Charcoal Boilerplate -> Locomotive front-end boilerplate

- Removing Charcoal files and configuration to be backend agnostic (therefore moving the assets)
- Using HTML5 Boilerplate .htaccess to which framework specific rules can be added later on
- Updating README with more information and documentation on the boilerplate
This commit is contained in:
dominiclord
2015-12-07 10:35:27 -05:00
parent 822dd4c8b6
commit b012a7a991
84 changed files with 1034 additions and 1881 deletions

6
.gitignore vendored
View File

@@ -1,5 +1,3 @@
.DS_Store
node_modules/
vendor
composer.lock
www/charcoal
www/modules/boilerplate/npm-debug.log
npm-debug.log

View File

@@ -1,6 +1,5 @@
module.exports = function(grunt) {
function loadConfig(path) {
var glob = require('glob');
var object = {};
@@ -16,7 +15,8 @@ module.exports = function(grunt) {
var config = {
pkg: grunt.file.readJSON('package.json')
}
};
grunt.loadTasks('grunt_tasks');
grunt.util._.extend(config, loadConfig('./grunt_tasks/'));
grunt.initConfig(config);
@@ -24,7 +24,6 @@ module.exports = function(grunt) {
// Load tasks
require('load-grunt-tasks')(grunt);
// Register tasks
grunt.registerTask('default', ['watch', 'notify:watch']);
grunt.registerTask('sync', ['browserSync', 'watch', 'notify:watch']);
@@ -44,12 +43,4 @@ module.exports = function(grunt) {
grunt.registerTask('j', [
'jshint'
]);
grunt.registerTask('wlint', [
// PHP
'phplint',
'jsonlint',
// Utilities
'watch'
]);
};

View File

@@ -1,31 +1,18 @@
Charcoal-Boilerplate
Locomotive front-end boilerplate
====================
Boilerplate for [`Charcoal`](#http://charcoal.locomotive.ca) projects by Locomotive.
Front-end Boilerplate for projects by Locomotive.
## Requirements
| Prerequisite | How to check | How to install |
| --------------- | ------------- | -------------- |
| Node.js 4.1.1 | `node -v` | [nodejs.org](//nodejs.org/) |
| Grunt >= 0.1.13 | `grunt -v` | `npm install -g grunt-cli` |
## Getting started
### Setup project
1. **Clone the boilerplate module into your own module**
1. `sh clone.sh {{project-name}}`
- where `{{project-name}}` is the name of the target project.
- Note: on windows, the `sh` command is usually ran from cygwin.
2. **Create and setup the database**
1. Create an empty database (most people use phpmyadmin...)
2. Setup the database in `www/config/config.json`
3. **Setup configuration**
1. Setup the proper `URL` in in `www/config/config.php`
2. Setup languages and project name, if necessary, in `www/config/config.json`
4. **Initialize Charcoal**
1. Make sure the Charcoal core is installed
- Using SVN, this is normally done with a `svn:externals` property in `www/`
2. Setup a local admin user
- Visit `http://{{project-url}}/admin` to start the admin user creation wizard.
### Install the node modules / grunt
1. **Get the latest node modules**
1. `npm install -g npm-check-updates`
2. `npm-check-updates -u`
@@ -34,29 +21,31 @@ Boilerplate for [`Charcoal`](#http://charcoal.locomotive.ca) projects by Locomot
2. **Run grunt and start coding**
- `grunt`
## Grunt
### Grunt
Each Grunt task has it's own file in the `grunt_tasks` folder.
#### BrowserSync
### BrowserSync
BrowserSync will automatically inject, refresh and sync all your browsers.
Run `grunt sync`
## SCSS
## CSS
### Import order
- We use [Sass](http://sass-lang.com/) for our CSS Preprocessor
- [itcss](http://itcss.io/) CSS architecture
- More Minimal BEM like CSS Syntax: `.block_element -modifier`
- [More Transparent UI Code with Namespaces](http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/)
### Sass import order
* **Settings:** Global variables, site-wide settings, config switches, etc.
* **Tools:** Site-wide mixins and functions.
* **Generic:** Low-specificity, far-reaching rulesets (e.g. resets).
* **Base:** Unclassed HTML elements (e.g. `a {}`, `blockquote {}`, `address {}`).
* **Objects:** Objects, abstractions, and design patterns (e.g. `.media {}`).
* **Components:** Discrete, complete chunks of UI (e.g. `.carousel {}`).
* **Objects:** Objects, abstractions, and design patterns (e.g. `.o-media {}`).
* **Components:** Discrete, complete chunks of UI (e.g. `.c-carousel {}`).
* **Trumps:** High-specificity, very explicit selectors. Overrides and helper
classes (e.g. `.hidden {}`).
*From [ITCSS](https://twitter.com/itcss_io)*
classes (e.g. `.u-hidden {}`).
### Grid
@@ -64,11 +53,11 @@ We are using a simple inline-block grid system.
**Usage**
Insert a `grid` block and add `grid__item` elements inside it.
Insert a `o-grid` block and add `o-grid_item` elements inside it.
No rows that contain floats, no twelve columns system; just the number of items you want, with the classes names you want, inside a single block.
- Include the grid mixins in your components classes.
- Create custom width grid items by including the `grid__item` mixin and adding the widths you need or just include the helpers mixins with fractions like names.
- Create custom width grid items by including the `o-grid_item` mixin and adding the widths you need or just include the helpers mixins with fractions like names.
- Add media queries, on the helpers mixins or on your custom components to change the grid items widths, for your content, on different screen sizes.
*[Demo](http://codepen.io/AntoineBoulanger/pen/EaLNxe)*
@@ -78,3 +67,8 @@ No rows that contain floats, no twelve columns system; just the number of items
We included some basic CSS styles and resets to the form elements so we can easily have custom style form elements that work on every browsers.
*[Demo](http://codepen.io/AntoineBoulanger/pen/uBJmi)*
## JavaScript
- We use HTML data attributes to init our JavaScript modules: `data-app`, `data-widget` and `data-template`
- All DOM related JavaScript is hooked to `js-` prefixed HTML classes
- [jQuery](https://jquery.com/) is globally included

View File

@@ -1,18 +0,0 @@
{
"minimum-stability":"stable",
"require": {
"league/climate": "~3.0",
"locomotivemtl/charcoal-composer-installer":"@dev",
"locomotivemtl/charcoal-legacy": "@dev"
},
"repositories":[
{
"type":"vcs",
"url":"https://github.com/mducharme/charcoal-composer-installer"
},
{
"type":"vcs",
"url":"https://github.com/locomotivemtl/charcoal-legacy"
}
]
}

View File

@@ -2,16 +2,15 @@ module.exports = {
dev: {
bsFiles: {
src: [
'www/modules/boilerplate/assets/styles/dist/*.css'
,'www/modules/boilerplate/assets/scripts/dist/*.js'
,'www/modules/boilerplate/assets/templates/*.php'
'www/assets/styles/dist/*.css',
'www/assets/scripts/dist/*.js'
]
},
options: {
proxy: "localhost",
proxy: 'localhost',
port: 3000,
watchTask: true,
notify: false
}
}
}
};

View File

@@ -1,19 +1,17 @@
module.exports = {
app: {
src: [
'www/modules/boilerplate/assets/scripts/src/app/*.js',
'www/modules/boilerplate/assets/scripts/src/templates/*.js',
'www/modules/boilerplate/assets/scripts/src/widgets/*.js',
'www/modules/boilerplate/assets/scripts/src/app.js'
'www/assets/scripts/src/app/*.js',
'www/assets/scripts/src/templates/*.js',
'www/assets/scripts/src/widgets/*.js',
'www/assets/scripts/src/app.js'
],
dest: 'www/modules/boilerplate/assets/scripts/dist/app.js'
dest: 'www/assets/scripts/dist/app.js'
},
vendors: {
src: [
'www/modules/boilerplate/assets/scripts/src/vendors/*.js'
'www/assets/scripts/src/vendors/*.js'
],
dest: 'www/modules/boilerplate/assets/scripts/dist/vendors.js'
dest: 'www/assets/scripts/dist/vendors.js'
}
};

View File

@@ -4,8 +4,8 @@ module.exports = {
},
build: {
expand: true,
cwd: 'www/modules/boilerplate/assets/styles/src/',
cwd: 'www/assets/styles/src/',
src: ['**/*.scss', '!base/_fonts.scss'],
dest: 'www/modules/boilerplate/assets/styles/src/'
}
dest: 'www/assets/styles/src/'
}
};

View File

@@ -2,9 +2,9 @@ module.exports = {
combine: {
files: [{
expand: true,
cwd: 'www/modules/boilerplate/assets/styles/dist/',
cwd: 'www/assets/styles/dist/',
src: '*.css',
dest: 'www/modules/boilerplate/assets/styles/dist/'
dest: 'www/assets/styles/dist/'
}]
}
}

View File

@@ -1,19 +1,19 @@
module.exports = {
options: {
"curly":true,
"eqeqeq": true,
"eqnull": true,
"undef":true,
"unused": true,
browser:true,
"globals":{
"window":true,
"$":true,
"jQuery":true
'curly': true,
'eqeqeq': true,
'eqnull': true,
'undef': true,
'unused': true,
'browser': true,
'globals': {
'window': true,
'$': true,
'jQuery': true
}
},
src: [
'www/modules/boilerplate/assets/scripts/src/**/*.js',
'!www/modules/boilerplate/assets/scripts/src/vendors/**/*.js'
],
'www/assets/scripts/src/**/*.js',
'!www/assets/scripts/src/vendors/**/*.js'
]
}

View File

@@ -1,20 +0,0 @@
module.exports = {
project:{
src:[
'*.json',
'../config/*.json',
'../config/**/*.json',
'config/*.json',
'config/**/*.json'
]
},
charcoal:{
src:[
'../charcoal/*.json',
'../charcoal/core/config/*.json',
'../charcoal/core/config/**/*.json',
'../charcoal/modules/**/config/*.json',
'../charcoal/modules/**/config/**/*.json'
]
}
}

View File

@@ -1,22 +0,0 @@
module.exports = {
options: {
swapPath: '/tmp',
phpArgs : {
// add -f for fatal errors
'-lf': null
}
},
project: [
'code/*.php',
'code/**/*.php',
'www/modules/boilerplate/assets/templates/*.php',
'www/modules/boilerplate/assets/templates/**/*.php'
],
charcoal: [
'../charcoal/core/code/*.php',
'../charcoal/core/code/**/*.php',
'../charcoal/modules/**/code/*.php',
'../charcoal/modules/**/code/**/*.php'
]
}

View File

@@ -4,13 +4,13 @@ module.exports = {
processors: [
require('autoprefixer')({
browsers: ['last 2 versions', '> 1%', 'ie >= 9']
}),
})
]
},
files: [
{
src : ['www/modules/boilerplate/assets/styles/dist/*.css'],
dest : 'www/modules/boilerplate/assets/styles/dist/',
src: ['www/assets/styles/dist/*.css'],
dest: 'www/assets/styles/dist/',
expand: true,
flatten: true
}

View File

@@ -4,7 +4,7 @@ module.exports = {
},
dist: {
files: {
'www/modules/boilerplate/assets/styles/dist/main.css': 'www/modules/boilerplate/assets/styles/src/main.scss'
'www/assets/styles/dist/main.css': 'www/assets/styles/src/main.scss'
}
}
}

View File

@@ -15,9 +15,9 @@ module.exports = {
},
dist: {
expand: true,
cwd: 'www/modules/boilerplate/assets/images/dist/',
cwd: 'www/assets/images/dist/',
src: '*.svg',
dest: 'www/modules/boilerplate/assets/images/dist/',
dest: 'www/assets/images/dist/',
ext: '.svg',
extDot: 'first'
}

View File

@@ -1,10 +1,8 @@
module.exports = {
options: {
},
options: {},
default: {
files: {
'www/modules/boilerplate/assets/images/dist/svgs.svg': ['www/modules/boilerplate/assets/images/svgs/*.svg'],
'www/assets/images/dist/svgs.svg': ['www/assets/images/svgs/*.svg']
}
}
}

View File

@@ -2,9 +2,9 @@ module.exports = {
target: {
files: [{
expand: true,
cwd: 'www/modules/boilerplate/assets/scripts/dist/',
cwd: 'www/assets/scripts/dist/',
src: '**/*.js',
dest: 'www/modules/boilerplate/assets/scripts/dist/'
dest: 'www/assets/scripts/dist/'
}]
}
}

View File

@@ -1,10 +1,10 @@
module.exports = {
javascript: {
files: ['www/modules/boilerplate/assets/scripts/src/**/*.js'],
files: ['www/assets/scripts/src/**/*.js'],
tasks: ['concat', 'notify:concat']
},
sass: {
files: ['www/modules/boilerplate/assets/styles/src/**/*.scss'],
files: ['www/assets/styles/src/**/*.scss'],
tasks: ['sass', 'postcss', 'notify:sass'],
options: {
spawn: false,
@@ -12,7 +12,7 @@ module.exports = {
}
},
svg: {
files: ['www/modules/boilerplate/assets/images/**/*.svg'],
files: ['www/assets/images/**/*.svg'],
tasks: ['svgstore', 'notify:svg']
},
tasks: {

View File

@@ -1,120 +0,0 @@
<?php
require_once('vendor/autoload.php');
function validate_project_name($project_name)
{
if(!is_string($project_name)) {
return false;
}
if(!$project_name) {
return false;
}
return !!preg_match('/^[a-z]+$/', $project_name);
}
$climate = new League\CLImate\CLImate;
$climate->description('Boilerplate setup: Rename the boilerplate files and classes');
$climate->arguments->add([
'project_name' => [
'longPrefix' => 'name',
'description' => 'Project (module) name',
'defaultValue' => ''
],
'help' => [
'longPrefix' => 'help',
'description' => 'Prints a usage statement',
'noValue' => true
],
'quiet' => [
'prefix' => 'q',
'longPrefix' => 'quit',
'description' => 'Disable Output additional information on operations',
'noValue' => false
]
]);
if($climate->arguments->defined('help')) {
$climate->usage();
die();
}
$climate->underline()->out('Charcoal Boilerplate Module Setup');
$climate->arguments->parse();
$project_name = $climate->arguments->get('project_name');
$verbose = !!$climate->arguments->get('quiet');
$verbose = true;
if(!$project_name) {
$input = $climate->input('What is the name of the project?');
$project_name = strtolower($input->prompt());
}
if(!validate_project_name($project_name)) {
$climate->red()->out('Invalid project name. Operation aborted.');
die();
}
$climate->bold()->out(sprintf('Using "%s" as project name...', $project_name));
if(!function_exists('glob_recursive')) {
function glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags));
}
return $files;
}
}
$climate->out("\n".'Replacing file content...');
foreach(glob_recursive("www/*") as $filename) {
if(!is_dir($filename)) {
$file = file_get_contents($filename);
$num_replacement1 = 0;
$num_replacement2 = 0;
$content = preg_replace("/boilerplate/", $project_name, $file, -1, $num_replacement1);
$content = preg_replace("/Boilerplate/", ucfirst($project_name), $content, -1, $num_replacement2);
$num_replacements = ($num_replacement1+$num_replacement2);
if($num_replacements > 0) {
file_put_contents($filename, $content);
if($verbose) {
$climate->dim()->out(sprintf('%d occurence(s) of "boilerplate" has been changed to "%s" in file "%s"', $num_replacements, $project_name, $filename));
}
}
}
}
$climate->out("\n".'Renaming files and directories');
$boilerplate_files = glob_recursive("www/*boilerplate*");
$boilerplate_files = array_reverse($boilerplate_files);
foreach($boilerplate_files as $filename) {
$target_name = preg_replace("/boilerplate/", $project_name, basename($filename));
$target_name = dirname($filename).'/'.$target_name;
if($target_name != $filename) {
rename($filename, $target_name);
if($verbose) {
$climate->dim()->out(sprintf('%s has been renamed to %s', $filename, $target_name));
}
}
}
$boilerplate_files = glob_recursive("www/*Boilerplate*");
$boilerplate_files = array_reverse($boilerplate_files);
foreach($boilerplate_files as $filename) {
$climate->inline('.');
$target_name = preg_replace("/Boilerplate/", ucfirst($project_name), basename($filename));
$target_name = dirname($filename).'/'.$target_name;
if($target_name != $filename) {
rename($filename, $target_name);
if($verbose) {
$climate->dim()->out(sprintf('%s has been renamed to %s', $filename, $target_name));
}
}
}
$climate->green()->out("\n".'Success!');

View File

@@ -1,114 +0,0 @@
<?php
require_once('vendor/autoload.php');
$climate = new League\CLImate\CLImate;
$climate->out('Charcoal Boilerplate Local Database Setup');
$input = $climate->input('What is your database username? ["root"]');
$input->defaultTo('root');
$db_user = $input->prompt();
$input = $climate->input('What is your database password? [""]');
$input->defaultTo('');
$db_password = $input->prompt();
$input = $climate->input('What is your database name?');
$db_name = $input->prompt();
if($db_name == '') {
$climate->red()->out('Setup aborted. Please enter a database name');
die();
}
$dsn = 'mysql:dbname='.$db_name;
try {
$dbh = new PDO($dsn, $db_user, $db_password);
$climate->out(sprintf('Database %s already exists.', $db_name));
$input = $climate->bold()->confirm('Do you want to use this database for this project?');
if ($input->confirmed()) {
// ...
}
else {
$climate->red()->out('Setup aborted.');
die();
}
}
catch (PDOException $e) {
$climate->out(sprintf('Database %s does not exist.', $db_name));
$input = $climate->bold()->confirm('Do you want to create it?');
if ($input->confirmed()) {
try {
$dbh = new PDO("mysql:", $db_user, $db_password);
$res = $dbh->exec("CREATE DATABASE `$db_name`;");
if(!$res) {
$climate->red()->out('Setup aborted. Could not create database.');
die();
}
else {
$climate->green()->out('Database created successfully.');
}
}
catch (PDOException $e) {
$climate->red()->out('Setup aborted. Could not create database.');
die();
}
}
else {
$climate->red()->out('Setup aborted.');
die();
}
}
// If here, DB is created. Setup config.json
$climate->out('Setting up the database for the project...');
$filename = 'www/config/config.json';
if(!file_exists($filename) || !is_writable($filename)) {
$climate->red()->out('Could not open config.json or file not writeable');
die();
}
$config = file_get_contents($filename);
$json = json_decode($config, true);
$input = $climate->input('What should the database ident be in the config file? ["local"]');
$input->defaultTo('local');
$db_ident = $input->prompt();
if(!isset($json['databases'])) {
$json['databases'] = [];
}
$databases = array_keys($json['databases']);
if(in_array($db_ident, $databases)) {
$input = $climate->bold()->confirm('Database ident already exists in the config file. Overwrite?');
if (!$input->confirmed()) {
$climate->red()->out('Setup aborted.');
die();
}
}
$json['databases'][$db_ident] = [
'database' => $db_name,
'username' => $db_user,
'password' => $db_password
];
$climate->green()->out('Database added successfully to config file.');
$input = $climate->bold()->confirm(sprintf('Do you want to use "%s" as the default database ident?', $db_name));
if ($input->confirmed()) {
$json['default_database'] = $db_ident;
}
$config = json_encode($json, JSON_PRETTY_PRINT);
$res = file_put_contents($filename, $config);
if($res === false) {
$climate->red()->out('Could not write config file. Setup aborted');
}
else {
$climate->green()->out('Database configuration successful.');
}

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,16 +0,0 @@
<?php
/**
* Default front-end section controller
* Simply delegates initiation to the Boilerplate Module.
*/
// Project configuration and Charcoal instanciation
include 'config/config.php';
// Charcoal init
Charcoal::init();
// Project init (front-page controller)
$opts = [];
Boilerplate_Module::init($opts);

View File

@@ -1,3 +0,0 @@
Order Deny,Allow
Deny from all

View File

@@ -1,48 +0,0 @@
{
"project_name": "Boilerplate",
"databases": {
"local": {
"database": "gdfg",
"username": "root",
"password": ""
},
"lab": {
"database": "",
"username": "",
"password": ""
},
"live": {
"database": "",
"username": "",
"password": ""
}
},
"default_database": "local",
"languages": {
"fr": {
"active": true
},
"en": {
"active": true
}
},
"default_language": "fr",
"modules": {
"admin": [],
"cms": [],
"newsletter": [],
"boilerplate": []
},
"objects": [],
"apis": [],
"default_template_controller":"Boilerplate_Template_Controller",
"url_options":{
"use_rewrite":true,
"lowercase":true,
"use_dash":true,
"remove_punctuation":true
},
"debug":{
"active":false
}
}

View File

@@ -1,5 +0,0 @@
{
"debug":{
"active":true
}
}

View File

@@ -1,33 +0,0 @@
<?php
/**
* config.php
*/
// Error reporting
error_reporting(E_ALL & ~E_STRICT);
ini_set('display_errors', true);
// Main Charcoal include. This is where the Charcoal autoloader is defined.
include __DIR__.'/../charcoal/charcoal.php';
// JSON Configuration
Charcoal::add_config(__DIR__.'/config.json');
$application_env = Charcoal::application_env();
if(file_exists(__DIR__ . '/config.'.$application_env.'.json')) {
Charcoal::add_config(__DIR__ . '/config.'.$application_env.'.json');
}
// Environment defaults
date_default_timezone_set('America/Montreal');
// Configuration overwrite
Charcoal::$config['ROOT'] = realpath(__DIR__).'/../';
if(isset($_SERVER['HTTP_HOST'])) {
Charcoal::$config['URL'] = 'http://'.$_SERVER['HTTP_HOST'].'/';
}
else {
Charcoal::$config['URL'] = 'http://localhost/';
}

View File

@@ -2,6 +2,7 @@
<!--[if lte IE 9]> <html lang="fr" class="ie9"> <![endif]-->
<!--[if gt IE 9]><!--> <html lang="fr"> <!--<![endif]-->
<head>
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
@@ -9,16 +10,16 @@
<meta name="theme-color" content="#f2f2f2">
<title>Boilerplate</title>
<link rel="apple-touch-icon" href="modules/boilerplate/assets/images/apple-touch-icon.png">
<link rel="icon" href="modules/boilerplate/assets/images/favicon.png">
<link rel="apple-touch-icon" href="assets/images/apple-touch-icon.png">
<link rel="icon" href="assets/images/favicon.png">
<link rel="stylesheet" href="modules/boilerplate/assets/styles/dist/main.css">
<link rel="stylesheet" href="assets/styles/dist/main.css">
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="modules/boilerplate/assets/scripts/dist/jquery-1.11.3.min.js"><\/script>')</script>
<script src="modules/boilerplate/assets/scripts/dist/vendors.js"></script>
<script src="modules/boilerplate/assets/scripts/dist/app.js"></script>
<script>window.jQuery || document.write('<script src="assets/scripts/dist/jquery-1.11.3.min.js"><\/script>')</script>
<script src="assets/scripts/dist/vendors.js"></script>
<script src="assets/scripts/dist/app.js"></script>
</body>
</html>

View File

@@ -1,18 +0,0 @@
<?php
/**
* Default front-end section controller
* Simply delegates initiation to the Boilerplate Module.
*/
// Project configuration and Charcoal instanciation
include 'config/config.php';
// Charcoal init
Charcoal::init();
// Project init (front-page controller)
$opts = [
'default_section' => Boilerplate_Config::get_latest()->default_section
];
Boilerplate_Module::init($opts);

View File

@@ -1,123 +0,0 @@
<?php
/**
* Boilerplate Action - Contact
*
* This action handles the "contact" form from the contact template
*
* It validates a CSRF token and create a CMS_Contact object from the POST data.
*
* ## Expected POST values:
* - csrf-token, string - A CSRF token (Charcoal::token() with ident "boilerplate.contact")
* - lastname
* - firstname
* - phone
* - email
* - subject
* - message
* - lang
*
* ## Optional POST values
* - referer, string - The URL to go back to
*
* ## CMS_Contact
* Contacts can be seen in the charcoal backend at url:
* [/admin/object-list-dashboard?obj_type=CMS_Contact]
*
* ## CMS_Contact_Category
* This action is bound to the CMS_Contact_Category object with id=1. This category:
* - Send confirmation email automatically
* - With email template boilerplate.contact-confirmation
* - May have CC and BCC to administratotors
*
* This object can be seen int he charcoal backend at url:
* [/admin/object-edit-dashboard?obj_type=CMS_Contact_Category&obj_id=1]
*
* ## TODOs
* - Support ajax request / json response
*
* @category Boilerplate
* @package Boilerplate.Action
* @subpackage Actions
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2012-08-01
* @link http://locomotive.ca
* @since Version 2014-07-01
*/
// Get referer
$referer = '';
if(isset($_POST['referer'])) {
$referer = filter_input(INPUT_POST, 'referer', FILTER_SANITIZE_STRING);
}
else if(isset($_SERVER['HTTP_REFERER'])) {
$referer = $_SERVER['HTTP_REFERER'];
}
else {
// None set: Use contact form
$referer = Charcoal::obj('CMS_Section')->load_from('ident', 'contact')->url();
}
function _header_error($msg='')
{
global $referer;
if(headers_sent()) {
// Error, cant send headers. Should never happened
die();
}
header('Location: '.$referer.'?contact-success=0&msg='.urlencode($msg));
die();
}
function _header_success($msg='')
{
global $referer;
if(headers_sent()) {
// Error, cant send headers. Should never happened
die();
}
header('Location: '.$referer.'?contact-success=1&msg='.urlencode($msg));
die();
die();
}
// Validate CSRF token
$csrf_token = filter_input(INPUT_POST, 'csrf-token', FILTER_SANITIZE_STRING);
if(!Charcoal::token_validate($csrf_token, 'boilerplate.contact')) {
Charcoal::feedback('error', 'send_contact', _t("Your session has expired. Please try again"));
_headers_error();
}
// Create and save the Contact object
$contact = Charcoal::obj('CMS_Contact');
$contact->from_flat_data($_POST);
// Hardcoded to the general contact category
$contact->category = 1;
$validations = $contact->validate();
if(!$validations){
//pre($contact);
// Saving the contact sends the email confirmatino automatically, according to the category
$contact_id = $contact->save();
if($contact_id) {
_header_success()_t("Successful.");
}
else {
_headers_error(_t("Error saving contact"));
}
}
else {
$msg = '';
foreach($validations as $property=>$messages){
foreach($messages as $m){
$msg .= $m.'<br />';
}
}
_headers_error($msg);
}

View File

@@ -1,13 +0,0 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/

View File

@@ -1,38 +0,0 @@
<?php
/**
* Contact form section
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="contact {{section.ident}}">
<h1>{{section.p.title}}</h1>
<h2>{{section.p.subtitle}}</h2>
<div class="section-summary">
{{section.p.summary.display}}
</div>
<div class="section-description">
{{section.p.content.display}}
</div>
<form method="post">
</form>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -1,35 +0,0 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="content {{section.ident}}">
<h1>{{section.p.title}}</h1>
<h2>{{section.p.subtitle}}</h2>
<div class="section-summary">
{{section.p.summary.display}}
</div>
<div class="section-description">
{{section.p.content.display}}
</div>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -1,25 +0,0 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="home {{section.ident}}">
<h1>{{section.p.title}}</h1>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -1,6 +0,0 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="modules/{{module}}/assets/scripts/dist/jquery-1.11.3.min.js"><\/script>')</script>
<script src="modules/{{module}}/assets/scripts/dist/vendors.js"></script>
<script src="modules/{{module}}/assets/scripts/dist/app.js"></script>
</body>
</html>

View File

@@ -1,37 +0,0 @@
<!doctype html>
<!--[if lte IE 9]> <html lang="{{lang}}" class="ie9"> <![endif]-->
<!--[if gt IE 9]><!--> <html lang="{{lang}}"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<base href="{{URL}}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f2f2f2">
<title>{{meta_title}}</title>
<link rel="apple-touch-icon" href="{{#assets.images}}apple-touch-icon.png{{/assets.images}}">
<link rel="icon" href="{{#assets.images}}favicon.png{{/assets.images}}">
<link rel="stylesheet" href="{{#assets.styles}}dist/main.css{{/assets.styles}}">
<meta name="description" content="{{meta_description}}">
{{opengraph_tags}}
{{! Only include analytics if it is set in the configuration}}
{{#cfg.google_analytics}}
<script>
(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', '{{cfg.google_analytics}}', 'auto');
ga('send', 'pageview');
</script>
{{/cfg.google_analytics}}
{{!A final chance to have custom headers tags (like styles or scripts) in the controllers}}
{{extra_header_content}}
</head>
<body>

View File

@@ -1,181 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* Boilerplate configuration
*
* The latest (current) object can always be used by calling:
* ```php
* $cfg = \Boilerplate\Config::get_latest();
* ```
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Config extends \Charcoal_Object
{
/**
* Google Analytics code
* @var string $google_analytics
* @see Property_String
*/
public $google_analytics;
/**
* Default section
* The section to load when reaching the default base URL.
* Also, usually the section to load when clicking on the main link / logo
* @var mixed $default_section
* @see Property_Object
* @see CMS_Section
*/
public $default_section;
/**
* Default lang
* @var string $default_lang
* @see Property_Lang
*/
public $default_lang;
/**
* URL of the related facebook page
* @var string $social_facebook_url
* @see Property_Url
*/
public $social_facebook_url;
/**
* URL of the related twitter account
* @var string $social_twitter_url
* @see Property_Url
*/
public $social_twitter_url;
/**
* URL of the related google+ page
* @var string $social_facebook_url
* @see Property_Url
*/
public $social_google_url;
/**
* URL of the related instagram page
* @var string $social_instagram_url
* @see Property_Url
*/
public $social_instagram_url;
/**
* URL of the related flickr page
* @var string $social_flickr_url
* @see Property_Url
*/
public $social_flickr_url;
/**
* URL of the related youtube page
* @var string $social_youtube_url
* @see Property_Url
*/
public $social_youtube_url;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_title
* @see Property_String
*/
public $meta_default_title;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_prefix
* @see Property_String
*/
public $meta_title_prefix;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_suffix
* @see Property_String
*/
public $meta_title_suffix;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_description
* @see Property_Text
*/
public $meta_default_description;
/**
* Default title, if none is specified
* - l10n: true
* - upload_path: "uploads/config/meta_image/"
* @var mixed $meta_default_image
* @see Property_Image
*/
public $meta_default_image;
/**
* Default meta-keywords, if none is specified
* - l10n: true
* - multiple: true
* @var mixed $meta_default_keywords
* @see Property_String
*/
public $meta_default_keywords;
/**
* Static getter of the latest config
*
* This is the preferred way of loading the Configuration object.
*
* It will only be loaded 1 time from the configuration, otherwie, it will be stored
* in a static variable.
*
* @return static Corim_Config
* @todo Use APC instead of static, if available
*/
static public function get_latest()
{
static $_cached;
$cache_key = 'latest_boilerplate_config';
if($_cached instanceof self) {
// Load from static if possible
return $_cached;
}
else {
// Load from DB otherwise
$_cached = Charcoal::obj( __CLASS__ );
$_cached->load_latest();
return $_cached;
}
}
/**
* @return Corim_Config
*/
public function load_latest()
{
// Hardcoded to ID 1
$this->load_key('id', 1);
// Chainable
return $this;
}
}

View File

@@ -1,91 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* The Boilerplate Module class
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Module extends Charcoal_Module
{
/**
* Module initialisation
*
* This function should act as both the initialization of the module and the front-page main controller.
*
* ## Options
* - default_action
* - default_section
* - default_lang
*
* @param array $opts
*
* @return null
*/
static public function init($opts=null)
{
// Make sure a session is started at all time. For tokens, some cache, user data, etc.
if (!session_id()) {
session_start();
}
// Get the latest configuration
$default_action = isset($opts['default_action']) ? $opts['default_action'] : '';
$default_section_id = isset($opts['default_section']) ? $opts['default_section'] : 0;
$default_lang = isset($opts['default_lang']) ? $opts['default_lang'] : 'fr';
// Load the action or section from the $_GET
$action = isset($_GET['action']) ? filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING) : $default_action;
$section_id = isset($_GET['s']) ? filter_input(INPUT_GET, 's', FILTER_SANITIZE_STRING) : $default_section_id;
// Set up the language and the required CSV file
$lang = isset($_GET['lang']) ? filter_input(INPUT_GET, 'lang', FILTER_SANITIZE_STRING) : $default_lang;
$l = Charcoal_L10n::get();
$l->set_lang($lang);
$l->add_resource_csv('boilerplate', $lang);
if($section_id) {
// By section
$section_loader = new Charcoal_Object_Loader('CMS_Section');
$section = $section_loader->{$section_id};
if($section->template) {
// What to do?
}
$tpl = Charcoal_Template::get($section->template);
// Section is already loaded, let's tell the controller about it.
$tpl->controller()->set_section( $section );
echo $tpl->render();
}
else if($action) {
// By action
\Charcoal::exec($action, $_REQUEST);
}
else {
// By nothing (404 page not found). This should never happen
die('404');
}
}
}

View File

@@ -1,263 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Template_Controller extends Charcoal_Template_Controller
{
/**
* Keep a copy of the current section
*/
private $_section;
/**
* Keep a copy of the Section Object loader
* @var \Charcoal_Object_Loader
*/
private $_sections_loader;
/**
* Keep a copy of the Template loader
* @var \Charcoal\Template_Loader
*/
private $_templates_loader;
/**
* Keep a copy of the Widget Loader
* @var \Charcoal\Widget_Loader
*/
private $_widgets_loader;
/**
* Get the current project's main module
*
* @return string
*/
public function module()
{
return 'boilerplate';
}
/**
* Sets the section to something when there is
* no "s" get parameter and we still wanna use this
*
* @see Cocqsac_module::init()
* @param $section CMS_Section Object
* @return this (chainable)
*/
public function set_section( $section )
{
$this->_section = $section;
return $this;
}
/**
* Get the current
* (Previously, this would have been `Charcoal::$vars['section']`)
*
* @return CMS_Section
*/
public function section()
{
if(isset($this->_section)) {
return $this->_section;
}
$section_id = isset($_GET['s']) ? filter_input(INPUT_GET, 's', FILTER_SANITIZE_STRING) : '';
$section = \Charcoal::obj('CMS_Section');
if($section_id) {
$section->load($section_id);
}
$this->_section = $section;
return $section;
}
/**
* Get a `CMS_Section` Object Loader
*
* - Use "ident" as a key, so it can be called with {{sections.ident}}
* - Cache the result, so this almost never touches the DB.
*
* ## The `\Charcoal_Object_Loader` object
* Read the documentation on `\Charcoal_Object_Loader` for more details.
* In short, it allows to call the objects with `->texts()->ident;` // `{{sections.ident}}` to return (and load on-the-fly, if required)
* the `CMS_Text` object with the `ident` "ident".
*
* @return \Charcoal\Object_Loader
* @see CMS_Section
*/
public function sections()
{
if(!$this->_sections_loader) {
// Load the object, if it was not.
$this->_sections_loader = new \Charcoal_Object_Loader('CMS_Section', 'ident', 'cache');
}
return $this->_sections_loader;
}
/**
* Get a "CMS_Text" Object Loader
* - Use "ident" as a key, so it can be called with {{sections.ident}}
* - Cache the result, so this almost never touches the DB.
*
* ## The `\Charcoal_Object_Loader` object
* Read the documentation on `\Charcoal_Object_Loader` for more details.
* In short, it allows to call the objects with `->sections()->ident;` to return (and load on-the-fly, if required)
* the `CMS_Section` object with the `ident` "ident".
*
* @return \Charcoal\Object_Loader
* @see CMS_Text
*/
public function texts()
{
if(!$this->_texts_loader) {
// Load the (text loader) object, if it was not.
$this->_texts_loader = new \Charcoal_Object_Loader('CMS_Text', 'ident', 'cache');
}
return $this->_texts_loader;
}
/**
* Get the latest Config instance from DB / cache
*
* @return Config
*/
public function cfg()
{
return Boilerplate_Config::get_latest();
}
/**
* Return the base URL
* Previously, this would have been `Charcoal::$config['URL']` (which still works)
*
* @return string
*/
public function URL()
{
return \Charcoal::$config['URL'];
}
/**
* Return the current URL
*
* @return string
*/
public function current_url()
{
return Charcoal::$config['HTTP_MODE'] . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
/**
* Test templating.
*
* Allow to hide content under dev_mode
*
* @return boolean
*/
public function dev_mode()
{
return false;
}
/**
* Returns the current language (2-character / ISO-639-1)
*
* @return string
*/
public function lang()
{
return _l();
}
/**
* Assets getters
*
* This method returns an array of lambda functions, which in turn takes the argument
*
* ## Using with mustache
* In short, this allows to get an asset with the following mustache tag:
* - `{{#assets.images}}test.png{{/assets.images}}
*
* ## Asset types
* - images
* - styles
* - scripts
* - fonts
* - files
* Read the documentation on \Charcoal\Asset for more details on how assets are loaded relative to the filesystem.
*
* @return array
* @see \Charcoal\Asset
*/
public function assets($asset_mode='url')
{
$ret = [
'images' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('images', $txt, $asset_mode);
},
'styles' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('styles', $txt, $asset_mode);
},
'scripts' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('scripts', $txt, $asset_mode);
},
'fonts' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('fonts', $txt, $asset_mode);
},
'files' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('files', $txt, $asset_mode);
}
];
return $ret;
}
/**
* Get the proper name of the template, usable for css class.
*
* (Replace invalid characters, such as a dot.)
*
* @return string
*/
public function template_class()
{
$token = $this->section()->template;
$search = ["boilerplate_"];
$replace = [""];
$token = str_replace(".", "_", $token);
if ( is_numeric($token) ) {
$token = preg_replace('/\D+/', '', $token);
}
else {
$token = str_replace($search, $replace,$token);
$token = preg_replace('/[^\w-]/', '', strtolower($token));
}
return $token;
}
}

