IMPROVEMENT: input.mask, babel, terser

This commit is contained in:
Tony Air 2020-02-08 02:51:42 +07:00
parent f1cdf0fb50
commit af1db85bca
20 changed files with 527 additions and 246 deletions

View File

@ -1,7 +1,6 @@
---
Name: webapp
---
SilverStripe\Core\Manifest\ModuleManifest:
project: app
@ -16,6 +15,8 @@ Page:
# - 'colymba/gridfield-bulk-editing-tools:client/dist/styles/main.css'
SilverStripe\Admin\LeftAndMain:
extra_requirements_js:
- 'app/client/dist/css/app_cms.js'
extra_requirements_css:
- 'app/client/dist/css/app_cms.css'

View File

@ -5,11 +5,14 @@ After:
- elemental-list
- elementalvirtual
---
Page:
extensions:
- DNADesign\Elemental\Extensions\ElementalPageExtension
DNADesign\Elemental\Models\ElementalArea:
extensions:
- Site\Extensions\ElementalArea
DNADesign\Elemental\Models\BaseElement:
default_global_elements: true
extensions:

View File

@ -1,9 +1,9 @@
"use strict";
'use strict';
import $ from 'jquery';
import Events from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_events';
const LayoutUI = (($) => {
const LayoutUI = ($ => {
// Constants
const W = window;
const D = document;
@ -19,6 +19,33 @@ const LayoutUI = (($) => {
console.log(`Initializing: ${NAME}`);
// your custom UI
// Custom fonts
$Body.append(
'<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,700,700i&display=swap" rel="stylesheet">',
);
/*google analytics */
/*(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
'script',
'//www.google-analytics.com/analytics.js',
'ga',
);
ga('create', 'UA-********-*', 'auto');
ga('send', 'pageview');*/
}
static dispose() {

View File

@ -1,5 +1,6 @@
import $ from 'jquery';
import './_consts';
'use strict';
import '../scss/app.scss';
// import Bootstrap
import 'popper.js';
@ -8,7 +9,21 @@ import 'bootstrap/js/dist/alert';
import 'bootstrap/js/dist/button';
import 'bootstrap/js/dist/carousel';
import 'bootstrap/js/dist/collapse';
import 'bootstrap/js/dist/dropdown';
import 'hammerjs/hammer';
import 'jquery-hammerjs/jquery.hammer';
// Routie
//import 'pouchdb/dist/pouchdb';
//import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/routes/index';
// conflicts with _components/_ui.hover.js (shows dropdown on hover)
//import 'bootstrap/js/dist/dropdown';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.hover';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.carousel';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.menu';
import 'bootstrap/js/dist/modal';
import 'bootstrap/js/dist/tooltip';
import 'bootstrap/js/dist/popover';
@ -16,27 +31,58 @@ import 'bootstrap/js/dist/scrollspy';
import 'bootstrap/js/dist/tab';
//
import Spinner from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.spinner';
// Sticky sidebar
import SidebarUI from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.sidebar';
//import Multislider from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.multislider';
// Flyout UI
//import Flyout from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.flyout';
// Offcanvas menu
//import 'offcanvas-bootstrap/dist/js/bootstrap.offcanvas';
import '../scss/app.scss';
import '@a2nt/meta-lightbox/src/js/meta-lightbox';
// youtube video preview image
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.video.preview';
// MainUI
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_main';
// Uncomment it to enable meta-lightbox zooming on hover
//import 'jquery-zoom/jquery.zoom';
// Forms UI
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.basics';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.validate';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.stepped';
// Toggle bootstrap form fields
//import FormToggleUI from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.fields.toggle';
// Bootstrap Date & Time fields
//import FormDatetime from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.datetime';
// Stepped forms functionality
//import FormStepped from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.stepped';
// Forms validation functionality
//import FormValidate from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.validate';
// Store forms data into localStorage
//import FormStorage from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.storage';
// client-side images cropping
//import FormCroppie from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.croppie';
// Google NoCaptcha fields
//import NoCaptcha from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.nocaptcha';
// youtube video preview image
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.video.preview';
// Meta Lightbox
import '@a2nt/meta-lightbox/src/js/index';
//import Confirmation from 'bootstrap-confirmation2/dist/bootstrap-confirmation';
//import Table from 'bootstrap-table/dist/bootstrap-table';
// AJAX UI
//import AjaxUI from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.ajax';
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_main';
import './_layout';
// Import fonts and images
function importAll(r) {
return r.keys().map(r);
}
@ -48,5 +94,5 @@ const fontAwesome = importAll(
require.context('font-awesome', false, /\.(otf|eot|svg|ttf|woff|woff2)$/),
);
// Your custom JS
import './_layout';
// Google Analytics
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/drivers/_google.track.external.links';

View File

@ -1,6 +1,17 @@
/**
* Your custom style
*/
.field {
margin: 2rem 0;
&.required:after {
display: none;
}
}
.form-control,
.select2-container--default .select2-selection,
.select2-dropdown .select2-search__field {
border-width: 0 0 1px 0;
}
.bg-alt {
@extend .bg-dark;

View File

@ -1,6 +0,0 @@
#Menu-SilverStripe-CampaignAdmin-CampaignAdmin,
#Menu-Dynamic-Elements-Sponsors-Admin-SponsorsAdmin,
#Menu-Dynamic-Elements-Admin-TestimonialsAdmin,
#Menu-Dynamic-Elements-Promos-Admin-PromosAdmin {
display: none;
}

View File

@ -8,6 +8,7 @@
namespace Site\Extensions;
use DNADesign\Elemental\Models\BaseElement;
use DNADesign\ElementalList\Model\ElementList;
use SilverStripe\Core\Config\Config;
use SilverStripe\Forms\CheckboxField;
@ -28,6 +29,7 @@ class ElementRows extends DataExtension
private static $db = [
'ContainerType' => 'Varchar(254)',
//'SidebarOnly' => 'Boolean(0)',
'Size' => 'Enum("1,2,3,4,5,6,7,8,9,10,11,12,auto","auto")',
];
@ -37,9 +39,11 @@ class ElementRows extends DataExtension
// move available globaly to main tab
$fields->removeByName('AvailableGlobally');
//$fields->removeByName('SidebarOnly');
$tab = $fields->findOrMakeTab('Root.Main');
$tab->push(CheckboxField::create('AvailableGlobally'));
//$tab->push(CheckboxField::create('SidebarOnly', 'Hidden (Sidebar Only)'));
// container type
if ($this->isRoot()) {
@ -97,7 +101,24 @@ class ElementRows extends DataExtension
$fields->removeByName('Size');
}
$tab = $fields->findOrMakeTab('Root.Settings')
// move parent elements
if($this->isList()){
$tab->push(DropdownField::create(
'MoveElementIDToParent',
'Move an element from the list to parent',
$this->owner->getField('Elements')->Elements()->map('ID', 'Title')
)->setEmptyString('(select an element to move)'));
$tab->push(DropdownField::create(
'MoveElementIDFromParent',
'Move an element from parent to the list',
$this->owner->Parent()->Elements()
->exclude('ID', $this->owner->ID)
->map('ID', 'Title')
)->setEmptyString('(select an element to move)'));
}
$fields->findOrMakeTab('Root.Settings')
->push(LiteralField::create(
'ClassName',
'<div class="form-group field text">'
@ -247,4 +268,35 @@ class ElementRows extends DataExtension
return $type;
}
public static function MoveElement($moveID, $targetID) {
$el = BaseElement::get_by_id($moveID);
if(!$el) {
return false;
}
$el->setField('ParentID', $targetID);
$el->write();
return true;
}
public function onBeforeWrite()
{
parent::onBeforeWrite();
$moveID = $this->owner->getField('MoveElementIDFromParent');
$targetID = $moveID ? $this->owner->Elements()->ID : null;
if($moveID && $targetID) {
self::MoveElement($moveID, $targetID);
}
$moveID = $this->owner->getField('MoveElementIDToParent');
$targetID = $moveID ? $this->owner->Parent()->ID : null;
if($moveID && $targetID) {
self::MoveElement($moveID, $targetID);
}
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Created by PhpStorm.
* User: tony
* Date: 6/23/18
* Time: 1:23 PM
*/
namespace Site\Extensions;
use DNADesign\Elemental\Models\BaseElement;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\HasManyList;
use SilverStripe\ORM\UnsavedRelationList;
class ElementalArea extends DataExtension
{
public function ElementFilteredControllers()
{
// Don't try and process unsaved lists
if ($this->Elements() instanceof UnsavedRelationList) {
return ArrayList::create();
}
$controllers = ArrayList::create();
$items = $this->Elements()->filterByCallback(static function (BaseElement $item) {
return $item->canView();
});
if ($items !== null) {
foreach ($items as $element) {
$controller = $element->getController();
$controllers->push($controller);
}
}
return $controllers;
}
/**
* A cache-aware accessor for the elements
* @return ArrayList|HasManyList|BaseElement[]
*/
public function Elements()
{
return $this->owner->Elements();//->exclude('SidebarOnly', true);
}
}

View File

@ -24,7 +24,7 @@ class SocialExtension extends DataExtension
private static $has_one = [
'Facebook' => Link::class,
'LinkedIn' => Link::class,
'GooglePlus' => Link::class,
'Pinterest' => Link::class,
'Instagram' => Link::class,
'Twitter' => Link::class,
'PublicEmail' => Link::class,
@ -38,7 +38,7 @@ class SocialExtension extends DataExtension
$linkFields = [
LinkField::create('FacebookID'),
LinkField::create('LinkedInID'),
LinkField::create('GooglePlusID'),
LinkField::create('PinterestID'),
LinkField::create('InstagramID'),
LinkField::create('TwitterID'),
];

View File

@ -10,6 +10,7 @@ use DNADesign\Elemental\Models\ElementContent;
class Page extends SiteTree
{
private static $default_container_class = 'container';
protected $_cached = [];
public static function DefaultContainer()
{
@ -22,9 +23,14 @@ class Page extends SiteTree
*/
public function Summary($wordsToDisplay = 30)
{
if (isset($this->_cached['summary'.$wordsToDisplay])) {
return $this->_cached['summary'.$wordsToDisplay];
}
$summary = $this->getField('Summary');
if ($summary) {
return $summary;
$this->_cached['summary'.$wordsToDisplay] = $summary;
return $this->_cached['summary'.$wordsToDisplay];
}
$element = ElementContent::get()->filter([
@ -33,10 +39,12 @@ class Page extends SiteTree
])->first();
if ($element) {
return $element->dbObject('HTML')->Summary($wordsToDisplay);
$this->_cached['summary'.$wordsToDisplay] = $element->dbObject('HTML')->Summary($wordsToDisplay);
return $this->_cached['summary'.$wordsToDisplay];
}
return false;
$this->_cached['summary'.$wordsToDisplay] = false;
return $this->_cached['summary'.$wordsToDisplay];
}
public function CSSClass()

View File

@ -0,0 +1,5 @@
<% if $ElementFilteredControllers %>
<% loop $ElementFilteredControllers %>
$Me
<% end_loop %>
<% end_if %>

View File

@ -1,7 +1,10 @@
<% if $ImageResized %>
<div class="image-element__image<% if $Resize %><% if $Height %> height{$Height}<% end_if %><% if $Width %> width{$Width}<% end_if %><% end_if %>">
<% if $ImageLink %><a href="$ImageLink.URL"><% end_if %>
<img src="$ImageResized.URL" class="img-responsive" alt="$Title.ATT" />
<img
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-lazy-src="$ImageResized.URL" class="img-responsive" alt="$Title.ATT"
/>
<% if $ImageLink %></a><% end_if %>
</div>
<% end_if %>

View File

@ -5,7 +5,12 @@
</div>
<% if $FeaturedImage %>
<div class="img card-img-top">
<a href="$Link">$FeaturedImage.Fill(350,200)</a>
<a href="$Link">
<img
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-lazy-src="$FeaturedImage.Fill(350,200).URL" alt="$Title.ATT"
/>
</a>
</div>
<% end_if %>

View File

@ -1,4 +1,4 @@
<div class="hidden-print">
<div class="hidden-print hidden-md">
$BetterNavigator
</div>
@ -9,7 +9,6 @@ $AutoRequirements($ClassName).RAW
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.48.0/mapbox-gl.js"></script>
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.48.0/mapbox-gl.css" rel="stylesheet" />--%>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700,700i|Roboto:400,400i,700,700i&display=swap&subset=latin-ext" rel="stylesheet" />
<%-- place extra requirements after this line --%>
<div class="extra-code extra-code-site">
$SiteConfig.ExtraCode

View File

@ -32,12 +32,21 @@ $MetaTags
<link rel="author" type="text/plain" href="{$AbsoluteBaseURL}humans.txt" />
<link rel="sitemap" type="application/xml" title="Sitemap" href="{$AbsoluteBaseURL}sitemap.xml" />
<link rel="dns-prefetch" href="https://fonts.gstatic.com" />
<link rel="dns-prefetch" href="https://use.fontawesome.com" />
<link rel="dns-prefetch" href="https://ajax.googleapis.com" />
<link rel="preconnect" href="https://use.fontawesome.com/" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://maps.google.com" />
<link rel="preconnect" href="https://ajax.googleapis.com" />
<link rel="preconnect" href="https://use.fontawesome.com" crossorigin />
<link rel="preconnect" href="https://ajax.googleapis.com" crossorigin />
<link rel="dns-prefetch" href="https://csi.gstatic.com" />
<link rel="dns-prefetch" href="https://maps.google.com" />
<link rel="dns-prefetch" href="https://maps.googleapis.com" />
<link rel="preconnect" href="https://csi.gstatic.com" />
<link rel="preconnect" href="https://maps.google.com" />
<link rel="preconnect" href="https://maps.googleapis.com" />
<link rel="preconnect" href="https://www.youtube.com" />

View File

@ -7,7 +7,8 @@
<% if $Image || $ImageURL %>
<span class="img">
<img class="d-block w-100"
src="<% if $ImageURL %>$ImageURL<% else %>$Image.Fill(1400,650).URL<% end_if %>"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-lazy-src="<% if $ImageURL %>$ImageURL<% else %>$Image.Fill(1400,650).URL<% end_if %>"
alt="<% if $Headline %>$Headline.XML<% end_if %>"
/>
</span>

View File

@ -1,20 +1,20 @@
<div class="sc-links">
<% if $Facebook %>
<a href="$Facebook.LinkURL" title="Facebook" target="_blank">
<i class="fab fa-facebook"></i>
<i class="fab fa-facebook-f"></i>
<i class="sr-only">Facebook</i>
</a>
<% end_if %>
<% if $LinkedIn %>
<a href="$LinkedIn.LinkURL" title="LinkedIn" target="_blank">
<i class="fab fa-linkedin"></i>
<i class="fab fa-linkedin-in"></i>
<i class="sr-only">LinkedIn</i>
</a>
<% end_if %>
<% if $GooglePlus %>
<a href="$GooglePlus.LinkURL" title="Google+" target="_blank">
<i class="fab fa-google-plus-g"></i>
<i class="sr-only">Google+</i>
<% if $Pinterest %>
<a href="$Pinterest.LinkURL" title="Pinterest" target="_blank">
<i class="fab fa-pinterest-p"></i>
<i class="sr-only">Pinterest</i>
</a>
<% end_if %>
<% if $Instagram %>

View File

@ -43,12 +43,14 @@
$Layout
</div>
<div class="col-md-3">
<div class="page-content-sidebar page-content">
<div class="page-content-sidebar page-content jsSidebarUI">
<div class="jsSidebarUI__inner">
$SideBarView
</div>
</div>
</div>
</div>
</div>
<% else %>
<div class="content-holder">
$Layout

View File

@ -1,6 +1,6 @@
{
"name": "ss-webpack-boilerplate",
"version": "2.0.0",
"version": "2.0.1",
"description": "Lets you create SilverStripe faster",
"author": "Tony Air <tony@twma.pro>",
"license": "MIT",
@ -23,25 +23,28 @@
"lint:sass": "sass-lint ./app/client/src --config .sasslintrc -v -q"
},
"browserslist": [
"defaults"
"defaults",
"ie>=11"
],
"dependencies": {
"@a2nt/meta-lightbox": "^1.2.2",
"@a2nt/ss-bootstrap-ui-webpack-boilerplate": "^1.5.9",
"yarn": "^1.21.1"
"@a2nt/ss-bootstrap-ui-webpack-boilerplate": "^1.7.3",
"browserslist": "^4.8.6",
"caniuse-lite": "^1.0.30001025",
"inputmask": "^5.0.3",
"yarn": "^1.22.0"
},
"devDependencies": {
"@a2nt/image-sprite-webpack-plugin": "^0.2.5",
"@babel/core": "^7.8.4",
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
"@babel/plugin-transform-react-jsx": "*",
"@babel/preset-env": "^7.8.4",
"babel-eslint": "^8.2.6",
"babel-loader": "^8.0.6",
"@google/markerclusterer": "^1.0.3",
"animate.css": "^3.7.0",
"autoprefixer": "^7.2.5",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.6",
"babel-loader": "^7.1.2",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"autoprefixer": "^9.7.4",
"bootbox": "^4.4.0",
"bootstrap": "^4.4.1",
"bootstrap-confirmation2": "^4.1.0",
@ -58,9 +61,9 @@
"cross-env": "^5.2.1",
"css-loader": "^3.4.2",
"eslint": "^4.18.1",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jquery": "^1.5.1",
"eslint-plugin-react": "^7.18.0",
"eslint-plugin-react": "^7.18.3",
"exif-js": "^2.3.0",
"exports-loader": "^0.7.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
@ -80,7 +83,6 @@
"jquery-hoverintent": "*",
"jquery-zoom": "^1.7.21",
"jquery.appear": "^1.0.1",
"jquery.inputmask": "^3.3.4",
"laravel-mix": "^4.1.2",
"lost": "^8.3.1",
"mapbox-gl": "^1.6.1",
@ -116,7 +118,7 @@
"url-loader": "^0.6.2",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1",
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^1.3.2",
"webpack-merge": "^4.2.2"
},

View File

@ -39,6 +39,70 @@ ServerSignature Off
php_flag expose_php Off
</IfModule>
# Enable Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
# Leverage Browser Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"
</IfModule>
<IfModule mod_headers.c>
<filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
Header set Cache-Control "max-age=2678400, public"
</filesmatch>
<filesmatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private, must-revalidate"
</filesmatch>
<filesmatch "\.(pdf)$">
Header set Cache-Control "max-age=86400, public"
</filesmatch>
<filesmatch "\.(js)$">
Header set Cache-Control "max-age=2678400, private"
</filesmatch>
</IfModule>
### SILVERSTRIPE START ###
# Deny access to templates (but allow from localhost)