Base elements

This commit is contained in:
Tony Air 2018-06-23 17:27:06 +07:00
parent b437805ca0
commit 20a76fde8a
143 changed files with 1722 additions and 211 deletions

View File

@ -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
View File

2
site/_config.php → app/_config.php Executable file → Normal file
View File

@ -16,5 +16,3 @@ HtmlEditorConfig::get('cms')->enablePlugins([
]);
FulltextSearchable::enable();

22
app/_config/config.yml Normal file
View 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
View 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
View 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

View File

@ -1,3 +1,4 @@
SilverStripe\SiteConfig\SiteConfig:
extensions:
- Site\Extensions\SiteConfigExtension

11
app/_config/webpack.yml Normal file
View 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
View File

@ -0,0 +1,2 @@
/*# sourceMappingURL=HomePage.css.map*/

1
app/client/dist/css/HomePage.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/HomePage.css","sourceRoot":""}

7
app/client/dist/css/app.css vendored Normal file

File diff suppressed because one or more lines are too long

1
app/client/dist/css/app.css.map vendored Normal file

File diff suppressed because one or more lines are too long

2
app/client/dist/css/editor.css vendored Normal file
View File

@ -0,0 +1,2 @@
/*# sourceMappingURL=editor.css.map*/

1
app/client/dist/css/editor.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/editor.css","sourceRoot":""}

2
app/client/dist/css/typography.css vendored Normal file
View File

@ -0,0 +1,2 @@
/*# sourceMappingURL=typography.css.map*/

View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"css/typography.css","sourceRoot":""}

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.eot";

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.svg";

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.ttf";

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.woff";

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.woff2";

1
app/client/dist/icons/.cache vendored Normal file
View 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"]}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

15
app/client/dist/icons/browserconfig.xml vendored Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
app/client/dist/icons/favicon-16x16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

BIN
app/client/dist/icons/favicon-32x32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/client/dist/icons/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

58
app/client/dist/icons/manifest.json vendored Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
app/client/dist/icons/mstile-150x150.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
app/client/dist/icons/mstile-310x150.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
app/client/dist/icons/mstile-310x310.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
app/client/dist/icons/mstile-70x70.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,9 @@
{
"version": "1.0",
"api_version": 1,
"layout": {
"logo": "yandex-browser-50x50.png",
"color": "#fff",
"show_title": true
}
}

View File

@ -0,0 +1 @@
module.exports = "../fonts/fontawesome-webfont.svg";

BIN
app/client/dist/img/icon-cfpb.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
app/client/dist/img/icon-lender.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

BIN
app/client/dist/img/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

2
app/client/dist/js/HomePage.js vendored Normal file
View 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
View 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

File diff suppressed because one or more lines are too long

1
app/client/dist/js/app.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
app/client/dist/js/editor.js vendored Normal file
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

BIN
app/client/src/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View 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;

View 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;

View 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;

View 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;

View 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;

View File

@ -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;
})($);

View 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');
}
}
});*/

View 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);

View 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);
},
});
});

View File

@ -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
View 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">&times;</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;

View 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%;
}

View 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];
}
}
}

View File

0
site/src/Pages/Page.php → app/src/Pages/Page.php Executable file → Normal file
View File

View File

View 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'))) {

View 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

View File

@ -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>

View File

@ -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 %>

View 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 %>">

View 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" />

View File

View File

View 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 %>

View File

@ -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"
]
}
}

View File

@ -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": {

View File

@ -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'

View File

@ -1,3 +0,0 @@
Page:
extensions:
- DNADesign\Elemental\Extensions\ElementalPageExtension

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -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;

View File

@ -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;

View File

@ -1,5 +0,0 @@
/**
* Your custom style
*/
@import "_components/slider";

View File

View File

@ -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'];