View File

@@ -1,29 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Contact extends Boilerplate_Template_Controller
{
}

View File

@@ -1,29 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Content extends Boilerplate_Template_Controller
{
}

View File

@@ -1,29 +0,0 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Home extends Boilerplate_Template_Controller
{
}

View File

@@ -1,350 +0,0 @@
{
"config_type":"object",
"config_version":1,
"module":"boilerplate",
"name":{
"en":"Configuration",
"fr":"Configuration"
},
"description":{
"en":"",
"fr":""
},
"long_description":{
"en":"",
"fr":""
},
"notes":{
"en":"",
"fr":""
},
"revision":true,
"properties":{
"id":{
"type":"id"
},
"google_analytics":{
"type":"string",
"label":{
"fr":"ID Google Analytics",
"en":"Google Analytics ID"
},
"notes":{
"fr":"Ex: UA-XXXXXX-X",
"en":"Ex: UA-XXXXXX-X"
}
},
"default_section":{
"type":"object",
"obj_type":"cms_section",
"label":{
"en":"Default section",
"fr":"Section par défaut"
},
"description":{
"en":"Default section is loaded when the default URL (without any section) is reached, or usually when the logo is clicked. Typically, this should be a \"Home\" section.",
"fr":"La section par défaut est chargée lorsqu'un utilisateur atteint l'URL par défaut (sans paramètre de section). Est également, à l'habitude, la section qui est chargée lorsque le logo est cliqué. Typiquement, ce devrait être une section \"Accueil\"."
},
"input_type":"tree_select",
"input_options":{
"tree_select":{
"tree_property":"master",
"order_property":"position"
}
}
},
"default_lang":{
"type":"lang",
"label":{
"en":"Default language",
"fr":"Langage par défaut"
}
},
"contact_address":{
"type":"string",
"l10n":true
},
"contact_address2":{
"type":"string",
"l10n":true
},
"contact_city":{
"type":"string",
"l10n":true
},
"contact_postal_code":{
"type":"string"
},
"contact_province":{
"type":"string",
"l10n":true
},
"contact_country":{
"type":"string"
},
"contact_phone":{
"type":"phone"
},
"contact_phone2":{
"type":"phone"
},
"contact_fax":{
"type":"phone"
},
"contact_email":{
"type":"email"
},
"contact_lat":{
"type":"float"
},
"contact_lon":{
"type":"float"
},
"social_facebook_url":{
"type":"string"
},
"social_twitter_url":{
"type":"string"
},
"social_google_url":{
"type":"string"
},
"social_linkedin_url":{
"type":"string"
},
"social_instagram_url":{
"type":"string"
},
"social_flickr_url":{
"type":"string"
},
"social_youtube_url":{
"type":"string"
},
"meta_default_title":{
"type":"string",
"l10n":true
},
"meta_title_prefix":{
"type":"string",
"l10n":true
},
"meta_title_suffix":{
"type":"string",
"l10n":true
},
"meta_default_description":{
"type":"text",
"l10n":true
},
"meta_default_image":{
"type":"image",
"upload_path":"uploads/cfg/meta_default_image/"
},
"meta_default_keywords":{
"type":"string",
"multiple":true,
"l10n":true,
"notes":{
"en":"",
"fr":"À moins d'avis professionnel disant le contraire, les mots-clés par défaut devraient être laissés vide."
}
},
"signature_text":{
"type":"string",
"l10n":true,
"label":{
"en":"Signature text",
"fr":"Texte de la signature"
}
},
"signature_title":{
"type":"string",
"l10n":true,
"label":{
"en":"Signature title",
"fr":"Titre de la signature"
},
"description":{
"en":"This is mainly used for SEO purpose.",
"fr":"Le titre est principalement utilisé à des fins de référencement / SEO."
}
},
"signature_url":{
"type":"url",
"l10n":true,
"label":{
"en":"Signature URL",
"fr":"Lien de la signature"
}
}
},
"data":{
},
"sources":{
"default":{
"table":"boilerplate_config"
}
},
"default_source" : "default",
"lists":{
"boilerplate_config":{
"label":{
"fr":"Liste des sections",
"en":"Section list"
},
"description":{
},
"properties":[
],
"orders":{
"position":{
"property":"position",
"mode":"asc"
}
}
}
},
"default_list":"boilerplate_config",
"forms":{
"boilerplate_config":{
"label":{
"en":"Configuration",
"fr":"Configuration"
},
"groups":{
"analytics":{
"label":{
"en":"Analytics",
"fr":"Outils d'analyse"
},
"properties":[
"google_analytics"
]
},
"content":{
"label":{
"en":"Default content settings",
"fr":"Configuration de contenu par défaut"
},
"properties":[
"default_section",
"default_lang"
]
},
"social":{
"label":{
"en":"Social Links",
"fr":"Liens sociaux"
},
"properties":[
"social_facebook_url",
"social_twitter_url",
"social_google_url",
"|",
"social_linkedin_url",
"|",
"social_instagram_url",
"social_flickr_url",
"|",
"social_youtube_url"
],
"properties_options":{},
"priority":30
},
"contact":{
"label":{
"en":"Meta-informations",
"fr":"Informations méta"
},
"l10n":true,
"l10n_options":{
"mode":"loop_group"
},
"properties":[
"contact_address",
"contact_address2",
"contact_city",
"contact_postal_code",
"contact_province",
"contact_country",
"|",
"contact_phone",
"contact_phone2",
"contact_fax",
"|",
"contact_email"
],
"properties_options":{},
"priority":40
},
"meta":{
"label":{
"en":"Meta-informations",
"fr":"Informations méta"
},
"l10n":true,
"l10n_options":{
"mode":"loop_group"
},
"properties":[
"meta_default_title",
"meta_title_prefix",
"meta_title_suffix",
"meta_default_description",
"meta_default_keywords",
"meta_default_image"
],
"properties_options":{},
"priority":50
},
"signature":{
"label":{
"en":"Signature",
"fr":"Signature"
},
"l10n":true,
"l10n_options":{
"mode":"loop_group"
},
"properties":[
"signature_text",
"signature_url",
"signature_title"
],
"priority":60
}
}
}
},
"default_form":"boilerplate_config",
"dashboards":{
},
"widgets": {
},
"patterns":{
},
"default_pattern":"default"
}

View File

@@ -1,3 +0,0 @@
{
}

View File

@@ -1,8 +0,0 @@
{
"url_options":{
"rewrite_pattern":{
"fr":"fr/{{:id}}/{{title:url}}",
"en":"en/{{:id}}/{{title:url}}"
}
}
}