'use strict'; const gulp = require('gulp'); const fs = require('fs'); const pkg = require('./package.json'); const iopackage = require('./io-package.json'); const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version; const uglify = require('gulp-uglify'); const concat = require('gulp-concat'); const sourcemaps = require('gulp-sourcemaps'); const gutil = require('gulp-util'); const htmlmin = require('gulp-htmlmin'); const del = require('del'); /*var appName = getAppName(); function getAppName() { var parts = __dirname.replace(/\\/g, '/').split('/'); return parts[parts.length - 1].split('.')[0].toLowerCase(); } */ const fileName = 'words.js'; let languages = { en: {}, de: {}, ru: {}, pt: {}, nl: {}, fr: {}, it: {}, es: {}, pl: {} }; function lang2data(lang, isFlat) { let str = isFlat ? '' : '{\n'; let count = 0; for (const w in lang) { if (lang.hasOwnProperty(w)) { count++; if (isFlat) { str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n'; } else { const key = ' "' + w.replace(/"/g, '\\"') + '": '; str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n'; } } } if (!count) return isFlat ? '' : '{\n}'; if (isFlat) { return str; } else { return str.substring(0, str.length - 2) + '\n}'; } } function readWordJs(src) { try { let words; if (fs.existsSync(src + 'js/' + fileName)) { words = fs.readFileSync(src + 'js/' + fileName).toString(); } else { words = fs.readFileSync(src + fileName).toString(); } const lines = words.split(/\r\n|\r|\n/g); let i = 0; while (!lines[i].match(/^systemDictionary = {/)) { i++; } lines.splice(0, i); // remove last empty lines i = lines.length - 1; while (!lines[i]) { i--; } if (i < lines.length - 1) { lines.splice(i + 1); } lines[0] = lines[0].replace('systemDictionary = ', ''); lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}'); words = lines.join('\n'); const resultFunc = new Function('return ' + words + ';'); return resultFunc(); } catch (e) { return null; } } function padRight(text, totalLength) { return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : ''); } function writeWordJs(data, src) { let text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n'; text += '/*global systemDictionary:true */\n'; text += '\'use strict\';\n\n'; text += 'systemDictionary = {\n'; for (const word in data) { if (data.hasOwnProperty(word)) { text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50); let line = ''; for (const lang in data[word]) { if (data[word].hasOwnProperty(lang)) { line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' '; } } if (line) { line = line.trim(); line = line.substring(0, line.length - 1); } text += line + '},\n'; } } text += '};'; if (fs.existsSync(src + 'js/')) { fs.writeFileSync(src + 'js/' + fileName, text); } else { fs.writeFileSync(src + '' + fileName, text); } } const EMPTY = ''; function words2languages(src) { const langs = Object.assign({}, languages); const data = readWordJs(src); if (data) { for (const word in data) { if (data.hasOwnProperty(word)) { for (const lang in data[word]) { if (data[word].hasOwnProperty(lang)) { langs[lang][word] = data[word][lang]; // pre-fill all other languages for (const j in langs) { if (langs.hasOwnProperty(j)) { langs[j][word] = langs[j][word] || EMPTY; } } } } } } if (!fs.existsSync(src + 'i18n/')) { fs.mkdirSync(src + 'i18n/'); } for (const l in langs) { if (!langs.hasOwnProperty(l)) continue; const keys = Object.keys(langs[l]); //keys.sort(); let obj = {}; for (let k = 0; k < keys.length; k++) { obj[keys[k]] = langs[l][keys[k]]; } if (!fs.existsSync(src + 'i18n/' + l)) { fs.mkdirSync(src + 'i18n/' + l); } fs.writeFileSync(src + 'i18n/' + l + '/translations.json', lang2data(obj)); } } else { console.error('Cannot read or parse ' + fileName); } } function words2languagesFlat(src) { const langs = Object.assign({}, languages); const data = readWordJs(src); if (data) { for (const word in data) { if (data.hasOwnProperty(word)) { for (const lang in data[word]) { if (data[word].hasOwnProperty(lang)) { langs[lang][word] = data[word][lang]; // pre-fill all other languages for (const j in langs) { if (langs.hasOwnProperty(j)) { langs[j][word] = langs[j][word] || EMPTY; } } } } } } const keys = Object.keys(langs.en); //keys.sort(); for (const l in langs) { if (!langs.hasOwnProperty(l)) continue; let obj = {}; for (let k = 0; k < keys.length; k++) { obj[keys[k]] = langs[l][keys[k]]; } langs[l] = obj; } if (!fs.existsSync(src + 'i18n/')) { fs.mkdirSync(src + 'i18n/'); } for (const ll in langs) { if (!langs.hasOwnProperty(ll)) continue; if (!fs.existsSync(src + 'i18n/' + ll)) { fs.mkdirSync(src + 'i18n/' + ll); } fs.writeFileSync(src + 'i18n/' + ll + '/flat.txt', lang2data(langs[ll], langs.en)); } fs.writeFileSync(src + 'i18n/flat.txt', keys.join('\n')); } else { console.error('Cannot read or parse ' + fileName); } } function languagesFlat2words(src) { const dirs = fs.readdirSync(src + 'i18n/'); let langs = {}; let bigOne = {}; const order = Object.keys(languages); dirs.sort((a, b) => { const posA = order.indexOf(a); const posB = order.indexOf(b); if (posA === -1 && posB === -1) { if (a > b) return 1; if (a < b) return -1; return 0; } else if (posA === -1) { return -1; } else if (posB === -1) { return 1; } else { if (posA > posB) return 1; if (posA < posB) return -1; return 0; } }); const keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n'); for (let l = 0; l < dirs.length; l++) { if (dirs[l] === 'flat.txt') continue; const lang = dirs[l]; const values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n'); langs[lang] = {}; keys.forEach(function (word, i) { langs[lang][word] = values[i].replace(/<\/ i>/g, '').replace(/<\/ b>/g, '').replace(/<\/ span>/g, '').replace(/% s/g, ' %s'); }); const words = langs[lang]; for (const word in words) { if (words.hasOwnProperty(word)) { bigOne[word] = bigOne[word] || {}; if (words[word] !== EMPTY) { bigOne[word][lang] = words[word]; } } } } // read actual words.js const aWords = readWordJs(); const temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt']; if (aWords) { // Merge words together for (const w in aWords) { if (aWords.hasOwnProperty(w)) { if (!bigOne[w]) { console.warn('Take from actual words.js: ' + w); bigOne[w] = aWords[w] } dirs.forEach(function (lang) { if (temporaryIgnore.indexOf(lang) !== -1) return; if (!bigOne[w][lang]) { console.warn('Missing "' + lang + '": ' + w); } }); } } } writeWordJs(bigOne, src); } function languages2words(src) { const dirs = fs.readdirSync(src + 'i18n/'); const langs = {}; const bigOne = {}; const order = Object.keys(languages); dirs.sort((a, b) => { const posA = order.indexOf(a); const posB = order.indexOf(b); if (posA === -1 && posB === -1) { if (a > b) return 1; if (a < b) return -1; return 0; } else if (posA === -1) { return -1; } else if (posB === -1) { return 1; } else { if (posA > posB) return 1; if (posA < posB) return -1; return 0; } }); for (let l = 0; l < dirs.length; l++) { if (dirs[l] === 'flat.txt') continue; const lang = dirs[l]; langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString(); langs[lang] = JSON.parse(langs[lang]); const words = langs[lang]; for (const word in words) { if (words.hasOwnProperty(word)) { bigOne[word] = bigOne[word] || {}; if (words[word] !== EMPTY) { bigOne[word][lang] = words[word]; } } } } // read actual words.js const aWords = readWordJs(); const temporaryIgnore = ['pt', 'fr', 'nl', 'it']; if (aWords) { // Merge words together for (const w in aWords) { if (aWords.hasOwnProperty(w)) { if (!bigOne[w]) { console.warn('Take from actual words.js: ' + w); bigOne[w] = aWords[w] } dirs.forEach(function (lang) { if (temporaryIgnore.indexOf(lang) !== -1) return; if (!bigOne[w][lang]) { console.warn('Missing "' + lang + '": ' + w); } }); } } } writeWordJs(bigOne, src); } gulp.task('words2languages', done => { words2languages('./src/'); done(); }); gulp.task('words2languagesFlat', done => { words2languagesFlat('./src/'); done(); }); gulp.task('languagesFlat2words', done => { languagesFlat2words('./src/'); done(); }); gulp.task('languages2words', done => { languages2words('./src/'); done(); }); gulp.task('updateEditHtml', done => { let text = fs.readFileSync('./src/edit.html').toString('utf-8'); let newText = text.replace(/Version: \d+\.\d+\.\d+<\/div>/, `Version: ${pkg.version}`); if (newText !== text) { fs.writeFileSync('./src/edit.html', newText); } done(); }); gulp.task('updatePackages', done => { iopackage.common.version = pkg.version; iopackage.common.news = iopackage.common.news || {}; if (!iopackage.common.news[pkg.version]) { const news = iopackage.common.news; const newNews = {}; newNews[pkg.version] = { en: 'news', de: 'neues', ru: 'новое' }; iopackage.common.news = Object.assign(newNews, news); } fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4)); done(); }); gulp.task('updateReadme', done => { const readme = fs.readFileSync('README.md').toString(); const pos = readme.indexOf('## Changelog\n'); if (pos !== -1) { const readmeStart = readme.substring(0, pos + '## Changelog\n'.length); const readmeEnd = readme.substring(pos + '## Changelog\n'.length); if (readme.indexOf(version) === -1) { const timestamp = new Date(); const date = timestamp.getFullYear() + '-' + ('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' + ('0' + (timestamp.getDate()).toString(10)).slice(-2); let news = ''; if (iopackage.common.news && iopackage.common.news[pkg.version]) { news += '* ' + iopackage.common.news[pkg.version].en; } fs.writeFileSync('README.md', readmeStart + '### ' + version + ' (' + date + ')\n' + (news ? news + '\n\n' : '\n') + readmeEnd); } } done(); }); gulp.task('clean', () => { return del([ 'src/js/words.js', 'www/**/*' ]); }); gulp.task('flotJS', () => { return gulp.src([ './src/lib/js/jquery.flot.min.js', './src/lib/js/jquery.flot.resize.min.js', './src/lib/js/jquery.flot.time.min.js', './src/lib/js/jquery.flot.categories.min.js', './src/lib/js/jquery.flot.spline.min.js', './src/lib/js/jquery.flot.selection.min.js', './src/lib/js/jquery.flot.hiddengraphs.js', './src/lib/js/jquery.flot.fillbetween.js', './src/lib/js/jquery.flot.navigate.min.js', './src/lib/js/jquery.flot.dashes.js', './src/lib/js/jquery.flot.grow.js', './src/lib/js/jquery-deparam.js', './src/js/days.js', './src/js/chart.js', './src/js/data.js' ]) .pipe(sourcemaps.init()) .pipe(concat('flot.js')) .pipe(uglify()) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('./www/js')); }); gulp.task('editJS', ['languages2words'], () => { return gulp.src([ './src/lib/js/jquery-deparam.js', './src/lib/js/jquery.colorpicker.js', './src/js/words.js', './src/js/settings.js', './src/js/edit.js', ]) .pipe(sourcemaps.init()) .pipe(concat('edit.js')) .pipe(uglify()) .on('error', function (err) { gutil.log(gutil.colors.red('[Error]'), err.toString()); }) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('./www/js')); }); gulp.task('indexHTML', () => { return gulp.src([ './src/index.html' ]) .pipe(sourcemaps.init()) .pipe(concat('index.html')) .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('./www/')); }); gulp.task('editHTML', ['updateEditHtml'], () => { return gulp.src([ './src/edit.html' ]) .pipe(sourcemaps.init()) .pipe(concat('edit.html')) .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('./www/')); }); gulp.task('copyCSS', () => { return gulp.src([ './src/lib/css/**/*' ]) .pipe(gulp.dest('./www/css')); }); gulp.task('copyImg', () => { return gulp.src([ './src/img/favicon.png' ]) .pipe(gulp.dest('./www/img')); }); gulp.task('default', ['flotJS', 'editJS', 'indexHTML', 'editHTML', 'copyCSS', 'copyImg']);