diff --git a/.gitignore b/.gitignore index 0dd8973c6..85f393a34 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .start.pid node_modules govuk_modules +lib/govuk_template.html # Ignore compiled stylesheets public/stylesheets/ diff --git a/Gruntfile.js b/Gruntfile.js index 8c50ce4a1..1a4148efb 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -46,11 +46,19 @@ module.exports = function (grunt) { }, { expand: true, - cwd: 'node_modules/govuk_template_mustache/', + cwd: 'node_modules/govuk_template_jinja/', src: '**', dest: 'govuk_modules/govuk_template/' }] }, + govuk_template_jinja: { + files: [{ + expand: true, + cwd: 'govuk_modules/govuk_template/views/layouts/', + src: '**', + dest: 'lib/' + }] + }, }, // workaround for libsass @@ -110,28 +118,14 @@ module.exports = function (grunt) { 'grunt-contrib-watch', 'grunt-sass', 'grunt-nodemon', - 'grunt-text-replace', 'grunt-concurrent', 'grunt-shell' ].forEach(function (task) { grunt.loadNpmTasks(task); }); - grunt.registerTask( - 'convert_template', - 'Converts the govuk_template to use mustache inheritance', - function () { - var script = require(__dirname + '/lib/template-conversion.js'); - - script.convert(); - grunt.log.writeln('govuk_template converted'); - } - ); - grunt.registerTask('default', [ 'copy', - 'convert_template', - 'replace', 'sass', 'concurrent:target' ]); @@ -141,8 +135,6 @@ module.exports = function (grunt) { 'Test that the default task runs the app', [ 'copy', - 'convert_template', - 'replace', 'sass' ] ); @@ -155,7 +147,7 @@ module.exports = function (grunt) { } ); - grunt.registerTask( + grunt.registerTask( 'lint_message', 'Output a message once linting is complete', function() { diff --git a/app/routes.js b/app/routes.js index 9f9a0b276..39cdff942 100755 --- a/app/routes.js +++ b/app/routes.js @@ -1,8 +1,8 @@ module.exports = { - bind : function (app, assetPath) { + bind : function (app, asset_path) { app.get('/', function (req, res) { - res.render('index', {'assetPath' : assetPath }); + res.render('index', {'asset_path' : asset_path }); }); // Redirect snippets page to the index page diff --git a/app/views/examples/example_date.html b/app/views/examples/example_date.html index b40c3ecc2..2d0d51495 100644 --- a/app/views/examples/example_date.html +++ b/app/views/examples/example_date.html @@ -1,11 +1,11 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
@@ -15,12 +15,10 @@

Example: Date

