Base elements
52
README.md
@ -2,16 +2,16 @@
|
||||
|
||||
## Simple WebPack boiler plate for SilverStripe
|
||||
|
||||
Checkout files at /site/ folder for details
|
||||
Checkout files at /app/ folder for details
|
||||
|
||||
### Features:
|
||||
+ You can use /site/_config/webpack.yml to setup webpack server parameters which will be used by webpack server and by SilverStripe to serve static content
|
||||
+ You can use /app/_config/webpack.yml to setup webpack server parameters which will be used by webpack server and by SilverStripe to serve static content
|
||||
+ You can use WebpackJS('file-name') and WebpackCSS('file-name') functions at templates to require JS and CSS. It will be served using static files or by using Webpack if the website in development mode and Webpack server is running
|
||||
+ WebpackTemplateProvider::WebpackJS('file-name') and WebpackTemplateProvider::WebpackCSS('file-name') can be used at php area
|
||||
+ All images will be optimised at /site/client/src/img and will be written to /site/client/dist/img (by default)
|
||||
+ Favicons will be generated at /site/client/dist/icons using /site/src/favicon.png
|
||||
+ Folder /site/client/src/js/types is used to create page specific JS (just create JS file there and it will be compiled)
|
||||
+ Folder /site/clent/src/scss/types is used to create page specific CSS (just create SCSS file there and it will be compiled)
|
||||
+ All images will be optimised at /app/client/src/img and will be written to /app/client/dist/img (by default)
|
||||
+ Favicons will be generated at /app/client/dist/icons using /app/src/favicon.png
|
||||
+ Folder /app/client/src/js/types is used to create page specific JS (just create JS file there and it will be compiled)
|
||||
+ Folder /app/clent/src/scss/types is used to create page specific CSS (just create SCSS file there and it will be compiled)
|
||||
+ Automatic linting (JS+SCSS)
|
||||
+ Bootstrap 4 included by default
|
||||
+ Font-Awesome included by default
|
||||
@ -20,32 +20,32 @@ Checkout files at /site/ folder for details
|
||||
|
||||
### Folder structure:
|
||||
|
||||
+ /site/_config/webpack.yml (Webpack configurtion)
|
||||
+ /site/src/WebpackTemplateProvider.php (WebpackJS and WebpackCSS functionality)
|
||||
+ /site/src/DeferedRequirements.php (Deferred Requirements + Requirements auto-loader)
|
||||
+ /site/templates/Page.ss (An example of Page.ss)
|
||||
+ /site/src (Your backend sources)
|
||||
+ /site/client/src (Your frontend sources)
|
||||
+ /site/client/dist (Your compiled-production assets)
|
||||
+ /app/_config/webpack.yml (Webpack configurtion)
|
||||
+ /app/src/WebpackTemplateProvider.php (WebpackJS and WebpackCSS functionality)
|
||||
+ /app/src/DeferedRequirements.php (Deferred Requirements + Requirements auto-loader)
|
||||
+ /app/templates/Page.ss (An example of Page.ss)
|
||||
+ /app/src (Your backend sources)
|
||||
+ /app/client/src (Your frontend sources)
|
||||
+ /app/client/dist (Your compiled-production assets)
|
||||
|
||||
|
||||
|
||||
+ /site/client/src/js (Your JS-scripts)
|
||||
+ /site/client/src/js/_components (Your JS components to be included)
|
||||
+ /site/client/src/js/_components/_spinner.js (An example to display and hide loading spinner)
|
||||
+ /site/client/src/js/app.js (main application file to include website-wide components)
|
||||
+ /site/client/src/js/main.js (Your custom site-wide functionality)
|
||||
+ /site/client/src/js/_events.js (Your custom site-wide events)
|
||||
+ /site/client/src/js/_pageType_and_component_template.js (A template which can be used to create new modules)
|
||||
+ /site/client/src/types/*.js (Extra page-specific modules to be auto-compiled. My suggestion is to use *ClassName*.js and then require it at SilverStripe custom controller area)
|
||||
+ /app/client/src/js (Your JS-scripts)
|
||||
+ /app/client/src/js/_components (Your JS components to be included)
|
||||
+ /app/client/src/js/_components/_spinner.js (An example to display and hide loading spinner)
|
||||
+ /app/client/src/js/app.js (main application file to include website-wide components)
|
||||
+ /app/client/src/js/main.js (Your custom site-wide functionality)
|
||||
+ /app/client/src/js/_events.js (Your custom site-wide events)
|
||||
+ /app/client/src/js/_pageType_and_component_template.js (A template which can be used to create new modules)
|
||||
+ /app/client/src/types/*.js (Extra page-specific modules to be auto-compiled. My suggestion is to use *ClassName*.js and then require it at SilverStripe custom controller area)
|
||||
|
||||
|
||||
|
||||
+ /site/clent/src/scss (Your styling to be compiled)
|
||||
+ /site/clent/src/scss/_components (Your custom SCSS components)
|
||||
+ /site/clent/src/scss/app.scss (main application file to include site-wide components)
|
||||
+ /site/clent/src/scss/_variables.sccs (your custom variables, ex. bootstrap)
|
||||
+ /site/clent/src/scss/_layout.sccs (Your site-wide styling)
|
||||
+ /app/clent/src/scss (Your styling to be compiled)
|
||||
+ /app/clent/src/scss/_components (Your custom SCSS components)
|
||||
+ /app/clent/src/scss/app.scss (main application file to include site-wide components)
|
||||
+ /app/clent/src/scss/_variables.sccs (your custom variables, ex. bootstrap)
|
||||
+ /app/clent/src/scss/_layout.sccs (Your site-wide styling)
|
||||
|
||||
|
||||
### Requirements:
|
||||
|
0
site/.htaccess → app/.htaccess
Executable file → Normal file
2
site/_config.php → app/_config.php
Executable file → Normal file
@ -16,5 +16,3 @@ HtmlEditorConfig::get('cms')->enablePlugins([
|
||||
]);
|
||||
|
||||
FulltextSearchable::enable();
|
||||
|
||||
|
22
app/_config/config.yml
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
Name: webapp
|
||||
---
|
||||
SilverStripe\Core\Manifest\ModuleManifest:
|
||||
project: app
|
||||
|
||||
SilverStripe\View\SSViewer:
|
||||
source_file_comments: true
|
||||
themes:
|
||||
- '$public'
|
||||
- '$default'
|
||||
|
||||
#SilverStripe\Admin\LeftAndMain:
|
||||
# extra_requirements_javascript:
|
||||
# - 'colymba/gridfield-bulk-editing-tools:client/dist/js/main.js'
|
||||
# - 'colymba/gridfield-bulk-editing-tools:client/lang/en.js'
|
||||
# extra_requirements_css:
|
||||
# - 'colymba/gridfield-bulk-editing-tools:client/dist/styles/main.css'
|
||||
|
||||
SilverStripe\Forms\HTMLEditor\TinyMCEConfig:
|
||||
editor_css:
|
||||
- 'app/client/dist/css/editor.css'
|
12
app/_config/debugbar.yml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
Name: debugbarext
|
||||
After:
|
||||
- 'framework'
|
||||
- 'debugbar'
|
||||
Only:
|
||||
environment: 'dev'
|
||||
---
|
||||
LeKoala\DebugBar\DebugBar:
|
||||
enabled_in_admin: false
|
||||
query_limit: 500
|
||||
max_header_length: 2048
|
11
app/_config/elements.yml
Normal file
@ -0,0 +1,11 @@
|
||||
Page:
|
||||
extensions:
|
||||
- DNADesign\Elemental\Extensions\ElementalPageExtension
|
||||
|
||||
DNADesign\Elemental\Models\BaseElement:
|
||||
default_global_elements: true
|
||||
extensions:
|
||||
- Site\Extensions\ElementRows
|
||||
|
||||
DNADesign\ElementalList\Model\ElementList:
|
||||
default_global_elements: false
|
1
site/_config/extensions.yml → app/_config/extensions.yml
Executable file → Normal file
@ -1,3 +1,4 @@
|
||||
SilverStripe\SiteConfig\SiteConfig:
|
||||
extensions:
|
||||
- Site\Extensions\SiteConfigExtension
|
||||
|
11
app/_config/webpack.yml
Normal file
@ -0,0 +1,11 @@
|
||||
# that's important to place this file into /app/_config/webpack.yml
|
||||
# with all configuration variables presented
|
||||
# Cuz WebPack compiling script use it to set configuration
|
||||
|
||||
Site\Templates\WebpackTemplateProvider:
|
||||
SRC: app/client/src
|
||||
DIST: app/client/dist
|
||||
HOSTNAME: localhost
|
||||
PORT: 3000
|
||||
TYPESJS: app/client/src/js/types
|
||||
TYPESSCSS: app/client/src/scss/types
|
2
app/client/dist/css/HomePage.css
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
/*# sourceMappingURL=HomePage.css.map*/
|
1
app/client/dist/css/HomePage.css.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/HomePage.css","sourceRoot":""}
|
7
app/client/dist/css/app.css
vendored
Normal file
1
app/client/dist/css/app.css.map
vendored
Normal file
2
app/client/dist/css/editor.css
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
/*# sourceMappingURL=editor.css.map*/
|
1
app/client/dist/css/editor.css.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/editor.css","sourceRoot":""}
|
2
app/client/dist/css/typography.css
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
/*# sourceMappingURL=typography.css.map*/
|
1
app/client/dist/css/typography.css.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/typography.css","sourceRoot":""}
|
1
app/client/dist/fonts/fontawesome-webfont.eot
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.eot";
|
1
app/client/dist/fonts/fontawesome-webfont.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.svg";
|
1
app/client/dist/fonts/fontawesome-webfont.ttf
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.ttf";
|
1
app/client/dist/fonts/fontawesome-webfont.woff
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.woff";
|
1
app/client/dist/fonts/fontawesome-webfont.woff2
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.woff2";
|
1
app/client/dist/icons/.cache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"hash":"5cffb502fb07fa499974d254725bb572","version":"0.0.9","optionHash":"48da8109542971737c0c3794682790d4","result":{"outputFilePrefix":"/icons/","html":["<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"app/client/dist//icons/apple-touch-icon-57x57.png\">","<link rel=\"apple-touch-icon\" sizes=\"60x60\" href=\"app/client/dist//icons/apple-touch-icon-60x60.png\">","<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"app/client/dist//icons/apple-touch-icon-72x72.png\">","<link rel=\"apple-touch-icon\" sizes=\"76x76\" href=\"app/client/dist//icons/apple-touch-icon-76x76.png\">","<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"app/client/dist//icons/apple-touch-icon-114x114.png\">","<link rel=\"apple-touch-icon\" sizes=\"120x120\" href=\"app/client/dist//icons/apple-touch-icon-120x120.png\">","<link rel=\"apple-touch-icon\" sizes=\"144x144\" href=\"app/client/dist//icons/apple-touch-icon-144x144.png\">","<link rel=\"apple-touch-icon\" sizes=\"152x152\" href=\"app/client/dist//icons/apple-touch-icon-152x152.png\">","<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"app/client/dist//icons/apple-touch-icon-180x180.png\">","<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">","<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">","<meta name=\"apple-mobile-web-app-title\" content=\"ss-webpack-boilerplate\">","<link rel=\"icon\" type=\"image/png\" sizes=\"228x228\" href=\"app/client/dist//icons/coast-228x228.png\">","<meta name=\"mobile-web-app-capable\" content=\"yes\">","<meta name=\"theme-color\" content=\"#fff\">","<meta name=\"application-name\" content=\"ss-webpack-boilerplate\">","<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"app/client/dist//icons/favicon-32x32.png\">","<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"app/client/dist//icons/favicon-16x16.png\">","<link rel=\"shortcut icon\" href=\"app/client/dist//icons/favicon.ico\">","<meta name=\"msapplication-TileColor\" content=\"#fff\">","<meta name=\"msapplication-TileImage\" content=\"mstile-144x144.png\">","<meta name=\"msapplication-config\" content=\"browserconfig.xml\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)\" href=\"app/client/dist//icons/apple-touch-startup-image-320x460.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)\" href=\"app/client/dist//icons/apple-touch-startup-image-640x920.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)\" href=\"app/client/dist//icons/apple-touch-startup-image-640x1096.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)\" href=\"app/client/dist//icons/apple-touch-startup-image-750x1294.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)\" href=\"app/client/dist//icons/apple-touch-startup-image-1182x2208.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)\" href=\"app/client/dist//icons/apple-touch-startup-image-1242x2148.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)\" href=\"app/client/dist//icons/apple-touch-startup-image-748x1024.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)\" href=\"app/client/dist//icons/apple-touch-startup-image-768x1004.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)\" href=\"app/client/dist//icons/apple-touch-startup-image-1496x2048.png\">","<link rel=\"apple-touch-startup-image\" media=\"(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)\" href=\"app/client/dist//icons/apple-touch-startup-image-1536x2008.png\">"],"files":["/icons/apple-touch-icon-57x57.png","/icons/apple-touch-icon-60x60.png","/icons/apple-touch-icon-72x72.png","/icons/apple-touch-icon-76x76.png","/icons/apple-touch-icon-120x120.png","/icons/apple-touch-icon-144x144.png","/icons/apple-touch-icon-152x152.png","/icons/apple-touch-icon-167x167.png","/icons/apple-touch-icon-180x180.png","/icons/apple-touch-icon.png","/icons/apple-touch-icon-precomposed.png","/icons/apple-touch-icon-114x114.png","/icons/coast-228x228.png","/icons/yandex-browser-50x50.png","/icons/android-chrome-36x36.png","/icons/android-chrome-48x48.png","/icons/android-chrome-96x96.png","/icons/android-chrome-72x72.png","/icons/android-chrome-144x144.png","/icons/android-chrome-192x192.png","/icons/android-chrome-256x256.png","/icons/android-chrome-384x384.png","/icons/android-chrome-512x512.png","/icons/favicon-16x16.png","/icons/favicon-32x32.png","/icons/favicon.ico","/icons/mstile-70x70.png","/icons/mstile-144x144.png","/icons/mstile-150x150.png","/icons/mstile-310x150.png","/icons/mstile-310x310.png","/icons/firefox_app_60x60.png","/icons/firefox_app_128x128.png","/icons/firefox_app_512x512.png","/icons/apple-touch-startup-image-320x460.png","/icons/apple-touch-startup-image-640x920.png","/icons/apple-touch-startup-image-640x1096.png","/icons/apple-touch-startup-image-748x1024.png","/icons/apple-touch-startup-image-750x1294.png","/icons/apple-touch-startup-image-768x1004.png","/icons/apple-touch-startup-image-1242x2148.png","/icons/apple-touch-startup-image-1182x2208.png","/icons/apple-touch-startup-image-1496x2048.png","/icons/apple-touch-startup-image-1536x2008.png","/icons/yandex-browser-manifest.json","/icons/manifest.json","/icons/browserconfig.xml","/icons/manifest.webapp"]}}
|
BIN
app/client/dist/icons/android-chrome-144x144.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/client/dist/icons/android-chrome-192x192.png
vendored
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
app/client/dist/icons/android-chrome-256x256.png
vendored
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
app/client/dist/icons/android-chrome-36x36.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/client/dist/icons/android-chrome-384x384.png
vendored
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
app/client/dist/icons/android-chrome-48x48.png
vendored
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/client/dist/icons/android-chrome-512x512.png
vendored
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
app/client/dist/icons/android-chrome-72x72.png
vendored
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
app/client/dist/icons/android-chrome-96x96.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
app/client/dist/icons/apple-touch-icon-114x114.png
vendored
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
app/client/dist/icons/apple-touch-icon-120x120.png
vendored
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
app/client/dist/icons/apple-touch-icon-144x144.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/client/dist/icons/apple-touch-icon-152x152.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
app/client/dist/icons/apple-touch-icon-167x167.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
app/client/dist/icons/apple-touch-icon-180x180.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
app/client/dist/icons/apple-touch-icon-57x57.png
vendored
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
app/client/dist/icons/apple-touch-icon-60x60.png
vendored
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/client/dist/icons/apple-touch-icon-72x72.png
vendored
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
app/client/dist/icons/apple-touch-icon-76x76.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
app/client/dist/icons/apple-touch-icon-precomposed.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
app/client/dist/icons/apple-touch-icon.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-1182x2208.png
vendored
Normal file
After Width: | Height: | Size: 322 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-1242x2148.png
vendored
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-1496x2048.png
vendored
Normal file
After Width: | Height: | Size: 457 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-1536x2008.png
vendored
Normal file
After Width: | Height: | Size: 492 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-320x460.png
vendored
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-640x1096.png
vendored
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-640x920.png
vendored
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-748x1024.png
vendored
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-750x1294.png
vendored
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
app/client/dist/icons/apple-touch-startup-image-768x1004.png
vendored
Normal file
After Width: | Height: | Size: 164 KiB |
15
app/client/dist/icons/browserconfig.xml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="mstile-70x70.png"/>
|
||||
<square150x150logo src="mstile-150x150.png"/>
|
||||
<wide310x150logo src="mstile-310x150.png"/>
|
||||
<square310x310logo src="mstile-310x310.png"/>
|
||||
<TileColor>#fff</TileColor>
|
||||
|
||||
</tile>
|
||||
|
||||
</msapplication>
|
||||
|
||||
</browserconfig>
|
BIN
app/client/dist/icons/coast-228x228.png
vendored
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
app/client/dist/icons/favicon-16x16.png
vendored
Normal file
After Width: | Height: | Size: 567 B |
BIN
app/client/dist/icons/favicon-32x32.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/client/dist/icons/favicon.ico
vendored
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
app/client/dist/icons/firefox_app_128x128.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/client/dist/icons/firefox_app_512x512.png
vendored
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
app/client/dist/icons/firefox_app_60x60.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
58
app/client/dist/icons/manifest.json
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "ss-webpack-boilerplate",
|
||||
"short_name": "ss-webpack-boilerplate",
|
||||
"description": null,
|
||||
"dir": "auto",
|
||||
"lang": "en-US",
|
||||
"display": "standalone",
|
||||
"orientation": "any",
|
||||
"start_url": "/?homescreen=1",
|
||||
"background_color": "#fff",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-256x256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
14
app/client/dist/icons/manifest.webapp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"name": "ss-webpack-boilerplate",
|
||||
"description": null,
|
||||
"icons": {
|
||||
"60": "firefox_app_60x60.png",
|
||||
"128": "firefox_app_128x128.png",
|
||||
"512": "firefox_app_512x512.png"
|
||||
},
|
||||
"developer": {
|
||||
"name": null,
|
||||
"url": null
|
||||
}
|
||||
}
|
BIN
app/client/dist/icons/mstile-144x144.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/client/dist/icons/mstile-150x150.png
vendored
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
app/client/dist/icons/mstile-310x150.png
vendored
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
app/client/dist/icons/mstile-310x310.png
vendored
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
app/client/dist/icons/mstile-70x70.png
vendored
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
app/client/dist/icons/yandex-browser-50x50.png
vendored
Normal file
After Width: | Height: | Size: 2.1 KiB |
9
app/client/dist/icons/yandex-browser-manifest.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"api_version": 1,
|
||||
"layout": {
|
||||
"logo": "yandex-browser-50x50.png",
|
||||
"color": "#fff",
|
||||
"show_title": true
|
||||
}
|
||||
}
|
1
app/client/dist/img/fontawesome-webfont.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
module.exports = "../fonts/fontawesome-webfont.svg";
|
BIN
app/client/dist/img/icon-cfpb.png
vendored
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/client/dist/img/icon-lender.png
vendored
Normal file
After Width: | Height: | Size: 946 B |
BIN
app/client/dist/img/logo.png
vendored
Normal file
After Width: | Height: | Size: 5.1 KiB |
2
app/client/dist/js/HomePage.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
!function(t){function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var e={};n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="app/client/dist/",n(n.s=33)}({33:function(t,n){}});
|
||||
//# sourceMappingURL=HomePage.js.map
|
1
app/client/dist/js/HomePage.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///js/HomePage.js","webpack:///webpack/bootstrap bf4e87ea9ffc4b0f0978"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","default","object","property","prototype","hasOwnProperty","p","s","33"],"mappings":"CAAS,SAAUA,GCInB,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAI,EAAAJ,EACAK,KACAH,WAUA,OANAJ,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,GAGAI,EAAAE,KAGAF,EAAAD,QAvBA,GAAAD,KA4BAF,GAAAQ,EAAAT,EAGAC,EAAAS,EAAAP,EAGAF,EAAAU,EAAA,SAAAP,EAAAQ,EAAAC,GACAZ,EAAAa,EAAAV,EAAAQ,IACAG,OAAAC,eAAAZ,EAAAQ,GACAK,gBACAC,cACAC,IAAAN,KAMAZ,EAAAmB,EAAA,SAAAf,GACA,GAAAQ,GAAAR,KAAAgB,WACA,WAA2B,MAAAhB,GAAAiB,SAC3B,WAAiC,MAAAjB,GAEjC,OADAJ,GAAAU,EAAAE,EAAA,IAAAA,GACAA,GAIAZ,EAAAa,EAAA,SAAAS,EAAAC,GAAsD,MAAAT,QAAAU,UAAAC,eAAAlB,KAAAe,EAAAC,IAGtDvB,EAAA0B,EAAA,mBAGA1B,IAAA2B,EAAA,MDMMC,GACA,SAAUxB,EAAQD","file":"js/HomePage.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"app/client/dist/\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 33);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ 33:\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ })\n\n/******/ });\n\n\n// WEBPACK FOOTER //\n// js/HomePage.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"app/client/dist/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 33);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap bf4e87ea9ffc4b0f0978"],"sourceRoot":""}
|
2
app/client/dist/js/app.js
vendored
Normal file
1
app/client/dist/js/app.js.map
vendored
Normal file
2
app/client/dist/js/editor.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
!function(t){function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var e={};n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="app/client/dist/",n(n.s=34)}({34:function(t,n){}});
|
||||
//# sourceMappingURL=editor.js.map
|
1
app/client/dist/js/editor.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///js/editor.js","webpack:///webpack/bootstrap bf4e87ea9ffc4b0f0978"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","default","object","property","prototype","hasOwnProperty","p","s","34"],"mappings":"CAAS,SAAUA,GCInB,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAI,EAAAJ,EACAK,KACAH,WAUA,OANAJ,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,GAGAI,EAAAE,KAGAF,EAAAD,QAvBA,GAAAD,KA4BAF,GAAAQ,EAAAT,EAGAC,EAAAS,EAAAP,EAGAF,EAAAU,EAAA,SAAAP,EAAAQ,EAAAC,GACAZ,EAAAa,EAAAV,EAAAQ,IACAG,OAAAC,eAAAZ,EAAAQ,GACAK,gBACAC,cACAC,IAAAN,KAMAZ,EAAAmB,EAAA,SAAAf,GACA,GAAAQ,GAAAR,KAAAgB,WACA,WAA2B,MAAAhB,GAAAiB,SAC3B,WAAiC,MAAAjB,GAEjC,OADAJ,GAAAU,EAAAE,EAAA,IAAAA,GACAA,GAIAZ,EAAAa,EAAA,SAAAS,EAAAC,GAAsD,MAAAT,QAAAU,UAAAC,eAAAlB,KAAAe,EAAAC,IAGtDvB,EAAA0B,EAAA,mBAGA1B,IAAA2B,EAAA,MDMMC,GACA,SAAUxB,EAAQD","file":"js/editor.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"app/client/dist/\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 34);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ 34:\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ })\n\n/******/ });\n\n\n// WEBPACK FOOTER //\n// js/editor.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"app/client/dist/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 34);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap bf4e87ea9ffc4b0f0978"],"sourceRoot":""}
|
2
app/client/dist/js/typography.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
!function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};e.m=t,e.c=n,e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="site/client/dist/",e(e.s=27)}({27:function(t,e){}});
|
||||
//# sourceMappingURL=typography.js.map
|
1
app/client/dist/js/typography.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///js/typography.js","webpack:///webpack/bootstrap c1e804200dc9a3f58466"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","default","object","property","prototype","hasOwnProperty","p","s","27"],"mappings":"CAAS,SAAUA,GCInB,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAI,EAAAJ,EACAK,KACAH,WAUA,OANAJ,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,GAGAI,EAAAE,KAGAF,EAAAD,QAvBA,GAAAD,KA4BAF,GAAAQ,EAAAT,EAGAC,EAAAS,EAAAP,EAGAF,EAAAU,EAAA,SAAAP,EAAAQ,EAAAC,GACAZ,EAAAa,EAAAV,EAAAQ,IACAG,OAAAC,eAAAZ,EAAAQ,GACAK,gBACAC,cACAC,IAAAN,KAMAZ,EAAAmB,EAAA,SAAAf,GACA,GAAAQ,GAAAR,KAAAgB,WACA,WAA2B,MAAAhB,GAAAiB,SAC3B,WAAiC,MAAAjB,GAEjC,OADAJ,GAAAU,EAAAE,EAAA,IAAAA,GACAA,GAIAZ,EAAAa,EAAA,SAAAS,EAAAC,GAAsD,MAAAT,QAAAU,UAAAC,eAAAlB,KAAAe,EAAAC,IAGtDvB,EAAA0B,EAAA,oBAGA1B,IAAA2B,EAAA,MDMMC,GACA,SAAUxB,EAAQD","file":"js/typography.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"site/client/dist/\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 27);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ 27:\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ })\n\n/******/ });\n\n\n// WEBPACK FOOTER //\n// js/typography.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"site/client/dist/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 27);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c1e804200dc9a3f58466"],"sourceRoot":""}
|
BIN
app/client/src/favicon.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
app/client/src/img/icon-cfpb.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/client/src/img/icon-lender.png
Normal file
After Width: | Height: | Size: 946 B |
BIN
app/client/src/img/logo.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
259
app/client/src/js/_components/_ui.ajax.js
Normal file
@ -0,0 +1,259 @@
|
||||
"use strict";
|
||||
|
||||
import $ from 'jquery';
|
||||
import Events from '../_events';
|
||||
import Spinner from './_ui.spinner';
|
||||
|
||||
const AjaxUI = (($) => {
|
||||
// Constants
|
||||
const G = window;
|
||||
const D = document;
|
||||
const $Html = $('html');
|
||||
const $Body = $('body');
|
||||
|
||||
const NAME = 'jsAjaxUI';
|
||||
const DATA_KEY = NAME;
|
||||
|
||||
class AjaxUI {
|
||||
// Constructor
|
||||
constructor(element) {
|
||||
this._element = element;
|
||||
const $element = $(this._element);
|
||||
$element.addClass(`${NAME}-active`);
|
||||
|
||||
$element.bind('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const $this = $(this);
|
||||
|
||||
$('.ajax').each(function () {
|
||||
const $this = $(this);
|
||||
$this.removeClass('active');
|
||||
$this.parents('.nav-item').removeClass('active');
|
||||
});
|
||||
|
||||
$this.addClass('loading');
|
||||
|
||||
AjaxUI.load($this.attr('href'), () => {
|
||||
$this.removeClass('loading');
|
||||
$this.parents('.nav-item').addClass('active');
|
||||
$this.addClass('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Public methods
|
||||
static load(url, callback) {
|
||||
// show spinner
|
||||
Spinner.show(() => {
|
||||
$Body.removeClass('loaded');
|
||||
});
|
||||
|
||||
// update document location
|
||||
G.MainUI.updateLocation(url);
|
||||
|
||||
const absoluteLocation = G.URLDetails['base'] + G.URLDetails['relative'].substring(1);
|
||||
if (absoluteLocation !== G.location.href) {
|
||||
G.history.pushState({
|
||||
ajax: true,
|
||||
page: absoluteLocation,
|
||||
}, document.title, absoluteLocation);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
sync: false,
|
||||
async: true,
|
||||
url,
|
||||
dataType: 'json',
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
error(jqXHR) {
|
||||
console.warn(`AJAX request failure: ${jqXHR.statusText}`);
|
||||
G.location.href = url;
|
||||
|
||||
// google analytics
|
||||
if (typeof G.ga === 'function') {
|
||||
G.ga('send', 'event', 'error', 'AJAX ERROR', jqXHR.statusText);
|
||||
}
|
||||
},
|
||||
success(data, status, jqXHR) {
|
||||
AjaxUI.process(data,jqXHR, callback);
|
||||
|
||||
// google analytics
|
||||
if (typeof G.ga === 'function') {
|
||||
G.ga('set', {
|
||||
page: G.URLDetails['relative'] + G.URLDetails['hash'],
|
||||
title: jqXHR.getResponseHeader('X-Title'),
|
||||
});
|
||||
G.ga('send', 'pageview');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static process(data, jqXHR, callback) {
|
||||
const css = jqXHR.getResponseHeader('X-Include-CSS').split(',') || [];
|
||||
const js = jqXHR.getResponseHeader('X-Include-JS').split(',') || [];
|
||||
|
||||
// Replace HTML regions
|
||||
if (typeof (data.regions) === 'object') {
|
||||
for (const key in data.regions) {
|
||||
if (typeof (data.regions[key]) === 'string') {
|
||||
AjaxUI.replaceRegion(data.regions[key], key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove already loaded scripts
|
||||
$('link[type="text/css"]').each(function () {
|
||||
const i = css.indexOf($(this).attr('href'));
|
||||
if (i > -1) {
|
||||
css.splice(i, 1);
|
||||
}else if(!$Body.data('unload-blocked')) {
|
||||
console.log(`Unloading: ${ $(this).attr('href')}`);
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('script[type="text/javascript"]').each(function () {
|
||||
const i = js.indexOf($(this).attr('src'));
|
||||
if (i > -1) {
|
||||
js.splice(i, 1);
|
||||
}else if(!$Body.data('unload-blocked')) {
|
||||
console.log(`Unloading: ${ $(this).attr('src')}`);
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
|
||||
// preload CSS
|
||||
this.preload(css).then(() => {
|
||||
const $head = $('head');
|
||||
css.forEach((el) => {
|
||||
$head.append(`<link rel="stylesheet" type="text/css" href="${el}" />`);
|
||||
});
|
||||
|
||||
// preload JS
|
||||
this.preload(js, 'script').then(() => {
|
||||
|
||||
js.forEach((el) => {
|
||||
$Body.append(`<script type="text/javascript" charset="UTF-8" src="${el}"></script>`);
|
||||
});
|
||||
|
||||
console.log('New page is loaded!');
|
||||
|
||||
// trigger events
|
||||
if (typeof (data.events) === 'object') {
|
||||
for (const eventName in data.events) {
|
||||
$(D).trigger(eventName, [data.events[eventName]]);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback();
|
||||
}
|
||||
|
||||
$(G).trigger(Events.AJAX);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static preload(items, type = 'text', cache = true) {
|
||||
if (!items.length) {
|
||||
return $.Deferred().resolve().promise();
|
||||
}
|
||||
|
||||
const dfds = [];
|
||||
items.forEach((url) => {
|
||||
const dfd = $.Deferred();
|
||||
|
||||
$.ajax({
|
||||
dataType: type,
|
||||
cache,
|
||||
url,
|
||||
}).always(() => {
|
||||
dfd.resolve();
|
||||
});
|
||||
|
||||
dfds.push(dfd);
|
||||
});
|
||||
|
||||
// return a master promise object which will resolve when all the deferred objects have resolved
|
||||
return $.when(...dfds);
|
||||
}
|
||||
|
||||
static replaceRegion(html, key) {
|
||||
const $region = $(`[data-ajax-region="${key}"]`);
|
||||
|
||||
if ($region.length) {
|
||||
$region.empty().append(html);
|
||||
} else {
|
||||
console.warn('Region returned without class or id!');
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
const $element = $(this._element);
|
||||
|
||||
$element.removeClass(`${NAME}-active`);
|
||||
$.removeData(this._element, DATA_KEY);
|
||||
this._element = null;
|
||||
}
|
||||
|
||||
static _jQueryInterface() {
|
||||
return this.each(function () {
|
||||
// attach functionality to element
|
||||
const $element = $(this);
|
||||
let data = $element.data(DATA_KEY);
|
||||
|
||||
if (!data) {
|
||||
data = new AjaxUI(this);
|
||||
$element.data(DATA_KEY, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// jQuery interface
|
||||
$.fn[NAME] = AjaxUI._jQueryInterface;
|
||||
$.fn[NAME].Constructor = AjaxUI;
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return AjaxUI._jQueryInterface;
|
||||
};
|
||||
|
||||
// auto-apply
|
||||
$('.ajax').ready(() => {
|
||||
$('.ajax').jsAjaxUI();
|
||||
});
|
||||
|
||||
// AJAX update browser title
|
||||
$(D).on('layoutRefresh', (e, data) => {
|
||||
D.title = data.Title;
|
||||
|
||||
$Html.attr('class','');
|
||||
if(data.ClassName){
|
||||
$Html.addClass(data.ClassName);
|
||||
}
|
||||
//data.Link = (data.Link === '/home/') ? '/' : data.Link;
|
||||
});
|
||||
|
||||
// Back/Forward functionality
|
||||
G.onpopstate = function(event) {
|
||||
const $existingLink = $(`a[href^="${ D.location }"]`);
|
||||
|
||||
if(event.state !== null && event.state.ajax){
|
||||
console.log('GOBACK (AJAX state)');
|
||||
AjaxUI.load(event.state.page);
|
||||
}else if($existingLink.length && $existingLink.hasClass('ajax')){
|
||||
console.log('GOBACK (AJAX link)');
|
||||
$existingLink.trigger('click');
|
||||
}else{
|
||||
console.log('GOBACK (HTTP)');
|
||||
G.location.href = D.location;
|
||||
}
|
||||
};
|
||||
|
||||
return AjaxUI;
|
||||
})($);
|
||||
|
||||
export default AjaxUI;
|
90
app/client/src/js/_components/_ui.carousel.js
Normal file
@ -0,0 +1,90 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
import Events from '../_events';
|
||||
|
||||
const CarouselUI = (($) => {
|
||||
// Constants
|
||||
const NAME = 'CarouselUI';
|
||||
|
||||
class CarouselUI {
|
||||
// Static methods
|
||||
|
||||
static each(callback) {
|
||||
$('.js-carousel').each(function(i, e) {
|
||||
callback(i, $(e));
|
||||
});
|
||||
}
|
||||
|
||||
static init() {
|
||||
this.dispose();
|
||||
|
||||
this.each((i, e) => {
|
||||
const $e = $(e),
|
||||
id = `Carousel${i}`;
|
||||
|
||||
$e.attr('id', id);
|
||||
$e.data('id', i);
|
||||
|
||||
const $items = $(e).find('.carousel-item'),
|
||||
count = $items.length;
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create carousel-controls
|
||||
if ($e.data('indicators')) {
|
||||
const $indicators = $('<ol class="carousel-indicators"></ol>');
|
||||
$indicators.append('<li data-target="#' + id + '" data-slide-to="0" class="active"></li>');
|
||||
for (let i = 1; i < count; i++) {
|
||||
$indicators.append('<li data-target="#' + id + '" data-slide-to="' + i + '"></li>');
|
||||
}
|
||||
$e.prepend($indicators);
|
||||
}
|
||||
|
||||
// create arrows
|
||||
if ($e.data('arrows')) {
|
||||
$e.prepend('<i class="carousel-control-prev" data-target="#' + id + '" role="button" data-slide="prev"><i class="fas fa-chevron-left" aria-hidden="true"></i><i class="sr-only">Previous</i></i>');
|
||||
$e.prepend('<i class="carousel-control-next" data-target="#' + id + '" role="button" data-slide="next"><i class="fas fa-chevron-right" aria-hidden="true"></i><i class="sr-only">Next</i></i>');
|
||||
}
|
||||
|
||||
// init carousel
|
||||
$e.carousel();
|
||||
|
||||
// init touch swipes
|
||||
$e.hammer().bind('swipeleft', (event) => {
|
||||
$(event.target).carousel('next');
|
||||
});
|
||||
|
||||
$e.hammer().bind('swiperight', (event) => {
|
||||
$(event.target).carousel('prev');
|
||||
});
|
||||
|
||||
$e.hammer().bind('panleft', (event) => {
|
||||
$(event.target).carousel('next');
|
||||
});
|
||||
|
||||
$e.hammer().bind('panright', (event) => {
|
||||
$(event.target).carousel('prev');
|
||||
});
|
||||
|
||||
$e.hammer().bind('tap', (event) => {
|
||||
$(event.target).carousel('next');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static dispose() {
|
||||
this.each((i, e) => {
|
||||
$(e).carousel('dispose');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
CarouselUI.init();
|
||||
});
|
||||
|
||||
return CarouselUI;
|
||||
})($);
|
||||
|
||||
export default CarouselUI;
|
103
app/client/src/js/_components/_ui.form.storage.js
Normal file
@ -0,0 +1,103 @@
|
||||
import $ from 'jquery';
|
||||
import Events from "../_events";
|
||||
|
||||
const FormStorage = (($) => {
|
||||
// Constants
|
||||
const NAME = 'jsFormStorage';
|
||||
const DATA_KEY = NAME;
|
||||
const STORAGE = window.localStorage;
|
||||
|
||||
class FormStorage {
|
||||
// Constructor
|
||||
constructor(element) {
|
||||
this._element = element;
|
||||
const $element = $(this._element);
|
||||
const $elements = $element.find('input,textarea');
|
||||
|
||||
$element.addClass(`${NAME}-active`);
|
||||
|
||||
// restore form data from localStorage
|
||||
$elements.each(function () {
|
||||
const id = $(this).attr('id');
|
||||
const type = $(this).attr('type');
|
||||
const val = STORAGE.getItem(NAME + id);
|
||||
|
||||
if (id && val && type) {
|
||||
if (type && (type === 'checkbox' || type === 'radio')) {
|
||||
$(this).prop('checked', val);
|
||||
} else {
|
||||
$(this).val(val);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// store form data into localStorage
|
||||
$elements.change(function () {
|
||||
const id = $(this).attr('id');
|
||||
const type = $(this).attr('type');
|
||||
let val = $(this).val();
|
||||
|
||||
if (type && (type === 'checkbox' || type === 'radio')) {
|
||||
val = !!$(this).is(':checked');
|
||||
}
|
||||
|
||||
if (id && type && type !== 'password') {
|
||||
STORAGE.setItem(NAME + id, val);
|
||||
}
|
||||
});
|
||||
|
||||
$element.submit(() => {
|
||||
$element.data(DATA_KEY).clear();
|
||||
});
|
||||
|
||||
$element.find('button,[type="submit"],[type="clear"]').click(() => {
|
||||
$element.data(DATA_KEY).clear();
|
||||
});
|
||||
}
|
||||
|
||||
// Public methods
|
||||
dispose() {
|
||||
const $element = $(this._element);
|
||||
|
||||
$element.removeClass(`${NAME}-active`);
|
||||
$.removeData(this._element, DATA_KEY);
|
||||
this._element = null;
|
||||
}
|
||||
|
||||
clear() {
|
||||
STORAGE.clear();
|
||||
}
|
||||
|
||||
static _jQueryInterface() {
|
||||
if (typeof window.localStorage !== 'undefined') {
|
||||
return this.each(function () {
|
||||
// attach functionality to element
|
||||
const $element = $(this);
|
||||
let data = $element.data(DATA_KEY);
|
||||
|
||||
if (!data) {
|
||||
data = new FormStorage(this);
|
||||
$element.data(DATA_KEY, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// jQuery interface
|
||||
$.fn[NAME] = FormStorage._jQueryInterface;
|
||||
$.fn[NAME].Constructor = FormStorage;
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return FormStorage._jQueryInterface;
|
||||
};
|
||||
|
||||
// auto-apply
|
||||
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
$('form').jsFormStorage();
|
||||
});
|
||||
|
||||
return FormStorage;
|
||||
})($);
|
||||
|
||||
export default FormStorage;
|
166
app/client/src/js/_components/_ui.map.api.js
Normal file
@ -0,0 +1,166 @@
|
||||
'use strict';
|
||||
|
||||
import $ from 'jquery';
|
||||
import Events from "../_events";
|
||||
import mapBoxGL from "mapbox-gl";
|
||||
//import "./mapStorage";
|
||||
|
||||
import "../../scss/types/MapPage.scss";
|
||||
|
||||
const W = window;
|
||||
|
||||
const MapAPI = (($) => {
|
||||
const STORAGE = W.localStorage;
|
||||
|
||||
// Constants
|
||||
const NAME = 'jsMapAPI';
|
||||
const DATA_KEY = NAME;
|
||||
const $BODY = $('body');
|
||||
let Map;
|
||||
let currentStyle;
|
||||
|
||||
class MapAPI {
|
||||
// Constructor
|
||||
constructor(element) {
|
||||
this._element = element;
|
||||
const $element = $(this._element);
|
||||
currentStyle = this.getStyle();
|
||||
|
||||
mapBoxGL.accessToken = 'pk.eyJ1IjoidG9ueS1haXIiLCJhIjoiY2l1OHoxZGp4MDAxZzJ0cHl0Y25jOWFpMCJ9.BC-YvTC2hUKhNbae4iAPCA';
|
||||
|
||||
Map = new mapBoxGL.Map({
|
||||
container: $element.find('.mapAPI-map')[0],
|
||||
center: [$BODY.data('default-lng'), $BODY.data('default-lat')],
|
||||
//hash: true,
|
||||
style: currentStyle,
|
||||
//localIdeographFontFamily: $BODY.css('font-family'),
|
||||
zoom: $element.data('map-zoom'),
|
||||
attributionControl: false
|
||||
/*transformRequest: (url, resourceType)=> {
|
||||
if(resourceType === 'Source' && url.startsWith('http://myHost')) {
|
||||
return {
|
||||
url: url.replace('http', 'https'),
|
||||
headers: { 'my-custom-header': true},
|
||||
credentials: 'include' // Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
}*/
|
||||
})
|
||||
.addControl(new mapBoxGL.AttributionControl({
|
||||
compact: true
|
||||
}))
|
||||
.addControl(new mapBoxGL.NavigationControl(), 'top-right')
|
||||
.addControl(new mapBoxGL.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true,
|
||||
},
|
||||
trackUserLocation: true,
|
||||
}),'bottom-right')
|
||||
.addControl(new mapboxgl.ScaleControl({
|
||||
maxWidth: 80,
|
||||
unit: 'metric'
|
||||
}),'top-left');
|
||||
|
||||
// event.target
|
||||
Map.on('load',(e) => {
|
||||
console.log('Map is loaded');
|
||||
/*Map.addSource('dem', {
|
||||
"type": "raster-dem",
|
||||
"url": "mapbox://mapbox.terrain-rgb"
|
||||
});
|
||||
Map.addLayer({
|
||||
"id": "hillshading",
|
||||
"source": "dem",
|
||||
"type": "hillshade"
|
||||
});*/
|
||||
});
|
||||
|
||||
/*Map.on('render',function(event){
|
||||
console.log('map moved');
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
// event: MapDataEvent
|
||||
Map.on('dataloading',() => {
|
||||
console.log('Loading map data');
|
||||
//console.log(event);
|
||||
});
|
||||
|
||||
// event: MapDataEvent
|
||||
Map.on('data',(event) => {
|
||||
console.log('Map data updated');
|
||||
//console.log(event);
|
||||
});*/
|
||||
|
||||
// check time every 60 mins and change to night style
|
||||
const api = this;
|
||||
setInterval(() => {
|
||||
const newStyle = api.getStyle();
|
||||
if(newStyle !== currentStyle){
|
||||
Map.setStyle(api.getStyle());
|
||||
}
|
||||
},36000);
|
||||
|
||||
|
||||
$element.addClass(`${NAME}-active`);
|
||||
}
|
||||
|
||||
// Public methods
|
||||
getMap() {
|
||||
return Map;
|
||||
}
|
||||
|
||||
getStyle() {
|
||||
return 'mapbox://styles/mapbox/streets-v9';
|
||||
const hour = new Date().getHours();
|
||||
if(hour < 6 || hour > 18) {
|
||||
// night
|
||||
//return 'mapbox://styles/mapbox/streets-v7';
|
||||
return 'mapbox://styles/tony-air/cjeacwih92iu42rpd8tcmuyb2';
|
||||
}else{
|
||||
// day
|
||||
return 'mapbox://styles/mapbox/streets-v9';
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
const $element = $(this._element);
|
||||
|
||||
$element.removeClass(`${NAME}-active`);
|
||||
$.removeData(this._element, DATA_KEY);
|
||||
this._element = null;
|
||||
}
|
||||
|
||||
static _jQueryInterface() {
|
||||
if (typeof W.localStorage !== 'undefined') {
|
||||
return this.each(function () {
|
||||
// attach functionality to element
|
||||
const $element = $(this);
|
||||
let data = $element.data(DATA_KEY);
|
||||
|
||||
if (!data) {
|
||||
data = new MapAPI(this);
|
||||
$element.data(DATA_KEY, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// jQuery interface
|
||||
$.fn[NAME] = MapAPI._jQueryInterface;
|
||||
$.fn[NAME].Constructor = MapAPI;
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return MapAPI._jQueryInterface;
|
||||
};
|
||||
|
||||
// auto-apply
|
||||
$(W).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
$('.mapAPI-map-container').jsMapAPI();
|
||||
});
|
||||
|
||||
return MapAPI;
|
||||
})($);
|
||||
|
||||
export default MapAPI;
|
62
app/client/src/js/_components/_ui.menu.js
Normal file
@ -0,0 +1,62 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
const SlidingMenu = (($) => {
|
||||
// Constants
|
||||
const NAME = 'jsSlidingMenu';
|
||||
const DATA_KEY = NAME;
|
||||
|
||||
class SlidingMenu {
|
||||
// Constructor
|
||||
constructor(element) {
|
||||
this._element = element;
|
||||
const $element = $(this._element);
|
||||
$element.addClass(`${NAME}-active`);
|
||||
|
||||
// esc button
|
||||
$(window).on('keyup',((e) => {
|
||||
if (e.which === 27) {
|
||||
$element.find('.is-open[data-toggle="offcanvas"]').click();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Public methods
|
||||
dispose() {
|
||||
console.log(`Disposing: ${NAME} elements`);
|
||||
|
||||
$(this._element).removeClass(`${NAME}-active`);
|
||||
$.removeData(this._element, DATA_KEY);
|
||||
this._element = null;
|
||||
}
|
||||
|
||||
static _jQueryInterface() {
|
||||
return this.each(function () {
|
||||
// attach functionality to element
|
||||
const $element = $(this);
|
||||
let data = $element.data(DATA_KEY);
|
||||
|
||||
if (!data) {
|
||||
data = new SlidingMenu(this);
|
||||
$element.data(DATA_KEY, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// jQuery interface
|
||||
$.fn[NAME] = SlidingMenu._jQueryInterface;
|
||||
$.fn[NAME].Constructor = SlidingMenu;
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return SlidingMenu._jQueryInterface;
|
||||
};
|
||||
|
||||
// auto-apply
|
||||
$(`.ui.${NAME}`).ready(() => {
|
||||
$(`.ui.${NAME}`).jsSlidingMenu();
|
||||
});
|
||||
|
||||
return SlidingMenu;
|
||||
})($);
|
||||
|
||||
export default SlidingMenu;
|
@ -1,6 +1,3 @@
|
||||
/**
|
||||
* Just an example component
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
const SpinnerUI = (($) => {
|
||||
@ -13,6 +10,7 @@ const SpinnerUI = (($) => {
|
||||
$('#PageLoading').hide('slow', callback);
|
||||
}
|
||||
}
|
||||
|
||||
return SpinnerUI;
|
||||
})($);
|
||||
|
30
app/client/src/js/_components/_ui.visibility.js
Normal file
@ -0,0 +1,30 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
const G = window;
|
||||
const D = document;
|
||||
|
||||
// remove browser default alerts
|
||||
/*alert = function () {
|
||||
console.log(arguments);
|
||||
console.log(new Error().stack);
|
||||
};*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*G.addEventListener(G.visibilityChangeEvent, () => {
|
||||
if (currentPage && typeof currentPage !== 'undefined') {
|
||||
if (
|
||||
landingPage !== G.location.href &&
|
||||
currentPage !== '/' &&
|
||||
currentPage.indexOf('/dev') === -1 &&
|
||||
!$('main>div').hasClass('type-ErrorPage')
|
||||
) {
|
||||
G.localStorage.setItem('current-page', G.location.href);
|
||||
} else if (landingPage === G.location.href || currentPage.indexOf('/dev') !== -1) {
|
||||
G.localStorage.removeItem('current-page');
|
||||
}
|
||||
}
|
||||
});*/
|
270
app/client/src/js/_components/mapStorage.js
Normal file
@ -0,0 +1,270 @@
|
||||
'use strict';
|
||||
|
||||
import mapbox from "mapbox-gl";
|
||||
|
||||
window.offlineMaps = {};
|
||||
|
||||
window.offlineMaps.eventManager = {
|
||||
_events: {},
|
||||
|
||||
on: function (event, action) {
|
||||
console.log(`event.on: ${ event}`);
|
||||
if (!(event in this._events)) {
|
||||
this._events[event] = [];
|
||||
}
|
||||
this._events[event].push(action);
|
||||
return this;
|
||||
},
|
||||
|
||||
off: function (event) {
|
||||
console.log(`event.off: ${ event}`);
|
||||
delete this._events[event];
|
||||
return this;
|
||||
},
|
||||
|
||||
fire: function (event) {
|
||||
console.log(`event.fire: ${ event}`);
|
||||
var events = this._events;
|
||||
if (event in events) {
|
||||
var actions = events[event];
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
for (var i = 0, l = actions.length; i < l; i++) {
|
||||
var action = actions[i];
|
||||
if (action instanceof Function) {
|
||||
action.apply(null, args);
|
||||
} else {
|
||||
this.fire.apply(this, [action].concat(args));
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
(function (window, emr, undefined) {
|
||||
var getIndexedDBStorage = function () {
|
||||
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
||||
|
||||
var IndexedDBImpl = function () {
|
||||
var self = this;
|
||||
var db = null;
|
||||
var request = indexedDB.open('TileStorage');
|
||||
|
||||
request.onsuccess = function() {
|
||||
db = this.result;
|
||||
emr.fire('storageLoaded', self);
|
||||
};
|
||||
|
||||
request.onerror = function (error) {
|
||||
console.log(error);
|
||||
};
|
||||
|
||||
request.onupgradeneeded = function () {
|
||||
var store = this.result.createObjectStore('tile', { keyPath: 'key' });
|
||||
store.createIndex('key', 'key', { unique: true });
|
||||
};
|
||||
|
||||
this.add = function (key, value) {
|
||||
var transaction = db.transaction(['tile'], 'readwrite');
|
||||
var objectStore = transaction.objectStore('tile');
|
||||
objectStore.put({ key, value });
|
||||
};
|
||||
|
||||
this.delete = function (key) {
|
||||
var transaction = db.transaction(['tile'], 'readwrite');
|
||||
var objectStore = transaction.objectStore('tile');
|
||||
objectStore.delete(key);
|
||||
};
|
||||
|
||||
this.get = function (key, successCallback, errorCallback) {
|
||||
var transaction = db.transaction(['tile'], 'readonly');
|
||||
var objectStore = transaction.objectStore('tile');
|
||||
var result = objectStore.get(key);
|
||||
result.onsuccess = function () {
|
||||
successCallback(this.result ? this.result.value : undefined);
|
||||
};
|
||||
result.onerror = errorCallback;
|
||||
};
|
||||
};
|
||||
|
||||
return indexedDB ? new IndexedDBImpl() : null;
|
||||
};
|
||||
|
||||
var getWebSqlStorage = function () {
|
||||
var openDatabase = window.openDatabase;
|
||||
|
||||
var WebSqlImpl = function () {
|
||||
var self = this;
|
||||
var db = openDatabase('TileStorage', '1.0', 'Tile Storage', 5 * 1024 * 1024);
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql('CREATE TABLE IF NOT EXISTS tile (key TEXT PRIMARY KEY, value TEXT)', [], () => {
|
||||
emr.fire('storageLoaded', self);
|
||||
});
|
||||
});
|
||||
|
||||
this.add = function (key, value) {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql('INSERT INTO tile (key, value) VALUES (?, ?)', [key, value]);
|
||||
});
|
||||
};
|
||||
|
||||
this.delete = function (key) {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql('DELETE FROM tile WHERE key = ?', [key]);
|
||||
});
|
||||
};
|
||||
|
||||
this.get = function (key, successCallback, errorCallback) {
|
||||
db.transaction((tx) => {
|
||||
tx.executeSql('SELECT value FROM tile WHERE key = ?', [key], (tx, result) => {
|
||||
successCallback(result.rows.length ? result.rows.item(0).value : undefined);
|
||||
}, errorCallback);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return openDatabase ? new WebSqlImpl() : null;
|
||||
};
|
||||
|
||||
emr.on('storageLoad', () => {
|
||||
var storage = getIndexedDBStorage() || getWebSqlStorage() || null;
|
||||
if (!storage) {
|
||||
emr.fire('storageLoaded', null);
|
||||
}
|
||||
});
|
||||
})(window, window.offlineMaps.eventManager);
|
||||
|
||||
(function (window, emr, mapbox, MM, undefined) {
|
||||
var StorageRequestManager = function (storage) {
|
||||
MM.RequestManager.apply(this, []);
|
||||
this._storage = storage;
|
||||
};
|
||||
|
||||
StorageRequestManager.prototype._imageToDataUri = function (image) {
|
||||
var canvas = window.document.createElement('canvas');
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
context.drawImage(image, 0, 0);
|
||||
|
||||
return canvas.toDataURL('image/png');
|
||||
};
|
||||
|
||||
StorageRequestManager.prototype._createTileImage = function (id, coord, value, cache) {
|
||||
var img = window.document.createElement('img');
|
||||
img.id = id;
|
||||
img.style.position = 'absolute';
|
||||
img.coord = coord;
|
||||
this.loadingBay.appendChild(img);
|
||||
if (cache) {
|
||||
img.onload = this.getLoadCompleteWithCache();
|
||||
img.crossOrigin = 'Anonymous';
|
||||
} else {
|
||||
img.onload = this.getLoadComplete();
|
||||
}
|
||||
img.onerror = this.getLoadComplete();
|
||||
img.src = value;
|
||||
};
|
||||
|
||||
StorageRequestManager.prototype._loadTile = function (id, coord, url) {
|
||||
var self = this;
|
||||
if (this._storage) {
|
||||
this._storage.get(id, (value) => {
|
||||
if (value) {
|
||||
self._createTileImage(id, coord, value, false);
|
||||
} else {
|
||||
self._createTileImage(id, coord, url, true);
|
||||
}
|
||||
}, () => {
|
||||
self._createTileImage(id, coord, url, true);
|
||||
});
|
||||
} else {
|
||||
self._createTileImage(id, coord, url, false);
|
||||
}
|
||||
};
|
||||
|
||||
StorageRequestManager.prototype.processQueue = function (sortFunc) {
|
||||
if (sortFunc && this.requestQueue.length > 8) {
|
||||
this.requestQueue.sort(sortFunc);
|
||||
}
|
||||
while (this.openRequestCount < this.maxOpenRequests && this.requestQueue.length > 0) {
|
||||
var request = this.requestQueue.pop();
|
||||
if (request) {
|
||||
this.openRequestCount++;
|
||||
this._loadTile(request.id, request.coord, request.url);
|
||||
request = request.id = request.coord = request.url = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
StorageRequestManager.prototype.getLoadCompleteWithCache = function () {
|
||||
if (!this._loadComplete) {
|
||||
var theManager = this;
|
||||
this._loadComplete = function(e) {
|
||||
//e = e || window.event;
|
||||
|
||||
var img = e.srcElement || e.target;
|
||||
img.onload = img.onerror = null;
|
||||
|
||||
if (theManager._storage) {
|
||||
theManager._storage.add(this.id, theManager._imageToDataUri(this));
|
||||
}
|
||||
|
||||
theManager.loadingBay.removeChild(img);
|
||||
theManager.openRequestCount--;
|
||||
delete theManager.requestsById[img.id];
|
||||
|
||||
if (e.type === 'load' && (img.complete ||
|
||||
(img.readyState && img.readyState === 'complete'))) {
|
||||
theManager.dispatchCallback('requestcomplete', img);
|
||||
} else {
|
||||
theManager.dispatchCallback('requesterror', {
|
||||
element: img,
|
||||
url: (`${ img.src}`),
|
||||
});
|
||||
img.src = null;
|
||||
}
|
||||
|
||||
setTimeout(theManager.getProcessQueue(), 0);
|
||||
};
|
||||
}
|
||||
return this._loadComplete;
|
||||
};
|
||||
|
||||
MM.extend(StorageRequestManager, MM.RequestManager);
|
||||
|
||||
var StorageLayer = function(provider, parent, name, storage) {
|
||||
this.parent = parent || document.createElement('div');
|
||||
this.parent.style.cssText = 'position: absolute; top: 0px; left: 0px;' +
|
||||
'width: 100%; height: 100%; margin: 0; padding: 0; z-index: 0';
|
||||
this.name = name;
|
||||
this.levels = {};
|
||||
this.requestManager = new StorageRequestManager(storage);
|
||||
this.requestManager.addCallback('requestcomplete', this.getTileComplete());
|
||||
this.requestManager.addCallback('requesterror', this.getTileError());
|
||||
if (provider) {
|
||||
this.setProvider(provider);
|
||||
}
|
||||
};
|
||||
|
||||
MM.extend(StorageLayer, MM.Layer);
|
||||
|
||||
var StorageTemplatedLayer = function(template, subdomains, name, storage) {
|
||||
return new StorageLayer(new MM.Template(template, subdomains), null, name, storage);
|
||||
};
|
||||
|
||||
emr.on('mapLoad', (storage) => {
|
||||
var map = mapbox.map('map');
|
||||
map.addLayer(new StorageTemplatedLayer('http://{S}.tile.osm.org/{Z}/{X}/{Y}.png',
|
||||
['a', 'b', 'c'], undefined, storage));
|
||||
map.ui.zoomer.add();
|
||||
map.ui.zoombox.add();
|
||||
map.centerzoom({ lat: 53.902254, lon: 27.561850 }, 13);
|
||||
});
|
||||
})(window, window.offlineMaps.eventManager, mapbox, MM);
|
||||
|
||||
(function (emr) {
|
||||
emr.on('storageLoaded', 'mapLoad');
|
||||
emr.fire('storageLoad');
|
||||
})(window.offlineMaps.eventManager);
|
13
app/client/src/js/_components/routes/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
import Events from '../../_events';
|
||||
import Routie from "routie";
|
||||
|
||||
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
Routie({
|
||||
'navigation': function() {
|
||||
$('#NavbarCollapse').addClass('in');
|
||||
},
|
||||
'carousel:id:num': function(id, num) {
|
||||
$(`#Carousel${ id}`).carousel(num);
|
||||
},
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import '../scss/app.scss';
|
||||
|
||||
// Bootstrap
|
||||
import Popper from 'popper.js';
|
||||
// import Bootstrap
|
||||
import 'popper.js';
|
||||
import 'bootstrap/js/dist/util';
|
||||
import 'bootstrap/js/dist/alert';
|
||||
import 'bootstrap/js/dist/button';
|
||||
@ -15,27 +15,20 @@ import 'bootstrap/js/dist/scrollspy';
|
||||
import 'bootstrap/js/dist/tab';
|
||||
//
|
||||
|
||||
// Extra modules
|
||||
import 'jquery-zoom/jquery.zoom';
|
||||
import 'meta-lightbox/meta-lightbox';
|
||||
//import Vue from 'vue/dist/vue.esm.js';
|
||||
|
||||
// import Bootstrap-Vue
|
||||
/*import { Carousel } from 'bootstrap-vue/es/components';
|
||||
Vue.use(Carousel);*/
|
||||
|
||||
import 'offcanvas-bootstrap/dist/js/bootstrap.offcanvas';
|
||||
|
||||
// import your custom UI components
|
||||
import './main';
|
||||
|
||||
// import images
|
||||
function importAll(r) {
|
||||
return r.keys().map(r);
|
||||
}
|
||||
|
||||
const images = importAll(require.context('../img/', false, /\.(png|jpe?g|svg|gif)$/));
|
||||
|
||||
// TODO: hot module update
|
||||
/* const Events = require("./_events");
|
||||
if (module.hot) {
|
||||
module.hot.accept();
|
||||
module.hot.addStatusHandler(status => {
|
||||
if(status === "apply"){
|
||||
$(window).trigger(Events.AJAX);
|
||||
}
|
||||
});
|
||||
} */
|
||||
const images = importAll(require.context('../img/', false, /\.(png|jpe?g|svg)$/));
|
||||
const fontAwesome = importAll(require.context('font-awesome', false, /\.(otf|eot|svg|ttf|woff|woff2)$/));
|
303
app/client/src/js/main.js
Normal file
@ -0,0 +1,303 @@
|
||||
"use strict";
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
import 'hammerjs/hammer';
|
||||
import 'jquery-hammerjs/jquery.hammer';
|
||||
|
||||
// Routie
|
||||
import 'pouchdb/dist/pouchdb';
|
||||
import './_components/routes/index';
|
||||
|
||||
import Events from './_events';
|
||||
import Spinner from './_components/_ui.spinner';
|
||||
|
||||
import './_components/_ui.carousel';
|
||||
import './_components/_ui.menu';
|
||||
import './_components/_ui.form.storage';
|
||||
import AjaxUI from './_components/_ui.ajax';
|
||||
|
||||
import SmoothScroll from 'smooth-scroll';
|
||||
const smoothScroll = SmoothScroll();
|
||||
|
||||
const MainUI = (($) => {
|
||||
// Constants
|
||||
const W = window;
|
||||
const D = document;
|
||||
const $Body = $('body');
|
||||
|
||||
const NAME = 'MainUI';
|
||||
|
||||
// get browser locale
|
||||
//const Locale = $('html').attr('lang').substring(0, 2);
|
||||
|
||||
const $AlertNotify = $('#AlertNotify');
|
||||
const $SiteWideMessage = $('#SiteWideMessage');
|
||||
|
||||
// get browser window visibility preferences
|
||||
// Opera 12.10, Firefox >=18, Chrome >=31, IE11
|
||||
const HiddenName = 'hidden';
|
||||
const VisibilityChangeEvent = 'visibilitychange';
|
||||
|
||||
// update visibility state
|
||||
D.addEventListener(VisibilityChangeEvent, () => {
|
||||
if (D.visibilityState === HiddenName) {
|
||||
console.log('Tab: hidden');
|
||||
$Body.addClass('is-hidden');
|
||||
$Body.trigger('tabHidden');
|
||||
} else {
|
||||
console.log('Tab: focused');
|
||||
$Body.removeClass('is-hidden');
|
||||
$Body.trigger('tabFocused');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// update online/offline state
|
||||
const updateOnlineStatus = function() {
|
||||
if (!navigator.onLine) {
|
||||
console.log('Tab: offline');
|
||||
$Body.addClass('is-offline');
|
||||
$Body.trigger('offline');
|
||||
} else {
|
||||
console.log('Tab: online');
|
||||
$Body.removeClass('is-offline');
|
||||
$Body.trigger('online');
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof navigator.onLine !== 'undefined') {
|
||||
W.addEventListener('offline', () => {
|
||||
updateOnlineStatus();
|
||||
}, false);
|
||||
|
||||
W.addEventListener('online', () => {
|
||||
updateOnlineStatus();
|
||||
}, false);
|
||||
|
||||
W.addEventListener('load', () => {
|
||||
updateOnlineStatus();
|
||||
});
|
||||
}
|
||||
|
||||
// scrollTo
|
||||
const ScrollTo = function(trigger, selector) {
|
||||
smoothScroll.animateScroll(
|
||||
D.querySelector(selector),
|
||||
trigger, {
|
||||
speed: 500,
|
||||
offset: -20,
|
||||
//easing: 'easeInOutCubic',
|
||||
// Callback API
|
||||
//before: function (anchor, toggle) {}, // Callback to run before scroll
|
||||
//`after: function (anchor, toggle) {} // Callback to run after scroll
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// session ping
|
||||
setInterval(() => {
|
||||
if ($Body.hasClass('is-offline')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
sync: false,
|
||||
async: true,
|
||||
cache: false,
|
||||
url: '/Security/ping',
|
||||
global: false,
|
||||
type: 'POST',
|
||||
complete(data, datastatus) {
|
||||
if (datastatus !== 'success') {
|
||||
W.location.reload(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}, 300000); // 5 min in ms
|
||||
|
||||
W.URLDetails = {
|
||||
'base': $('base').attr('href'),
|
||||
'relative': '/',
|
||||
'hash': '',
|
||||
};
|
||||
|
||||
class MainUI {
|
||||
// Static methods
|
||||
|
||||
static init() {
|
||||
this.dispose();
|
||||
|
||||
console.log(`Initializing: ${NAME}`);
|
||||
|
||||
// update location details
|
||||
this.updateLocation();
|
||||
|
||||
// mark available offline areas
|
||||
if ('caches' in W) {
|
||||
$('a.offline').addClass('offline-available');
|
||||
}
|
||||
|
||||
this.loadImages();
|
||||
|
||||
// mark external links
|
||||
$('a.external,a[rel="external"]').attr('target', '_blank');
|
||||
|
||||
// show encoded emails
|
||||
/*$(D).find('.obm').each(function () {
|
||||
if ($(this).attr('data-val') !== undefined) {
|
||||
const email = $(this).attr('data-val').split('')
|
||||
.reverse()
|
||||
.join('')
|
||||
.slice(0, -8)
|
||||
.replace(/[a-zA-Z]/g, (c) => String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26))
|
||||
.replace('#AT#', '@');
|
||||
const attr = $(this).attr('data-val-append');
|
||||
if (attr !== undefined && attr !== false) {
|
||||
$(this).append(email);
|
||||
}
|
||||
if ($(this).find('.sr-only').length > 0) {
|
||||
$(this).find('.sr-only').append(email);
|
||||
}
|
||||
if ($(this).attr('href') !== undefined) {
|
||||
$(this).attr('href', `mailto:${email}`);
|
||||
}
|
||||
}
|
||||
});*/
|
||||
//
|
||||
|
||||
// scroll links
|
||||
$(D).on('click', '.js-scrollTo', function(e) {
|
||||
e.preventDefault();
|
||||
ScrollTo(this, $(this).attr('data-target'));
|
||||
});
|
||||
|
||||
// load external fonts
|
||||
if ($('[data-extfont]').length) {
|
||||
$.getScript('//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js', () => {
|
||||
const fonts = [];
|
||||
$('[data-extfont]').each(function(i) {
|
||||
fonts[i] = $(this).attr('data-extfont');
|
||||
});
|
||||
W.WebFont.load({
|
||||
google: {
|
||||
families: fonts,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// hide spinner
|
||||
Spinner.hide(() => {
|
||||
$Body.addClass('loaded');
|
||||
});
|
||||
|
||||
// fire page printing
|
||||
if (W.URLDetails['hash'].indexOf('printpage') > -1) {
|
||||
W.print();
|
||||
}
|
||||
}
|
||||
|
||||
static updateLocation(url) {
|
||||
let location = url || W.location.href;
|
||||
location = location.replace(W.URLDetails['base'], '/');
|
||||
const hash = location.indexOf('#');
|
||||
|
||||
W.URLDetails.relative = location.split('#')[0];
|
||||
W.URLDetails.hash = (hash >= 0) ? location.substr(location.indexOf('#')) : '';
|
||||
}
|
||||
|
||||
// show site-wide alert
|
||||
static alert(msg, cls) {
|
||||
$SiteWideMessage.fadeOut('fast');
|
||||
|
||||
$SiteWideMessage.html(`<div class="page-alert"><div class="alert alert-${cls}"><i class="close" data-dismiss="alert">×</i>${msg}</div></div>`);
|
||||
$SiteWideMessage.find('.page-alert').alert();
|
||||
|
||||
$SiteWideMessage.find('.close[data-dismiss="alert"]').click(() => {
|
||||
$SiteWideMessage.fadeOut('slow', () => {
|
||||
$SiteWideMessage.find('.page-alert').alert('close');
|
||||
});
|
||||
});
|
||||
|
||||
$SiteWideMessage.fadeIn('slow');
|
||||
|
||||
if ($AlertNotify.length) {
|
||||
$AlertNotify[0].play();
|
||||
}
|
||||
|
||||
$(W).trigger('alert-appeared');
|
||||
}
|
||||
|
||||
// hide site-wide alert
|
||||
static alertHide() {
|
||||
if ($SiteWideMessage.length !== 0) {
|
||||
$SiteWideMessage.fadeOut('slow', () => {
|
||||
$SiteWideMessage.find('.alert').alert('close');
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
$AlertNotify.length &&
|
||||
typeof $AlertNotify[0].stop !== 'undefined'
|
||||
) {
|
||||
$AlertNotify[0].stop();
|
||||
}
|
||||
|
||||
$(W).trigger('alert-removed');
|
||||
}
|
||||
|
||||
// load all images
|
||||
static loadImages() {
|
||||
const $imgs = $Body.find('img');
|
||||
const $imgUrls = [];
|
||||
const $imgLazyUrls = [];
|
||||
|
||||
// collect image details
|
||||
$imgs.each(function() {
|
||||
const src = $(this).attr('src');
|
||||
const lazySrc = $(this).data('lazy-src');
|
||||
if (src.length) {
|
||||
$imgUrls.push(src);
|
||||
}
|
||||
if (lazySrc) {
|
||||
$imgLazyUrls.push(lazySrc);
|
||||
}
|
||||
});
|
||||
|
||||
// load defined images
|
||||
AjaxUI.preload($imgUrls).then(() => {
|
||||
$(W).trigger('images-loaded');
|
||||
|
||||
// load lazy images
|
||||
AjaxUI.preload($imgLazyUrls).then(() => {
|
||||
// update lazy img src
|
||||
$('img[data-lazy-src]').each(function() {
|
||||
if (!$(this).attr('src')) {
|
||||
return;
|
||||
}
|
||||
$(this).attr('src', $(this).data('lazy-src'));
|
||||
});
|
||||
|
||||
console.log('All images are loaded!');
|
||||
|
||||
$(W).trigger('images-lazy-loaded');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static dispose() {
|
||||
console.log(`Destroying: ${NAME}`);
|
||||
}
|
||||
}
|
||||
|
||||
$(W).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
MainUI.init();
|
||||
});
|
||||
|
||||
W.MainUI = MainUI;
|
||||
|
||||
return MainUI;
|
||||
})($);
|
||||
|
||||
export default MainUI;
|
14
app/client/src/scss/_layout.scss
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Your custom style
|
||||
*/
|
||||
|
||||
@import "_components/ui.carousel";
|
||||
|
||||
// hide default page title cuz elemental object will be used to display titles
|
||||
h1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
130
app/src/Extensions/ElementRows.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: tony
|
||||
* Date: 6/23/18
|
||||
* Time: 1:23 PM
|
||||
*/
|
||||
|
||||
namespace Site\Extensions;
|
||||
|
||||
|
||||
use DNADesign\ElementalList\Model\ElementList;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\ORM\FieldType\DBEnum;
|
||||
|
||||
class ElementRows extends DataExtension
|
||||
{
|
||||
private static $column_class = 'col-md-';
|
||||
private static $container_styles = [
|
||||
'container' => 'Fixed container',
|
||||
'container-fluid' => 'Fluid Container',
|
||||
];
|
||||
|
||||
private static $db = [
|
||||
'Size' => 'Enum("1,2,3,4,5,6,7,8,9,10,11,12","6")',
|
||||
];
|
||||
|
||||
public function updateCMSFields(FieldList $fields)
|
||||
{
|
||||
$tab = $fields->findOrMakeTab('Root.Main');
|
||||
|
||||
if($this->isRoot() && $this->isList()) {
|
||||
$styleDropdown = $fields->dataFieldByName('Style');
|
||||
if ($styleDropdown) {
|
||||
$styleDropdown->setSource(self::$container_styles);
|
||||
} else {
|
||||
$styleDropdown = DropdownField::create(
|
||||
'Style',
|
||||
_t(__CLASS__.'.STYLE', 'Style variation'),
|
||||
self::$container_styles
|
||||
);
|
||||
$fields->insertBefore($styleDropdown, 'ExtraClass');
|
||||
}
|
||||
}
|
||||
|
||||
if($this->isColumn()) {
|
||||
$sizes = $this->owner->dbObject('Size');
|
||||
$defaultSize = $sizes->getDefaultValue();
|
||||
|
||||
$sizeDropdown = DropdownField::create(
|
||||
'Size',
|
||||
'Column Size (12 cols grid, ex. for 3 equal cols: 12/3 = 4 is the size that you need)',
|
||||
$sizes->enumValues()
|
||||
);
|
||||
$tab->push($sizeDropdown);
|
||||
|
||||
// set default size
|
||||
if(!$this->owner->getField('Size')){
|
||||
$sibling = $this->owner->Parent()
|
||||
->Elements()
|
||||
->exclude('ID', $this->owner->ID)
|
||||
->last();
|
||||
|
||||
$sizeDropdown->setValue($sibling ? $sibling->getField('Size') : $defaultSize);
|
||||
}
|
||||
}else{
|
||||
$fields->removeByName('Size');
|
||||
}
|
||||
}
|
||||
|
||||
public function isList()
|
||||
{
|
||||
return is_a($this->owner, ElementList::class);
|
||||
}
|
||||
|
||||
public function isRow()
|
||||
{
|
||||
if(!$this->isList()){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isColumn()
|
||||
{
|
||||
if(!$this->isRoot() && !$this->isRow()){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isRoot()
|
||||
{
|
||||
$parent = $this->owner->Parent()->getOwnerPage();
|
||||
if(is_a($parent, 'Page')){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ExtraClass()
|
||||
{
|
||||
return $this->isColumn()
|
||||
? self::$column_class.$this->owner->getField('Size')
|
||||
: '';
|
||||
}
|
||||
|
||||
/*
|
||||
* if it's root element and it doesn't contain any container styles
|
||||
* add the first one
|
||||
*/
|
||||
public function updateStyleVariant(&$style)
|
||||
{
|
||||
$style = $this->owner->getField('Style');
|
||||
$container_styles = array_keys(self::$container_styles);
|
||||
|
||||
if(
|
||||
$this->isRoot()
|
||||
&& $this->isList()
|
||||
&& !in_array($style, $container_styles)
|
||||
){
|
||||
$style = $container_styles[0];
|
||||
}
|
||||
}
|
||||
}
|
0
site/src/Extensions/SiteConfigExtension.php → app/src/Extensions/SiteConfigExtension.php
Executable file → Normal file
0
site/src/Pages/HomePage.php → app/src/Pages/HomePage.php
Executable file → Normal file
0
site/src/Pages/HomePageController.php → app/src/Pages/HomePageController.php
Executable file → Normal file
0
site/src/Pages/Page.php → app/src/Pages/Page.php
Executable file → Normal file
0
site/src/Pages/PageController.php → app/src/Pages/PageController.php
Executable file → Normal file
2
site/src/Templates/DeferedRequirements.php → app/src/Templates/DeferedRequirements.php
Executable file → Normal file
@ -48,7 +48,7 @@ class DeferedRequirements implements TemplateGlobalProvider
|
||||
|
||||
// Class libs
|
||||
if ($class) {
|
||||
$dir = Path::join(Director::publicFolder(), ManifestFileFinder::RESOURCES_DIR, 'site','client');
|
||||
$dir = Path::join(Director::publicFolder(), ManifestFileFinder::RESOURCES_DIR, 'app', 'client');
|
||||
|
||||
|
||||
if (file_exists(Path::join($dir, 'css', $class . '.css'))) {
|
2
site/src/Templates/WebpackTemplateProvider.php → app/src/Templates/WebpackTemplateProvider.php
Executable file → Normal file
@ -27,7 +27,7 @@ class WebpackTemplateProvider implements TemplateGlobalProvider
|
||||
/**
|
||||
* @var string assets static files directory
|
||||
*/
|
||||
private static $dist = 'site/client/dist';
|
||||
private static $dist = 'app/client/dist';
|
||||
|
||||
/**
|
||||
* @return array
|
@ -0,0 +1,6 @@
|
||||
<% if $ShowTitle %>
|
||||
<h2 class="list-element__title">$Title</h2>
|
||||
<% end_if %>
|
||||
<div class="list-element__container row" data-listelement-count="$Elements.Elements.Count">
|
||||
$Elements
|
||||
</div>
|
@ -0,0 +1,4 @@
|
||||
<% if $ShowTitle %><h3>$Title</h3><% end_if %>
|
||||
<% if $Image %>
|
||||
<img src="$Image.URL" class="img-responsive" alt="$Title.ATT">
|
||||
<% end_if %>
|
0
site/templates/Includes/Content.ss → app/templates/Includes/Content.ss
Executable file → Normal file
@ -1,6 +1,5 @@
|
||||
<% if $SlideShow %>
|
||||
<%-- Use: data-ride="carousel" to autoinitialize bootstrap carousel --%>
|
||||
<div id="Carousel{$ID}" class="carousel slide" data-indicators="true" data-arrows="true">
|
||||
<div id="Carousel{$ID}" class="carousel slide js-carousel" data-indicators="true" data-arrows="true">
|
||||
<div class="carousel-inner">
|
||||
<% loop $SlideShow %>
|
||||
<div class="carousel-item<% if $First %> active<% end_if %>">
|
10
site/templates/Includes/Head.ss → app/templates/Includes/Head.ss
Executable file → Normal file
@ -21,14 +21,14 @@ $MetaTags
|
||||
<link rel="preconnect" href="https://i9.ytimg.com" />
|
||||
<link rel="preconnect" href="https://s.ytimg.com" />
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{$AbsoluteBaseURL}resources/site/client/dist/icons/favicon.ico" />
|
||||
<link rel="icon" sizes="144x144" type="image/png" href="{$AbsoluteBaseURL}resources/site/client/dist/icons/android-chrome-144x144.png" />
|
||||
<link rel="apple-touch-icon" href="{$AbsoluteBaseURL}resources/site/client/dist/icons/apple-touch-icon.png" />
|
||||
<link rel="apple-touch-icon-precomposed" href="{$AbsoluteBaseURL}resources/site/client/dist/icons/apple-touch-icon-precomposed.png" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{$AbsoluteBaseURL}resources/app/client/dist/icons/favicon.ico" />
|
||||
<link rel="icon" sizes="144x144" type="image/png" href="{$AbsoluteBaseURL}resources/app/client/dist/icons/android-chrome-144x144.png" />
|
||||
<link rel="apple-touch-icon" href="{$AbsoluteBaseURL}resources/app/client/dist/icons/apple-touch-icon.png" />
|
||||
<link rel="apple-touch-icon-precomposed" href="{$AbsoluteBaseURL}resources/app/client/dist/icons/apple-touch-icon-precomposed.png" />
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
|
||||
<meta name="application-name" content="{$SiteConfig.Title}" />
|
||||
<meta name="msapplication-TileImage" content="{$AbsoluteBaseURL}resources/site/client/dist/icons/mstile-144x144.png" />
|
||||
<meta name="msapplication-TileImage" content="{$AbsoluteBaseURL}resources/app/client/dist/icons/mstile-144x144.png" />
|
||||
<meta name="msapplication-TileColor" content="#2F98F1" />
|
||||
|
||||
<meta content="yes" name="apple-mobile-web-app-capable" />
|
0
site/templates/Layout/HomePage.ss → app/templates/Layout/HomePage.ss
Executable file → Normal file
0
site/templates/Layout/Page.ss → app/templates/Layout/Page.ss
Executable file → Normal file
@ -18,7 +18,7 @@
|
||||
<header class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<a href="/"><img src="/resources/site/client/dist/img/logo.png" alt="{$SiteConfig.Title}" /></a>
|
||||
<a href="/"><img src="/resources/app/client/dist/img/logo.png" alt="{$SiteConfig.Title}" /></a>
|
||||
</div>
|
||||
<div class="col-sm-6 text-right">
|
||||
<% with $SiteConfig %>
|
@ -4,7 +4,7 @@
|
||||
"description": "The SilverStripe Framework Installer",
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"silverstripe/recipe-cms": "1.1",
|
||||
"silverstripe/recipe-cms": "1.2.x-dev",
|
||||
"wilr/silverstripe-googlesitemaps": "*",
|
||||
"silverstripe/userforms": "*",
|
||||
"undefinedoffset/sortablegridfield": "*",
|
||||
@ -30,19 +30,20 @@
|
||||
"vulcandigital/silverstripe-seo": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"lekoala/silverstripe-debugbar": "dev-master"
|
||||
},
|
||||
"extra": {
|
||||
"expose": [
|
||||
"site/client/dist",
|
||||
"site/thirdparty/client"
|
||||
"app/client/dist",
|
||||
"app/thirdparty/client"
|
||||
],
|
||||
"project-files-installed": [
|
||||
"mysite/.htaccess",
|
||||
"mysite/_config.php",
|
||||
"mysite/_config/mysite.yml",
|
||||
"mysite/code/Page.php",
|
||||
"mysite/code/PageController.php"
|
||||
"app/.htaccess",
|
||||
"app/_config.php",
|
||||
"app/_config/mysite.yml",
|
||||
"app/src/Page.php",
|
||||
"app/src/PageController.php"
|
||||
],
|
||||
"public-files-installed": [
|
||||
".htaccess",
|
||||
@ -56,5 +57,14 @@
|
||||
"process-timeout": 600
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
"minimum-stability": "dev",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Site\\": "app/src/"
|
||||
},
|
||||
"classmap": [
|
||||
"app/src/Pages/Page.php",
|
||||
"app/src/Pages/PageController.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,11 @@
|
||||
"jquery-hammerjs": "^2.0.0",
|
||||
"jquery-zoom": "^1.7.21",
|
||||
"meta-lightbox": "^1.0.0",
|
||||
"offcanvas-bootstrap": "^2.5.2",
|
||||
"popper.js": "^1.14.3",
|
||||
"pouchdb": "^6.4.3",
|
||||
"routie": "0.0.1",
|
||||
"smooth-scroll": "^14.2.0",
|
||||
"yarn": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,20 +0,0 @@
|
||||
SilverStripe\View\SSViewer:
|
||||
source_file_comments: true
|
||||
themes:
|
||||
- '$public'
|
||||
- 'simple'
|
||||
- '$default'
|
||||
|
||||
DNADesign\Elemental\Models\BaseElement:
|
||||
default_global_elements: true
|
||||
|
||||
SilverStripe\Admin\LeftAndMain:
|
||||
extra_requirements_javascript:
|
||||
- 'colymba/gridfield-bulk-editing-tools:client/dist/js/main.js'
|
||||
- 'colymba/gridfield-bulk-editing-tools:client/lang/en.js'
|
||||
extra_requirements_css:
|
||||
- 'colymba/gridfield-bulk-editing-tools:client/dist/styles/main.css'
|
||||
|
||||
SilverStripe\Forms\HTMLEditor\TinyMCEConfig:
|
||||
editor_css:
|
||||
- 'site/client/dist/css/editor.css'
|
@ -1,3 +0,0 @@
|
||||
Page:
|
||||
extensions:
|
||||
- DNADesign\Elemental\Extensions\ElementalPageExtension
|
@ -1,11 +0,0 @@
|
||||
# that's important to place this file into /site/_config/webpack.yml
|
||||
# with all configuration variables presented
|
||||
# Cuz WebPack compiling script use it to set configuration
|
||||
|
||||
Site\Templates\WebpackTemplateProvider:
|
||||
SRC: site/client/src
|
||||
DIST: site/client/dist
|
||||
HOSTNAME: localhost
|
||||
PORT: "3000"
|
||||
TYPESJS: site/client/src/js/types
|
||||
TYPESSCSS: site/client/src/scss/types
|
Before Width: | Height: | Size: 9.0 KiB |
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Just an example component
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
const SliderUI = (($) => {
|
||||
class SliderUI {
|
||||
static init() {
|
||||
this.each(function ($this) {
|
||||
const $items = $this.find('.carousel-item'),
|
||||
id = $this.attr('id'),
|
||||
count = $items.length;
|
||||
|
||||
if(!count){
|
||||
return;
|
||||
}
|
||||
|
||||
if($this.data('indicators')) {
|
||||
let $controls = $('<ol class="carousel-indicators"></ol>');
|
||||
$controls.append('<li data-target="#' + id + '" data-slide-to="0" class="active"></li>');
|
||||
for (let i = 1; i < count; i++) {
|
||||
$controls.append('<li data-target="#' + id + '" data-slide-to="' + i + '"></li>');
|
||||
}
|
||||
$this.prepend($controls);
|
||||
}
|
||||
|
||||
if($this.data('arrows')){
|
||||
$this.prepend('<i class="carousel-control-prev" data-target="#' + id + '" role="button" data-slide="prev"><i class="fas fa-chevron-left" aria-hidden="true"></i><i class="sr-only">Previous</i></i>');
|
||||
$this.prepend('<i class="carousel-control-next" data-target="#' + id + '" role="button" data-slide="next"><i class="fas fa-chevron-right" aria-hidden="true"></i><i class="sr-only">Next</i></i>');
|
||||
}
|
||||
|
||||
$this.carousel();
|
||||
});
|
||||
}
|
||||
|
||||
static dispose() {
|
||||
self.each(function ($this) {
|
||||
$this.carousel('dispose');
|
||||
});
|
||||
}
|
||||
|
||||
static each(callback) {
|
||||
$('.carousel').each(function () {
|
||||
callback($(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
return SliderUI;
|
||||
})($);
|
||||
|
||||
export default SliderUI;
|
@ -1,40 +0,0 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
import Events from './_events';
|
||||
// import an example component
|
||||
import Spinner from './_components/_spinner';
|
||||
import Slider from './_components/_slider';
|
||||
|
||||
const MainUI = (($) => {
|
||||
// Constants
|
||||
const NAME = 'MainUI';
|
||||
|
||||
class MainUI {
|
||||
// Static methods
|
||||
static init() {
|
||||
this.destroy();
|
||||
console.log(`Initializing: ${NAME}`);
|
||||
|
||||
Spinner.hide(() => {
|
||||
$('body').addClass('loaded');
|
||||
});
|
||||
|
||||
Slider.init();
|
||||
}
|
||||
|
||||
static destroy() {
|
||||
console.log(`Destroying: ${NAME}`);
|
||||
Spinner.show(() => {
|
||||
$('body').removeClass('loaded');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
MainUI.init();
|
||||
});
|
||||
|
||||
return MainUI;
|
||||
})($);
|
||||
|
||||
export default MainUI;
|
@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Your custom style
|
||||
*/
|
||||
|
||||
@import "_components/slider";
|
0
site/thirdparty/client/.gitkeep
vendored
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Load webpack configuration from site/_config/webpack.yml
|
||||
* Load webpack configuration from app/_config/webpack.yml
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, 'site/_config/webpack.yml'), 'utf8'));
|
||||
const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, 'app/_config/webpack.yml'), 'utf8'));
|
||||
|
||||
module.exports = conf['Site\\Templates\\WebpackTemplateProvider'];
|