├── dist
├── js.js
├── js.min.js
├── style.min.css
├── style.css
└── style.css.map
├── assets
├── style
│ └── main.scss
└── js
│ └── manual-concat-file.js
├── bower.json
├── language
├── english
│ ├── MYMODULE_lang.php
│ └── index.html
└── index.html
├── .idea
├── inspectionProfiles
│ └── profiles_settings.xml
├── PerfexCRM-Module-Boilerplate.iml
└── modules.xml
├── index.html
├── views
├── index.html
└── module-view.php
├── examples
├── index.html
└── KitchenSink.php
├── helpers
└── index.html
├── libraries
└── index.html
├── models
└── index.html
├── controllers
└── index.html
├── composer.json
├── webpack.config.js
├── package.json
├── PerfexCRM-Module-Boilerplate.php
├── .gitignore
├── README.md
└── GruntFile.js
/dist/js.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dist/js.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/style/main.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/js/manual-concat-file.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dist/style.min.css:
--------------------------------------------------------------------------------
1 | body{background:#00f}
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "perfex-crm-module-boilerplate"
3 | }
--------------------------------------------------------------------------------
/dist/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue; }
3 |
4 | /*# sourceMappingURL=style.css.map */
--------------------------------------------------------------------------------
/language/english/MYMODULE_lang.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/helpers/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/language/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/libraries/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/models/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/controllers/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/dist/style.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "file": "style.css",
4 | "sources": [
5 | "../assets/style/main.scss"
6 | ],
7 | "names": [],
8 | "mappings": "AAAA,AAAA,IAAI,CAAC;EACH,UAAU,EAAE,IAAI,GACjB"
9 | }
--------------------------------------------------------------------------------
/language/english/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403 Forbidden
5 |
6 |
7 |
8 | Directory access is forbidden.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lunardevelopment/perfex-crm-module-boilerplate",
3 | "authors": [
4 | {
5 | "name": "LunarDevelopment",
6 | "email": "development.lunar@gmail.com"
7 | }
8 | ],
9 | "require": {}
10 | }
11 |
--------------------------------------------------------------------------------
/views/module-view.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/PerfexCRM-Module-Boilerplate.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019.
3 | *
4 | */
5 |
6 | const path = require('path');
7 |
8 | module.exports = {
9 | entry: './src/js/index.js',
10 | output: {
11 | filename: 'js/main.min.js',
12 | path: path.resolve(__dirname, 'assets')
13 | },
14 | module: {
15 | rules: [{
16 | test: /\.scss$/,
17 | use: [
18 | "style-loader", // creates style nodes from JS strings
19 | "css-loader", // translates CSS into CommonJS
20 | "sass-loader" // compiles Sass to CSS, using Node Sass by default
21 | ]
22 | }]
23 | }
24 | };
25 |
26 |
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PerfexCRM-Module-Boilerplate",
3 | "version": "1.0.0",
4 | "description": "A Module Boilerplate for PerfexCRM",
5 | "main": "index.js",
6 | "directories": {
7 | "example": "examples"
8 | },
9 | "scripts": {
10 | "start": "node ./bin/www"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/LunarDevelopment/PerfexCRM-Module-Boilerplate.git"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/LunarDevelopment/PerfexCRM-Module-Boilerplate/issues"
21 | },
22 | "homepage": "https://github.com/LunarDevelopment/PerfexCRM-Module-Boilerplate#readme",
23 | "devDependencies": {
24 | "autoprefixer": "^7.1.1",
25 | "grunt": "^1.3.0",
26 | "grunt-concurrent": "^2.3.1",
27 | "grunt-contrib-concat": "^1.0.1",
28 | "grunt-contrib-cssmin": "^2.0.0",
29 | "grunt-contrib-imagemin": "^1.0.1",
30 | "grunt-contrib-uglify": "^2.2.0",
31 | "grunt-contrib-watch": "^1.0.0",
32 | "grunt-pagespeed": "^2.0.1",
33 | "grunt-postcss": "^0.8.0",
34 | "grunt-sass": "^2.0.0",
35 | "imagemin-mozjpeg": "^5.1.0",
36 | "load-grunt-tasks": "^3.5.2",
37 | "pixrem": "^3.0.2",
38 | "time-grunt": "^1.4.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/PerfexCRM-Module-Boilerplate.php:
--------------------------------------------------------------------------------
1 | input->post();
48 | $client_id = $this->input->post('client_id');
49 |
50 | // Get data from GET request
51 |
52 | $data = $this->input->get();
53 | $client_id = $this->input->get('client_id');
54 |
55 |
56 | function example_database_function($data)
57 | {
58 | $CI = &get_instance();
59 | $CI->db->where('id', $data['id']);
60 | $CI->db->update(db_prefix() . 'table_name', [
61 | 'column' => $data['key'],
62 | ]);
63 | }
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | ### macOS template
3 | # General
4 | .DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | # Files that might appear in the root of a volume
15 | .DocumentRevisions-V100
16 | .fseventsd
17 | .Spotlight-V100
18 | .TemporaryItems
19 | .Trashes
20 | .VolumeIcon.icns
21 | .com.apple.timemachine.donotpresent
22 |
23 | # Directories potentially created on remote AFP share
24 | .AppleDB
25 | .AppleDesktop
26 | Network Trash Folder
27 | Temporary Items
28 | .apdisk
29 | ### JetBrains template
30 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
31 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
32 |
33 | # User-specific stuff:
34 | .idea/**/workspace.xml
35 | .idea/**/tasks.xml
36 | .idea/dictionaries
37 |
38 | # Sensitive or high-churn files:
39 | .idea/**/dataSources/
40 | .idea/**/dataSources.ids
41 | .idea/**/dataSources.xml
42 | .idea/**/dataSources.local.xml
43 | .idea/**/sqlDataSources.xml
44 | .idea/**/dynamic.xml
45 | .idea/**/uiDesigner.xml
46 |
47 | # Gradle:
48 | .idea/**/gradle.xml
49 | .idea/**/libraries
50 |
51 | # CMake
52 | cmake-build-debug/
53 |
54 | # Mongo Explorer plugin:
55 | .idea/**/mongoSettings.xml
56 |
57 | ## File-based project format:
58 | *.iws
59 |
60 | ## Plugin-specific files:
61 |
62 | # IntelliJ
63 | out/
64 |
65 | # mpeltonen/sbt-idea plugin
66 | .idea_modules/
67 |
68 | # JIRA plugin
69 | atlassian-ide-plugin.xml
70 |
71 | # Cursive Clojure plugin
72 | .idea/replstate.xml
73 |
74 | # Crashlytics plugin (for Android Studio and IntelliJ)
75 | com_crashlytics_export_strings.xml
76 | crashlytics.properties
77 | crashlytics-build.properties
78 | fabric.properties
79 |
80 | # Dependencies
81 | node_modules
82 | bower_components
83 | vendor
84 |
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PerfexCRM-Module-Boilerplate
2 | A Module Boilerplate for PerfexCRM
3 |
4 | ## References
5 |
6 | [Introduction to Modules](https://help.perfexcrm.com/introduction-to-perfex-crm-modules/)
7 |
8 | [Module Security](https://help.perfexcrm.com/module-security/)
9 |
10 | [Basics of Modules](https://help.perfexcrm.com/module-basics/)
11 |
12 | ## Need to know
13 |
14 | All modules should be added in the modules folder in your root directory where Perfex CRM is installed and each module must have unique folder name and init file with the same name as your module folder name.
15 |
16 | It’s very important to make sure that your module folder name and the .php file name are the same, otherwise, your module won’t be shown in the modules list.
17 |
18 | This boilerplate uses composer for dependency management and npm with
19 |
20 | ## Getting Started
21 |
22 | You can create a new module with this repo by running the following commands:
23 |
24 | ```bash
25 | # these are system wide and only required as a one off
26 | npm i -g node-sass
27 | npm i -g sassdoc
28 | npm i -g grunt-cli
29 | npm i -g bower
30 |
31 | git clone https://github.com/LunarDevelopment/PerfexCRM-Module-Boilerplate.git MYMODULENAME
32 |
33 | cd MYMODULENAME
34 | mv ./PerfexCRM-Module-Boilerplate.php ./MYMODULENAME.php
35 | mv ./language/english/MYMODULE_lang.php ./language/english/REPLACETHISBIT_lang.php
36 |
37 | npm install
38 | bower install
39 | composer install
40 |
41 | # Not needed but handy to know what bower is installing for you:
42 | # bower install --save-dev jQuery
43 | # bower install --save-dev normalize-css
44 | # bower install --save-dev font-awesome
45 |
46 | # Remember to update the doc block in ./MYMODULENAME.php with the name of your module and a description
47 |
48 | ```
49 |
50 | ## Developing
51 |
52 | "Frontend", so to speak, is handled by grunt tasks - do not edit any files in dist/ but in stead work on your js, scss and place images in the assets/ path which will then be compiled with the below commands, either individually or as a group. It's handy to use the watch command while
53 |
54 | Executes the Sass -> CSS task:
55 |
56 | `grunt css`
57 |
58 | Executes the JS task:
59 |
60 | `grunt js`
61 |
62 | Executes the Image task:
63 |
64 | `grunt image`
65 |
66 | Executes Sass/CSS, JS and Images at once:
67 |
68 | `grunt build`
69 |
70 | File Watcher
71 | A File watcher will run the specified task/s when a file has been changed, you could simply start one with
72 |
73 | `grunt watch css`
74 |
75 | if you just want to let it run when you change a Sass (*.scss) file.
76 |
77 | Or let it watch for everything:
78 |
79 | `grunt watch`
80 |
81 | As all images will be changed everytime, depending on your deployment it could be that you should exclude images from the watchers. Also it could take a lot of time when you got a lot of pictures. So run `grunt image` when you are finished with handling images.
82 |
83 |
84 |
--------------------------------------------------------------------------------
/examples/KitchenSink.php:
--------------------------------------------------------------------------------
1 | load->helper('module_name/helper_name');
14 | $CI->load->library('module_name/library_name');
15 |
16 | /*
17 | * Get data from POST request
18 | */
19 | $data = $this->input->post();
20 | $client_id = $this->input->post('client_id');
21 |
22 | /*
23 | * Get data from GET request
24 | */
25 | $data = $this->input->get();
26 | $client_id = $this->input->get('client_id');
27 |
28 |
29 | /*
30 | * Connect to the database with CI ORM
31 | */
32 | function example_database_function($data)
33 | {
34 | $CI = &get_instance();
35 | $CI->db->where('id', $data['id']);
36 | $CI->db->update(db_prefix() . 'table_name', [
37 | 'column' => $data['key'],
38 | ]);
39 | }
40 |
41 |
42 | /*
43 | * Create a Table
44 | */
45 |
46 | if (!$CI->db->table_exists(db_prefix() . 'new_table')) {
47 | $CI->db->query('CREATE TABLE `' . db_prefix() . "new_table` (
48 | `id` INT(11) NOT NULL,
49 | `subject` VARCHAR(191) NOT NULL,
50 | `description` TEXT NOT NULL,
51 | `start_date` DATE NOT NULL,
52 | `end_date` DATE NOT NULL,
53 | `goal_type` INT(11) NOT NULL,
54 | `contract_type` INT(11) NOT NULL DEFAULT '0',
55 | `achievement` INT(11) NOT NULL,
56 | `notify_when_fail` TINYINT(1) NOT NULL DEFAULT '1',
57 | `notify_when_achieve` TINYINT(1) NOT NULL DEFAULT '1',
58 | `notified` INT(11) NOT NULL DEFAULT '0',
59 | `staff_id` INT(11) NOT NULL DEFAULT '0'
60 | ) ENGINE=InnoDB DEFAULT CHARSET=" . $CI->db->char_set . ';');
61 | }
62 |
63 |
64 | /*
65 | * Options
66 | */
67 |
68 | /**
69 | * Add a module option, the name must be unique amongst all modules.
70 | * @param string $name The name of the option to be added, make sure it’s unique and prefixed with E.q. your module name.
71 | * @param string $value Value to store.
72 | * @param string $autoload if you are using the option a lot in the views then autoload it.
73 | * @return mixed
74 | */
75 | add_option($name, $value, $autoload);
76 | get_option($option_name);
77 | update_option($option_name, $new_value);
78 |
79 |
80 | /*
81 | * Available Hooks
82 | */
83 |
84 | /**
85 | * Register module activation hook
86 | * @param string $module module system name
87 | * @param mixed $function function for the hook
88 | * @return mixed
89 | */
90 |
91 | register_activation_hook($module, $function);
92 |
93 | /**
94 | * Register module deactivation hook
95 | * @param string $module module system name
96 | * @param mixed $function function for the hook
97 | * @return mixed
98 | */
99 |
100 | register_deactivation_hook($module, $function);
101 |
102 | /**
103 | * Register module uninstall hook
104 | * @param string $module module system name
105 | * @param mixed $function function for the hook
106 | * @return mixed
107 | */
108 |
109 | register_uninstall_hook($module, $function);
110 |
111 | /**
112 | * Register module cron task, the cron task is executed after the core cron tasks are finished
113 | * @param mixed $function function/class parameter for the hook
114 | * @return null
115 | */
116 |
117 | register_cron_task($function);
118 |
119 | /**
120 | * Inject custom payment gateway into the payment gateways array
121 | * @param string $idpayment gateway id, should equal like the libraries/classname e.q. gateways/New_gateway
122 | * @param string $module module name to load the gateway if not already loaded
123 | */
124 |
125 | register_payment_gateway($id, $module);
126 |
127 | /**
128 | * Register module language files to support custom_lang.php file
129 | * @param string $module module system name
130 | * @param array $languages array of language file names without the _lang.php
131 | * @return null
132 | */
133 |
134 | register_language_files($module, $languages);
135 |
136 | /**
137 | * Module URL
138 | * e.q. https://crm-installation.com/module_name/
139 | * @param string $module module system name
140 | * @param string $segment additional string to append to the URL
141 | * @return string
142 | */
143 |
144 | module_dir_url($module, $segment = '');
145 |
146 | /**
147 | * Module directory absolute path
148 | * @param string $module module system name
149 | * @param string $concat append additional string to the path
150 | * @return string
151 | */
152 |
153 | module_dir_path($module, $concat = '');
154 |
155 | /**
156 | * Module libraries path
157 | * e.q. modules/module_name/libraries
158 | * @param string $module module name
159 | * @param string $concat append additional string to the path
160 | * @return string
161 | */
162 |
163 | module_libs_path($module, $concat = '');
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/GruntFile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019.
3 | *
4 | */
5 |
6 | module.exports = function(grunt) {
7 | //
8 | // Paths
9 | //
10 |
11 | /**
12 | * with trailing slash
13 | * bower_components/ (mostly)
14 | * @type {string}
15 | */
16 | let path_bower = 'bower_components/';
17 | /**
18 | * with trailing slash
19 | * vendor/ (mostly)
20 | * @type {string}
21 | */
22 | let path_composer = 'vendor/';
23 |
24 | /**
25 | * This folder will be watched and JS concated, mangled, minified
26 | *
27 | * with trailing slash
28 | * @type {string}
29 | */
30 | let path_js_src_dir = 'assets/js/';
31 | /**
32 | * The folder in which the JS output should be saved
33 | *
34 | * with trailing slash
35 | * @type {string}
36 | */
37 | let path_js_build_dir = 'dist/';
38 |
39 | /**
40 | * The main Sass file that should be transpiled, but:
41 | *
42 | * without extension
43 | * @type {string}
44 | */
45 | let path_sass_src_file = 'assets/style/main';
46 | /**
47 | * The folder where most sass files are located, will be used for the CSS file watcher
48 | *
49 | * with trailing slash
50 | * @type {string}
51 | */
52 | let path_sass_src_dir = 'assets/style/';
53 | /**
54 | * The folder in which the CSS should be saved
55 | *
56 | * with trailing slash
57 | * @type {string}
58 | */
59 | let path_sass_build_dir = 'dist/';
60 | /**
61 | * Name of the CSS file, but:
62 | *
63 | * without extension
64 | * @type {string}
65 | */
66 | let path_sass_build_file = 'style';
67 |
68 | /**
69 | * The source image folder, will be watched and all images optimized and copied into path_img_build
70 | *
71 | * with trailing slash
72 | * @type {string}
73 | */
74 | let path_img_src = 'assets/media/';
75 | /**
76 | * The folder in which the optimized images are saved
77 | *
78 | * with trailing slash
79 | * @type {string}
80 | */
81 | let path_img_build = 'dist/media/';
82 |
83 | //
84 | // JS concat
85 | //
86 |
87 | let js_concat = [
88 | path_bower + 'jQuery/dist/jquery.min.js',
89 | path_js_src_dir + '**/*.js'
90 | ];
91 |
92 | //
93 | // Options
94 | //
95 |
96 | /**
97 | * imagemin level of optimization for png and dynamic (svg|gif)
98 | * @type {number}
99 | */
100 | let img_optimization_lvl = 3;
101 | /**
102 | * imagemin level of builded image quality for jpeg and dynamic (svg|gif)
103 | * @type {number}
104 | */
105 | let img_quality_lvl = 90;
106 |
107 | //
108 | // Watcher
109 | //
110 |
111 | /**
112 | * The more files must be scanned the longer it takes, keep the list clean!
113 | * @type {[*]}
114 | */
115 | let watch_css = [
116 | path_sass_src_dir + '**/*.scss',
117 | '!**/node_modules/**',
118 | '!**/*.min.css'
119 | ];
120 | /**
121 | * The more files must be scanned the longer it takes, keep the list clean!
122 | * @type {[*]}
123 | */
124 | let watch_js = [
125 | path_js_src_dir + '**/*.js',
126 | '!**/node_modules/**',
127 | '!**/*.min.js'
128 | ];
129 | /**
130 | * The more files must be scanned the longer it takes, keep the list clean!
131 | * @type {[*]}
132 | */
133 | let watch_img = [
134 | path_img_src + '**/*.{gif,svg,png,jpg}',
135 | ];
136 |
137 | require('time-grunt')(grunt);
138 |
139 | require('load-grunt-tasks')(grunt);
140 |
141 | grunt.initConfig({
142 | pkg: grunt.file.readJSON('package.json'),
143 |
144 | // JS
145 | concat: {
146 | dist: {
147 | // warns when something was not found but was specified
148 | nonull: true,
149 | src: js_concat,
150 | dest: path_js_build_dir + 'js.js'
151 | }
152 | },
153 | uglify: {
154 | build: {
155 | options: {
156 | sourceMap: true,
157 | mangle: {
158 | properties: true,
159 | toplevel: false,
160 | reserved: ['jQuery', 'jquery']
161 | }
162 | },
163 | src: path_js_build_dir + 'js.js',
164 | dest: path_js_build_dir + 'js.min.js'
165 | }
166 | },
167 |
168 | // CSS
169 | sass: {
170 | options: {
171 | sourceMap: true
172 | },
173 | dist: {
174 | files: {
175 | [path_sass_build_dir + path_sass_build_file + '.css']: path_sass_src_file + '.scss'
176 | }
177 | }
178 | },
179 | cssmin: {
180 | target: {
181 | files: [{
182 | expand: true,
183 | cwd: path_sass_build_dir,
184 | src: [path_sass_build_file + '.css', '!' + path_sass_build_file + '.css.map'],
185 | dest: path_sass_build_dir,
186 | ext: '.min.css'
187 | }]
188 | }
189 | },
190 | postcss: {
191 | options: {
192 | map: false,
193 | processors: [
194 | require('pixrem')(), // add fallbacks for rem units
195 | require('autoprefixer')({browsers: 'last 4 versions'})
196 | ]
197 | },
198 | dist: {
199 | src: path_sass_build_dir + path_sass_build_file + '.min.css'
200 | }
201 | },
202 |
203 | // Image
204 | imagemin: {
205 | png: {
206 | options: {
207 | optimizationLevel: img_optimization_lvl
208 | },
209 | files: [{
210 | expand: true,
211 | cwd: path_img_src,
212 | src: ['**/*.png'],
213 | dest: path_img_build
214 | }]
215 | },
216 | jpg: {
217 | options: {
218 | quality: img_quality_lvl,
219 | progressive: true,
220 | use: [require('imagemin-mozjpeg')()]
221 | },
222 | files: [{
223 | expand: true,
224 | cwd: path_img_src,
225 | src: ['**/*.jpg'],
226 | dest: path_img_build
227 | }]
228 | },
229 | dynamic: {
230 | options: {
231 | optimizationLevel: img_optimization_lvl,
232 | quality: img_quality_lvl,
233 | svgoPlugins: [{removeViewBox: false}]
234 | },
235 | files: [{
236 | expand: true,
237 | cwd: path_img_src,
238 | src: ['**/*.{gif,svg}'],
239 | dest: path_img_build
240 | }]
241 | }
242 | },
243 |
244 | // Multi Tasking
245 | concurrent: {
246 | image: ['imagemin:png', 'imagemin:jpg', 'imagemin:dynamic'],
247 | build: [['js'], ['css'], 'concurrent:image']
248 | },
249 |
250 | // JS and CSS/Sass file watcher
251 | watch: {
252 | css: {
253 | files: watch_css,
254 | tasks: ['css']
255 | },
256 | js: {
257 | files: watch_js,
258 | tasks: ['js']
259 | },
260 | image: {
261 | files: watch_img,
262 | tasks: ['image']
263 | }
264 | }
265 | });
266 |
267 | // Multi-Thread Task Runner
268 | grunt.loadNpmTasks('grunt-concurrent');
269 |
270 | // JS
271 | grunt.registerTask('js', ['concat', 'uglify']);
272 |
273 | // SASS
274 | grunt.registerTask('css', ['sass', 'cssmin', 'postcss']);
275 |
276 | // Images
277 | grunt.registerTask('image', ['concurrent:image']);
278 |
279 | // Build All
280 | grunt.registerTask('build', ['concurrent:build']);
281 | };
282 |
--------------------------------------------------------------------------------