- {{> form_date }} + {% include "snippets/form_date.html" %}
-{{/content}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_details_summary.html b/app/views/examples/example_details_summary.html index ef3b7eabc..ef50e35c3 100644 --- a/app/views/examples/example_details_summary.html +++ b/app/views/examples/example_details_summary.html @@ -1,11 +1,11 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
@@ -87,6 +87,4 @@

Example 3: Summary content is visible, details conten

-{{/content}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_form_elements.html b/app/views/examples/example_form_elements.html index 594e385c1..1e9c3abc7 100644 --- a/app/views/examples/example_form_elements.html +++ b/app/views/examples/example_form_elements.html @@ -1,11 +1,11 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
@@ -501,37 +501,35 @@

These examples are one-question-per-page examples and use a heading for the question, with a visually hidden legend inside a fieldset.

- {{> form_radio_buttons }} + {% include "snippets/form_radio_buttons.html" %}
- {{> form_checkboxes }} + {% include "snippets/form_checkboxes.html" %}
- {{> form_radio_buttons_inline }} + {% include "snippets/form_radio_buttons_inline.html" %}
- {{> form_radio_inline_yes_no }} + {% include "snippets/form_radio_inline_yes_no.html" %}
- {{> form_inset_radios }} + {% include "snippets/form_inset_radios.html" %}
- {{> form_inset_checkboxes }} + {% include "snippets/form_inset_checkboxes.html" %}
-{{/content}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_form_validation_multiple_questions.html b/app/views/examples/example_form_validation_multiple_questions.html index fbc51aeab..a336a40d8 100644 --- a/app/views/examples/example_form_validation_multiple_questions.html +++ b/app/views/examples/example_form_validation_multiple_questions.html @@ -1,17 +1,17 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
- {{> form_error_multiple }} + {% include "snippets/form_error_multiple.html" %}

Implementation advice

@@ -65,6 +65,4 @@

Implementation advice

-{{/content}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_form_validation_single_question_radio.html b/app/views/examples/example_form_validation_single_question_radio.html index 18704fa2c..4437a2c57 100644 --- a/app/views/examples/example_form_validation_single_question_radio.html +++ b/app/views/examples/example_form_validation_single_question_radio.html @@ -1,17 +1,17 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
- {{> form_error_radio }} + {% include "snippets/form_error_radio.html" %}

Implementation advice

@@ -71,6 +71,4 @@

Implementation advice

-{{/content}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_grid_layout.html b/app/views/examples/example_grid_layout.html index b476fce7e..587bebeee 100644 --- a/app/views/examples/example_grid_layout.html +++ b/app/views/examples/example_grid_layout.html @@ -1,11 +1,11 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %}
@@ -128,10 +128,10 @@

One quarter

-{{/content}} +{% endblock %} -{{$bodyEnd}} - {{>scripts}} +{% block body_end %} + {% include "includes/scripts.html" %} -{{/bodyEnd}} - -{{/layout_example}} +{% endblock %} diff --git a/app/views/examples/example_icons.html b/app/views/examples/example_icons.html index c5ca5f2df..ca3754082 100644 --- a/app/views/examples/example_icons.html +++ b/app/views/examples/example_icons.html @@ -1,11 +1,11 @@ -{{ - {{>breadcrumb}} + {% include "includes/breadcrumb.html" %} - {{>elements_tracking}} -{{/head}} + {% include "includes/elements_tracking.html" %} +{% endblock %} -{{$propositionHeader}} - {{>service_manual_navigation}} -{{/propositionHeader}} +{% block proposition_header %} + {% include "includes/service_manual_navigation.html" %} +{% endblock %} -{{$headerClass}}with-proposition{{/headerClass}} +{% block header_class %} + with-proposition +{% endblock %} -{{$bodyEnd}} - {{>scripts}} -{{/bodyEnd}} - -{{/govuk_template}} +{% block body_end %} + {% include "includes/scripts.html" %} +{% endblock %} diff --git a/app/views/snippets/form_error_multiple.html b/app/views/snippets/form_error_multiple.html index ef1d1161b..e5ff05717 100644 --- a/app/views/snippets/form_error_multiple.html +++ b/app/views/snippets/form_error_multiple.html @@ -1,4 +1,4 @@ -{{#error}} +{% if error %}

@@ -10,41 +10,41 @@

-{{/error}} +{% endif %}

Your personal details

-
+
-
-
+
-
diff --git a/app/views/snippets/form_error_radio.html b/app/views/snippets/form_error_radio.html index f030f2715..72b02affc 100644 --- a/app/views/snippets/form_error_radio.html +++ b/app/views/snippets/form_error_radio.html @@ -1,4 +1,4 @@ -{{#error}} +{% if error %}

@@ -14,7 +14,7 @@

-{{/error}} +{% endif %}

Check your personal details @@ -25,19 +25,19 @@

-
+
- + Are your personal details correct and up-to-date? - {{#error}} + {% if error %} Error message about personal details goes here - {{/error}} + {% endif %} diff --git a/lib/template-config.js b/lib/template-config.js deleted file mode 100755 index 9d2562a83..000000000 --- a/lib/template-config.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - assetPath: "{{assetPath}}", - afterHeader: "{{$afterHeader}}{{/afterHeader}}", - bodyClasses: "{{$bodyClasses}}{{/bodyClasses}}", - bodyEnd: "{{$bodyEnd}}{{/bodyEnd}}", - content: "{{$content}}{{/content}}", - cookieMessage: "{{$cookieMessage}}

GOV.UK uses cookies to make the site simpler. Find out more about cookies

{{/cookieMessage}}", - crownCopyrightMessage: "{{$crownCopyrightMessage}}© Crown copyright{{/crownCopyrightMessage}}", - footerSupportLinks: "{{$footerSupportLinks}}{{/footerSupportLinks}}", - footerTop: "{{$footerTop}}{{/footerTop}}", - globalHeaderText: "{{$globalHeaderText}}GOV.UK{{/globalHeaderText}}", - head: "{{$head}}{{/head}}", - headerClass: "{{$headerClass}}{{/headerClass}}", - homepageUrl: "{{$homepageUrl}}https://www.gov.uk{{/homepageUrl}}", - insideHeader: "{{$insideHeader}}{{/insideHeader}}", - licenceMessage: "{{$licenceMessage}}

All content is available under the Open Government Licence v3.0, except where otherwise stated

{{/licenceMessage}}", - logoLinkTitle: "{{$logoLinkTitle}}Go to the GOV.UK homepage{{/logoLinkTitle}}", - pageTitle: "{{$pageTitle}}GOV.UK - The best place to find government services and information{{/pageTitle}}", - propositionHeader: "{{$propositionHeader}}{{/propositionHeader}}", - skipLinkMessage: "{{$skipLinkMessage}}Skip to main content{{/skipLinkMessage}}" -}; diff --git a/lib/template-conversion.js b/lib/template-conversion.js deleted file mode 100755 index 186f42999..000000000 --- a/lib/template-conversion.js +++ /dev/null @@ -1,22 +0,0 @@ -var Hogan = require('hogan.js'), - fs = require('fs'), - path = require('path'), - govukDir = path.normalize(__dirname + '/../govuk_modules/'), - govukConfig = require(__dirname + '/template-config'), - compiledTemplate, - govukTemplate, - handleErr; - -handleErr = function (err) { - if (err) { - throw err; - } -}; - -module.exports = { - convert : function () { - govukTemplate = fs.readFileSync(govukDir + '/govuk_template/views/layouts/govuk_template.html', { encoding : 'utf-8' }); - compiledTemplate = Hogan.compile(govukTemplate); - fs.writeFileSync(govukDir + '/govuk_template/views/layouts/govuk_template.html', compiledTemplate.render(govukConfig), { encoding : 'utf-8' }); - } -}; diff --git a/lib/template-engine.js b/lib/template-engine.js deleted file mode 100755 index 72e2aedea..000000000 --- a/lib/template-engine.js +++ /dev/null @@ -1,73 +0,0 @@ - -var Hogan = require('hogan.js'); -var ReadDir = require('readdir'); -var Path = require('path'); -var FS = require('fs'); - -function TemplateEngine() { -} - -/** - * All active directory file system watches - * @type {fs.FSWatcher[]} - * @ignore - */ -TemplateEngine._watches = []; - -/** - * Called by the express server to get the content for a given template at the templatePath supplied. The templateData - * can contain any content from a configured route, and will be made available to the templates. - * - * Templates can include partials by name for any template also in the views directory, note that if sub-directories are - * used to create included partials, express will not necessarily recognise that file as a valid view path... you've been - * warned. - * - * @param {String} templatePath Path to the template - * @param {Object} templateData Data to give to the template - * @param {Function} next Callback to receive two arguments, an error object and the template result. - */ -TemplateEngine.__express = function(templatePath, templateData, next) { - var templateName = Path.basename(templatePath, Path.extname(templatePath)); - var templates = TemplateEngine._getTemplates([templateData.settings.views, templateData.settings.vendorViews]); - var output = null, error = null; - - try { - output = templates[templateName].render(templateData, templates); - } - catch (e) { - error = e; - } - finally { - next(error, output); - } -}; - -/** - * Stores an individual template based on the supplied path, the name of the template is the file's basename without - * the extension. - * - * @param {String} templatePath - */ -TemplateEngine._storeTemplate = function(templatePath) { - var templateName = Path.basename(templatePath, Path.extname(templatePath)); - TemplateEngine.__templates[templateName] = Hogan.compile(FS.readFileSync(templatePath, 'utf-8')); - - console.log('Stored template', templateName); -}; - -/** - * Gets all templates, when the template path hasn't yet been scanned it will be read synchronously to ensure there are - * always templates available. - * - * @param {Array} templatePaths - */ -TemplateEngine._getTemplates = function(templatePaths) { - TemplateEngine.__templates = {}; - for (var i = 0, j = templatePaths.length; i < j; i++) { - ReadDir.readSync(templatePaths[i], ['**.html'], ReadDir.ABSOLUTE_PATHS) - .forEach(TemplateEngine._storeTemplate, TemplateEngine); - } - return TemplateEngine.__templates; -}; - -module.exports = TemplateEngine; diff --git a/package.json b/package.json index 0a616c3c7..7dc49fab9 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,9 @@ "body-parser": "^1.14.1", "consolidate": "^0.10.0", "express": "4.13.3", + "express-nunjucks": "^0.9.3", "express-writer": "0.0.4", - "govuk_template_mustache": "^0.17.2", + "govuk_template_jinja": "https://github.com/alphagov/govuk_template/releases/download/v0.17.3/jinja_govuk_template-0.17.3.tgz", "grunt": "^0.4.2", "grunt-cli": "0.1.13", "grunt-concurrent": "^0.4.3", @@ -25,8 +26,6 @@ "grunt-nodemon": "^0.3.0", "grunt-sass": "^1.0.0", "grunt-shell": "^1.3.0", - "grunt-text-replace": "^0.3.12", - "hogan.js": "3.0.2", "node-sass": "^3.2.0", "readdir": "0.0.6" }, diff --git a/server.js b/server.js index 022ff225f..2a89881f7 100755 --- a/server.js +++ b/server.js @@ -1,14 +1,20 @@ -var express = require('express'), - bodyParser = require('body-parser'), +var bodyParser = require('body-parser'), + express = require('express'), + nunjucks = require('express-nunjucks'), + path = require('path'), routes = require(__dirname + '/app/routes.js'), app = express(), port = (process.env.PORT || 3000); // Application settings -app.engine('html', require(__dirname + '/lib/template-engine.js').__express); app.set('view engine', 'html'); -app.set('vendorViews', __dirname + '/govuk_modules/govuk_template/views/layouts'); -app.set('views', __dirname + '/app/views'); +app.set('views', [__dirname + '/app/views', __dirname + '/lib/']); + +nunjucks.setup({ + autoescape: true, + watch: true, + noCache: true +}, app); // Middleware to serve static assets app.use('/public', express.static(__dirname + '/public')); @@ -24,7 +30,7 @@ app.use(bodyParser.urlencoded({ // send assetPath to all views app.use(function (req, res, next) { - res.locals.assetPath="/public/"; + res.locals.asset_path="/public/"; next(); });