4 const csso = require('gulp-csso');
5 const del = require('del');
6 const fs = require('fs');
7 const glob = require('glob');
8 const gap = require('gulp-append-prepend');
9 const replace = require('replace-in-file');
10 const gulp = require('gulp');
11 const argv = require('minimist')(process.argv.slice(2));
12 const gulpif = require('gulp-if');
13 const prefix = require('gulp-autoprefixer');
14 const rename = require('gulp-rename');
15 const sass = require('gulp-sass');
16 const sourcemaps = require('gulp-sourcemaps');
17 const gulp_watch = require('gulp-watch');
20 const packages = require('./package.json');
24 all: [], // must always be empty
26 // Command Line Arguments
31 // Source file locations
34 style_portal: 'interface/themes/patientportal-style.scss',
35 style_uni: 'interface/themes/oe-styles/style_*.scss',
36 style_color: 'interface/themes/colors/*.scss',
37 directional: 'interface/themes/directional.scss'
41 assets: 'public/assets/'
44 themes: 'public/themes'
48 // Clean up lingering static themes
49 function clean(done) {
50 del.sync([config.dest.themes + "/*"]);
54 // Parses command line arguments
55 function ingest(done) {
56 if (config.dev && typeof config.dev !== "boolean") {
62 // definition of header for all compiled css
63 const autoGeneratedHeader = `
64 /*! This style sheet was autogenerated using gulp + scss
65 * For usage instructions, see: https://github.com/openemr/openemr/blob/master/interface/README.md
69 // standard themes css compilation
70 function styles_style_portal() {
71 return gulp.src(config.src.styles.style_portal)
72 .pipe(sourcemaps.init())
73 .pipe(sass().on('error', sass.logError))
74 .pipe(prefix('last 1 version'))
75 .pipe(gap.prependText(autoGeneratedHeader))
76 .pipe(gulpif(!config.dev, csso()))
77 .pipe(gulpif(!config.dev, sourcemaps.write()))
78 .pipe(gulp.dest(config.dest.themes));
80 // standard themes css compilation
81 function styles_style_uni() {
82 return gulp.src(config.src.styles.style_uni)
83 .pipe(sourcemaps.init())
84 .pipe(sass().on('error', sass.logError))
85 .pipe(prefix('last 1 version'))
86 .pipe(gap.prependText(autoGeneratedHeader))
87 .pipe(gulpif(!config.dev, csso()))
88 .pipe(gulpif(!config.dev, sourcemaps.write()))
89 .pipe(gulp.dest(config.dest.themes));
92 // color themes css compilation
93 function styles_style_color() {
94 return gulp.src(config.src.styles.style_color)
95 .pipe(sourcemaps.init())
96 .pipe(sass().on('error', sass.logError))
97 .pipe(prefix('last 1 version'))
98 .pipe(gap.prependText(autoGeneratedHeader))
99 .pipe(gulpif(!config.dev, csso()))
100 .pipe(gulpif(!config.dev, sourcemaps.write()))
101 .pipe(gulp.dest(config.dest.themes));
104 // rtl standard themes css compilation
105 function rtl_style_portal() {
106 return gulp.src(config.src.styles.style_portal)
107 .pipe(gap.prependText('$dir: rtl;\n@import "rtl";\n@import "directional";\n')) // watch out for this relative path!
108 .pipe(gap.appendText('@include if-rtl { @include rtl_style; }\n'))
109 .pipe(sourcemaps.init())
110 .pipe(sass().on('error', sass.logError))
111 .pipe(prefix('last 1 version'))
112 .pipe(gap.prependText(autoGeneratedHeader))
113 .pipe(gulpif(!config.dev, csso()))
114 .pipe(gulpif(!config.dev, sourcemaps.write()))
115 .pipe(rename({ prefix: "rtl_" }))
116 .pipe(gulp.dest(config.dest.themes));
119 // rtl standard themes css compilation
120 function rtl_style_uni() {
121 return gulp.src(config.src.styles.style_uni)
122 .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
123 .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
124 .pipe(sourcemaps.init())
125 .pipe(sass().on('error', sass.logError))
126 .pipe(prefix('last 1 version'))
127 .pipe(gap.prependText(autoGeneratedHeader))
128 .pipe(gulpif(!config.dev, csso()))
129 .pipe(gulpif(!config.dev, sourcemaps.write()))
130 .pipe(rename({ prefix: "rtl_" }))
131 .pipe(gulp.dest(config.dest.themes));
134 // rtl color themes css compilation
135 function rtl_style_color() {
136 return gulp.src(config.src.styles.style_color)
137 .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
138 .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
139 .pipe(sourcemaps.init())
140 .pipe(sass().on('error', sass.logError))
141 .pipe(prefix('last 1 version'))
142 .pipe(gap.prependText(autoGeneratedHeader))
143 .pipe(gulpif(!config.dev, csso()))
144 .pipe(gulpif(!config.dev, sourcemaps.write()))
145 .pipe(rename({ prefix: "rtl_" }))
146 .pipe(gulp.dest(config.dest.themes));
150 const styles = gulp.parallel(styles_style_color, styles_style_uni, styles_style_portal, rtl_style_color, rtl_style_uni, rtl_style_portal);
152 // Copies (and distills, if possible) assets from node_modules to public/assets
153 function install(done) {
154 // combine dependencies and napa sources into one object
155 const dependencies = packages.dependencies;
156 for (let key in packages.napa) {
157 if (packages.napa.hasOwnProperty(key)) {
158 dependencies[key] = packages.napa[key];
162 for (let key in dependencies) {
163 // check if the property/key is defined in the object itself, not in parent
164 if (dependencies.hasOwnProperty(key)) {
166 // dwv is special and need to copy dist, decoders and locales
167 gulp.src('node_modules/' + key + '/dist/**/*')
168 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
169 gulp.src('node_modules/' + key + '/decoders/**/*')
170 .pipe(gulp.dest(config.dist.assets + key + '/decoders'));
171 gulp.src('node_modules/' + key + '/locales/**/*')
172 .pipe(gulp.dest(config.dist.assets + key + '/locales'));
173 } else if (key == 'bootstrap' || key == 'bootstrap-v4-rtl' || key == 'bootswatch') {
174 // bootstrap, bootstrap-v4-rtl, and bootswatch are special and need to copy dist and scss
175 gulp.src('node_modules/' + key + '/dist/**/*')
176 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
177 gulp.src('node_modules/' + key + '/scss/**/*')
178 .pipe(gulp.dest(config.dist.assets + key + '/scss'));
179 } else if (key == '@ttskch/select2-bootstrap4-theme') {
180 // @ttskch/select2-bootstrap4-theme is special and need to copy dist and src
181 // modify src/layout.scss in order for sass build to work by removing:
182 // @import "~bootstrap/scss/functions";
183 // @import "~bootstrap/scss/variables";
184 // @import "~bootstrap/scss/mixins";
185 gulp.src('node_modules/' + key + '/dist/**/*')
186 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
187 gulp.src('node_modules/' + key + '/src/**/*')
188 .pipe(gulp.dest(config.dist.assets + key + '/src'))
189 .on('end', function() {
191 files: config.dist.assets + key + '/src/layout.scss',
194 /@import "~bootstrap\/scss\/functions";/,
195 /@import "~bootstrap\/scss\/variables";/,
196 /@import "~bootstrap\/scss\/mixins";/
201 } else if (fs.existsSync('node_modules/' + key + '/dist')) {
202 // only copy dist directory, if it exists
203 gulp.src('node_modules/' + key + '/dist/**/*')
204 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
207 gulp.src('node_modules/' + key + '/**/*')
208 .pipe(gulp.dest(config.dist.assets + key));
217 // watch all changes and re-run styles
218 gulp.watch('./interface/**/*.scss', { interval: 1000, mode: 'poll' }, styles);
220 // watch all changes to css/php files in themes and copy to public
221 return gulp_watch('./interface/themes/*.{css,php}', { ignoreInitial: false })
222 .pipe(gulp.dest(config.dest.themes));
226 // copy all leftover root-level components to the theme directory
227 // hoping this is only temporary
228 return gulp.src(['interface/themes/*.{css,php}'])
229 .pipe(gulp.dest(config.dest.themes));
233 exports.watch = watch;
235 // Export pertinent default task
236 // - Note that the default task runs if no other task is chosen,
237 // which is generally how this script is always used (except in
238 // rare case where the user is running the watch task).
239 if (config.install) {
240 exports.default = gulp.series(install)
242 exports.default = gulp.series(clean, ingest, styles, sync);