From abe565eb0163e8982c58c7bfb859e65556d67b17 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 12 Feb 2016 08:33:04 +1300 Subject: [PATCH] JS build tooling fixes - Relaxed NodeJS dependency to 4.x - Switch to NPM "dependencies" (rather than dev) Provides consistency with framework, where these had previously been broken out between "dependencies" and "devDependencies", which in turn caused issues with "npm shrinkwrap" - Add npm-shrinkwrap.json: Consistent with framework approach Using uber's wrapper library since it prevents npm shrinkwrap from failing on file generation, as well as actually suceeding with an "npm install" once the file is present. - Don't add comments to dist files via babelify We've had some issues with different dependencies causing different results based on the environment, which in turn causes unnecessary diffs - making our work harder to review. Comments can be read through the ES6 source files, and through source maps when generated through `npm run build --development` - Make JS build tooling and naming consistent with framework --- .gitignore | 3 +- code/controllers/CMSMain.php | 2 +- gulpfile.js | 59 +- javascript/dist/AssetAdmin.js | 55 +- javascript/dist/CMSMain.AddForm.js | 36 +- javascript/dist/CMSMain.EditForm.js | 176 +-- javascript/dist/CMSMain.Tree.js | 19 +- javascript/dist/CMSMain.js | 29 - javascript/dist/CMSPageHistoryController.js | 69 +- javascript/dist/SiteTreeURLSegmentField.js | 30 +- .../dist/{bundle-lib.js => bundle-legacy.js} | 3 +- javascript/src/bundles/{lib.js => legacy.js} | 0 npm-shrinkwrap.json | 1372 +++++++++++------ package.json | 7 +- 14 files changed, 956 insertions(+), 904 deletions(-) rename javascript/dist/{bundle-lib.js => bundle-legacy.js} (83%) rename javascript/src/bundles/{lib.js => legacy.js} (100%) diff --git a/.gitignore b/.gitignore index 8a9c5dfa..0421b1fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .sass-cache .DS_Store -node_modules \ No newline at end of file +node_modules +/**/*.js.map diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index f9d038cc..f201ba73 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -69,7 +69,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr Requirements::css(CMS_DIR . '/css/screen.css'); Requirements::customCSS($this->generatePageIconsCss()); Requirements::add_i18n_javascript(CMS_DIR . '/javascript/lang', false, true); - Requirements::javascript(CMS_DIR . '/javascript/dist/bundle-lib.js', [ + Requirements::javascript(CMS_DIR . '/javascript/dist/bundle-legacy.js', [ 'provides' => [ CMS_DIR . '/javascript/dist/CMSMain.AddForm.js', CMS_DIR . '/javascript/dist/CMSMain.EditForm.js', diff --git a/gulpfile.js b/gulpfile.js index 2fde3ee1..54c53833 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,6 +4,7 @@ var gulp = require('gulp'), notify = require('gulp-notify'), uglify = require('gulp-uglify'); gulpUtil = require('gulp-util'), + gulpif = require('gulp-if'), browserify = require('browserify'), babelify = require('babelify'), watchify = require('watchify'), @@ -13,7 +14,8 @@ var gulp = require('gulp'), glob = require('glob'), eventStream = require('event-stream'), semver = require('semver'), - packageJson = require('./package.json'); + packageJson = require('./package.json'), + sourcemaps = require('gulp-sourcemaps'); var PATHS = { MODULES: './node_modules', @@ -28,6 +30,10 @@ var browserifyOptions = { plugin: [watchify] }; +var isDev = typeof process.env.npm_config_development !== 'undefined'; + +process.env.NODE_ENV = isDev ? 'development' : 'production'; + /** * Transforms the passed JavaScript files to UMD modules. * @@ -41,7 +47,8 @@ function transformToUmd(files, dest) { .pipe(babel({ presets: ['es2015'], moduleId: 'ss.' + path.parse(file).name, - plugins: ['transform-es2015-modules-umd'] + plugins: ['transform-es2015-modules-umd'], + comments: false })) .on('error', notify.onError({ message: 'Error: <%= error.message %>', @@ -56,36 +63,36 @@ if (!semver.satisfies(process.versions.node, packageJson.engines.node)) { process.exit(1); } -if (process.env.npm_config_development) { +if (isDev) { browserifyOptions.debug = true; } -gulp.task('build', ['umd-cms', 'umd-watch', 'bundle-lib']); +var babelifyOptions = { + presets: ['es2015', 'react'], + ignore: /(node_modules|thirdparty)/, + comments: false +}; -gulp.task('bundle-lib', function bundleLib() { - var stream = browserify(Object.assign({}, browserifyOptions, { - entries: PATHS.CMS_JAVASCRIPT_SRC + '/bundles/lib.js' - })) - .transform(babelify.configure({ - presets: ['es2015'], - ignore: /(thirdparty)/ - })) - .on('log', function (msg) { gulpUtil.log('Finished bundle-lib.js ' + msg); }) - .on('update', bundleLib) - .external('jQuery') - .external('i18n') - .bundle() - .on('error', notify.onError({ - message: 'Error: <%= error.message %>', - })) - .pipe(source('bundle-lib.js')) - .pipe(buffer()); +gulp.task('build', ['umd-cms', 'umd-watch', 'bundle-legacy']); - if (typeof process.env.npm_config_development === 'undefined') { - stream.pipe(uglify()); - } +gulp.task('bundle-legacy', function bundleLeftAndMain() { + var bundleFileName = 'bundle-legacy.js'; - return stream.pipe(gulp.dest(PATHS.CMS_JAVASCRIPT_DIST)); + return browserify(Object.assign({}, browserifyOptions, { entries: PATHS.CMS_JAVASCRIPT_SRC + '/bundles/legacy.js' })) + .on('update', bundleLeftAndMain) + .on('log', function (msg) { gulpUtil.log('Finished', 'bundled ' + bundleFileName + ' ' + msg) }) + .transform('babelify', babelifyOptions) + .external('jQuery') + .external('i18n') + .external('router') + .bundle() + .on('error', notify.onError({ message: bundleFileName + ': <%= error.message %>' })) + .pipe(source(bundleFileName)) + .pipe(buffer()) + .pipe(sourcemaps.init({ loadMaps: true })) + .pipe(gulpif(!isDev, uglify())) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(PATHS.CMS_JAVASCRIPT_DIST)); }); gulp.task('umd-cms', function () { diff --git a/javascript/dist/AssetAdmin.js b/javascript/dist/AssetAdmin.js index fdbfe43c..ab05186d 100644 --- a/javascript/dist/AssetAdmin.js +++ b/javascript/dist/AssetAdmin.js @@ -23,39 +23,9 @@ }; } - /** - * File: AssetAdmin.js - */ - _jQuery2.default.entwine('ss', function ($) { - /** - * Delete selected folders through "batch actions" tab. - */ - /* assets don't currently have batch actions; disabling for now - $(document).ready(function() { - $('#Form_BatchActionsForm').entwine('.ss.tree').register( - // TODO Hardcoding of base URL - 'admin/assets/batchactions/delete', - function(ids) { - var confirmed = confirm( - i18n.sprintf( - i18n._t('AssetAdmin.BATCHACTIONSDELETECONFIRM'), - ids.length - ) - ); - return (confirmed) ? ids : false; - } - ); - }); - */ - - /** - * Load folder detail view via controller methods - * rather than built-in GridField view (which is only geared towards showing files). - */ $('.AssetAdmin.cms-edit-form .ss-gridfield-item').entwine({ onclick: function onclick(e) { - // Let actions do their own thing if ($(e.target).closest('.action').length) { this._super(e); return; @@ -94,12 +64,6 @@ } }); - /** - * Prompt for a new foldername, rather than using dedicated form. - * Better usability, but less flexibility in terms of inputs and validation. - * Mainly necessary because AssetAdmin->AddForm() returns don't play nicely - * with the nested AssetAdmin->EditForm() DOM structures. - */ $('.AssetAdmin .cms-add-folder-link').entwine({ onclick: function onclick(e) { var name = prompt(_i18n2.default._t('Folder.Name')); @@ -110,17 +74,7 @@ } }); - /** - * Class: #Form_SyncForm - */ $('#Form_SyncForm').entwine({ - - /** - * Function: onsubmit - * - * Parameters: - * (Event) e - */ onsubmit: function onsubmit(e) { var button = jQuery(this).find(':submit:first'); button.addClass('loading'); @@ -129,16 +83,14 @@ data: this.serializeArray(), success: function success() { button.removeClass('loading'); - // reload current form and tree + var currNode = $('.cms-tree')[0].firstSelected(); if (currNode) { var url = $(currNode).find('a').attr('href'); $('.cms-content').loadPanel(url); } $('.cms-tree')[0].setCustomURL('admin/assets/getsubtree'); - $('.cms-tree')[0].reload({ onSuccess: function onSuccess() { - // TODO Reset current tree node - } }); + $('.cms-tree')[0].reload({ onSuccess: function onSuccess() {} }); } }); @@ -146,9 +98,6 @@ } }); - /** - * Reload the gridfield to show the user the file has been added - */ $('.AssetAdmin.cms-edit-form .ss-uploadfield-item-progress').entwine({ onunmatch: function onunmatch() { $('.AssetAdmin.cms-edit-form .ss-gridfield').reload(); diff --git a/javascript/dist/CMSMain.AddForm.js b/javascript/dist/CMSMain.AddForm.js index 25cae0a7..a0098c61 100644 --- a/javascript/dist/CMSMain.AddForm.js +++ b/javascript/dist/CMSMain.AddForm.js @@ -22,10 +22,6 @@ } _jQuery2.default.entwine('ss', function ($) { - /** - * Reset the parent node selection if the type is - * set back to "toplevel page", to avoid submitting inconsistent state. - */ $(".cms-add-form .parent-mode :input").entwine({ onclick: function onclick(e) { if (this.val() == 'top') { @@ -37,8 +33,8 @@ }); $(".cms-add-form").entwine({ - ParentID: 0, // Last selected parentID - ParentCache: {}, // Cache allowed children for each selected page + ParentID: 0, + ParentCache: {}, onadd: function onadd() { var self = this; this.find('#Form_AddForm_ParentID_Holder .TreeDropdownField').bind('change', function () { @@ -58,12 +54,7 @@ cache[parentID] = children; this.setParentCache(cache); }, - /** - * Limit page type selection based on parent selection. - * Select of root classes is pre-computed, but selections with a given parent - * are updated on-demand. - * Similar implementation to LeftAndMain.Tree.js. - */ + updateTypeList: function updateTypeList() { var hints = this.data('hints'), parentTree = this.find('#Form_AddForm_ParentID_Holder .TreeDropdownField'), @@ -78,15 +69,12 @@ disallowedChildren = []; if (id) { - // Prevent interface operations if (this.hasClass('loading')) return; this.addClass('loading'); - // Enable last parent ID to be re-selected from memory this.setParentID(id); if (!parentTree.getValue()) parentTree.setValue(id); - // Use cached data if available disallowedChildren = this.loadCachedChildren(id); if (disallowedChildren !== null) { this.updateSelectionFilter(disallowedChildren, defaultChildClass); @@ -97,7 +85,6 @@ url: self.data('childfilter'), data: { 'ParentID': id }, success: function success(data) { - // reload current form and tree self.saveCachedChildren(id, data); self.updateSelectionFilter(data, defaultChildClass); }, @@ -111,15 +98,9 @@ disallowedChildren = hint && typeof hint.disallowedChildren !== 'undefined' ? hint.disallowedChildren : [], this.updateSelectionFilter(disallowedChildren, defaultChildClass); } }, - /** - * Update the selection filter with the given blacklist and default selection - * - * @param array disallowedChildren - * @param string defaultChildClass - */ + updateSelectionFilter: function updateSelectionFilter(disallowedChildren, defaultChildClass) { - // Limit selection - var allAllowed = null; // troolian + var allAllowed = null; this.find('#Form_AddForm_PageType li').each(function () { var className = $(this).find('input').val(), isAllowed = $.inArray(className, disallowedChildren) === -1; @@ -129,7 +110,6 @@ if (allAllowed === null) allAllowed = isAllowed;else allAllowed = allAllowed && isAllowed; }); - // Set default child selection, or fall back to first available option if (defaultChildClass) { var selectedEl = this.find('#Form_AddForm_PageType li input[value=' + defaultChildClass + ']').parents('li:first'); } else { @@ -138,7 +118,6 @@ selectedEl.setSelected(true); selectedEl.siblings().setSelected(false); - // Disable the "Create" button if none of the pagetypes are available var buttonState = this.find('#Form_AddForm_PageType li:not(.disabled)').length ? 'enable' : 'disable'; this.find('button[name=action_doAdd]').button(buttonState); @@ -173,7 +152,6 @@ list = $('.cms-list'), parentId = 0; - // Choose parent ID either from tree or list view, depending which is visible if (tree.is(':visible')) { var selected = tree.jstree('get_selected'); parentId = selected ? $(selected[0]).data('id') : null; @@ -194,11 +172,7 @@ $('.cms-container').loadPanel(url, null, data); e.preventDefault(); - // Remove focussed state from button this.blur(); - - // $('.cms-page-add-form-dialog').dialog('open'); - // e.preventDefault(); } }); }); diff --git a/javascript/dist/CMSMain.EditForm.js b/javascript/dist/CMSMain.EditForm.js index 035d9935..1cea35de 100644 --- a/javascript/dist/CMSMain.EditForm.js +++ b/javascript/dist/CMSMain.EditForm.js @@ -23,31 +23,14 @@ }; } - /** - * File: CMSMain.EditForm.js - */ - - _jQuery2.default.entwine('ss', function ($) { - /** - * Class: .cms-edit-form :input[name=ClassName] - * Alert the user on change of page-type. This might have implications - * on the available form fields etc. - */ $('.cms-edit-form :input[name=ClassName]').entwine({ - // Function: onchange onchange: function onchange() { alert(_i18n2.default._t('CMSMAIN.ALERTCLASSNAME')); } }); - /** - * Class: .cms-edit-form input[name=Title] - * - * Input validation on the Title field - */ $('.cms-edit-form input[name=Title]').entwine({ - // Constructor: onmatch onmatch: function onmatch() { var self = this; @@ -64,7 +47,6 @@ var title = self.val(); self.data('OrigVal', title); - // Criteria for defining a "new" page if (urlSegmentInput.val().indexOf(urlSegmentInput.data('defaultUrl')) === 0 && liveLinkInput.val() == '') { self.updateURLSegment(title); } else { @@ -82,31 +64,17 @@ this._super(); }, - /** - * Function: updateRelatedFields - * - * Update the related fields if appropriate - * (String) title The new title - * (Stirng) origTitle The original title - */ updateRelatedFields: function updateRelatedFields(title, origTitle) { - // Update these fields only if their value was originally the same as the title this.parents('form').find('input[name=MetaTitle], input[name=MenuTitle]').each(function () { var $this = $(this); if ($this.val() == origTitle) { $this.val(title); - // Onchange bubbling didn't work in IE8, so .trigger('change') couldn't be used + if ($this.updatedRelatedFields) $this.updatedRelatedFields(); } }); }, - /** - * Function: updateURLSegment - * - * Update the URLSegment - * (String) title - */ updateURLSegment: function updateURLSegment(title) { var urlSegmentInput = $('input:text[name=URLSegment]', this.closest('form')); var urlSegmentField = urlSegmentInput.closest('.field.urlsegment'); @@ -117,12 +85,6 @@ } }, - /** - * Function: updateBreadcrumbLabel - * - * Update the breadcrumb - * (String) title - */ updateBreadcrumbLabel: function updateBreadcrumbLabel(title) { var pageID = $('.cms-edit-form input[name=ID]').val(); var panelCrumb = $('span.cms-panel-link.crumb'); @@ -131,17 +93,10 @@ } }, - /** - * Function: _addActions - * - * Utility to add update from title action - * - */ _addActions: function _addActions() { var self = this; var updateURLFromTitle; - // update button updateURLFromTitle = $('