-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
t/5: Introducing the CKEDITOR namespace, the AMD API and the Builder. #6
Changes from 29 commits
1c16b97
b44682c
03f78c4
2c6e785
a23bda8
1eddc34
9368232
e0ebc2c
ba2f8c6
130b2c7
a3a4956
1dce371
767f6ac
ef522dd
255d2b5
2f578cf
051574a
6113982
c2413f0
c3fc22c
667acb1
76d64c6
f4074f0
9a86ebb
10246ac
3d4fbbe
950871b
66297bb
49b17a2
8880b20
990f135
2c89d5d
ef856f4
1a37506
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** | ||
* @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
*/ | ||
|
||
/* global requirejs, define, require, window, document, location */ | ||
|
||
'use strict'; | ||
|
||
// This file is shared by the dev and release versions of CKEditor. It bootstraps the API. | ||
|
||
( function( root ) { | ||
var CKEDITOR = root.CKEDITOR = { | ||
/** | ||
* Computes the value of the `basePath` property. | ||
* | ||
* @private | ||
* @method | ||
* @returns {String} A full URL. | ||
*/ | ||
_getBasePath: getBasePath, | ||
|
||
/** | ||
* The full URL for the CKEditor installation directory. | ||
* | ||
* It is possible to manually provide the base path by setting a global variable named `CKEDITOR_BASEPATH`. This | ||
* global variable must be set **before** the editor script loading. | ||
* | ||
* console.log( CKEDITOR.basePath ); // e.g. 'http://www.example.com/ckeditor/' | ||
* | ||
* @property {String} | ||
*/ | ||
basePath: getBasePath(), | ||
|
||
/** | ||
* Defines an AMD module. | ||
* | ||
* See https://github.com/ckeditor/ckeditor5-design/wiki/AMD for more details about our AMD API. | ||
* | ||
* @method | ||
* @member CKEDITOR | ||
*/ | ||
define: define, | ||
|
||
/** | ||
* Retrieves one or more AMD modules. | ||
* | ||
* Note that the CKEditor AMD API does not download modules on demand so be sure to have their relative scripts | ||
* available in the page. | ||
* | ||
* See https://github.com/ckeditor/ckeditor5-design/wiki/AMD for more details about our AMD API. | ||
* | ||
* @method | ||
* @member CKEDITOR | ||
*/ | ||
require: require | ||
}; | ||
|
||
requirejs.config( { | ||
// Modules are generally relative to the core project. | ||
baseUrl: CKEDITOR.basePath + 'node_modules/ckeditor5-core/src/', | ||
|
||
// These configurations will make no difference in the build version because the following paths will be | ||
// already defined there. | ||
paths: { | ||
// Hide the core "ckeditor" under a different name. | ||
'ckeditor-core': CKEDITOR.basePath + 'node_modules/ckeditor5-core/src/ckeditor', | ||
|
||
// The dev version overrides for the "ckeditor" module. This is empty on release. | ||
'ckeditor-dev': CKEDITOR.basePath + 'src/ckeditor-dev' | ||
} | ||
} ); | ||
|
||
// Define a new "ckeditor" module, which overrides the core one with the above and the dev stuff. | ||
define( 'ckeditor', [ 'ckeditor-core', 'ckeditor-dev', 'utils' ], function( core, dev, utils ) { | ||
utils.extend( core, root.CKEDITOR, ( dev || {} ) ); | ||
root.CKEDITOR = core; | ||
|
||
return core; | ||
} ); | ||
|
||
function getBasePath() { | ||
if ( window.CKEDITOR_BASEPATH ) { | ||
return window.CKEDITOR_BASEPATH; | ||
} | ||
|
||
var scripts = document.getElementsByTagName( 'script' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why so much spacing between variable declarations? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed with 10246ac. |
||
var basePathSrcPattern = /(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i; | ||
var path; | ||
|
||
// Find the first script that src matches ckeditor.js. | ||
[].some.call( scripts, function( script ) { | ||
var match = script.src.match( basePathSrcPattern ); | ||
|
||
if ( match ) { | ||
path = match[ 1 ]; | ||
|
||
return true; | ||
} | ||
} ); | ||
|
||
if ( path.indexOf( ':/' ) == -1 && path.slice( 0, 2 ) != '//' ) { | ||
if ( path[ 0 ] == '/' ) { | ||
path = location.href.match( /^.*?:\/\/[^\/]*/ )[ 0 ] + path; | ||
} else { | ||
path = location.href.match( /^[^\?]*\/(?:)/ )[ 0 ] + path; | ||
} | ||
} | ||
|
||
return path; | ||
} | ||
} )( window ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
*/ | ||
|
||
/* jshint node: true */ | ||
|
||
'use strict'; | ||
|
||
var Builder = require( './build/builder' ); | ||
|
||
module.exports = function( grunt ) { | ||
grunt.registerTask( 'build', 'Build a release out of the current development code.', function() { | ||
var done = this.async(); | ||
var builder = new Builder(); | ||
builder.build( done ); | ||
} ); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
/** | ||
* @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
*/ | ||
|
||
/* jshint node: true */ | ||
|
||
'use strict'; | ||
|
||
module.exports = Builder; | ||
|
||
/** | ||
* A CKEditor 5 release builder. | ||
* | ||
* @class Builder | ||
*/ | ||
function Builder( target ) { | ||
/** | ||
* The target directory where to create the build. | ||
* | ||
* **Warning**: if existing, this directory will be deleted before processing. | ||
* | ||
* @property {String} | ||
*/ | ||
this.target = target || 'build'; | ||
|
||
/** | ||
* The temporary directory to use for build processing. | ||
* | ||
* **Warning**: if existing, this directory will be deleted before processing. | ||
* | ||
* @property {String} | ||
*/ | ||
this.tmp = 'build_tmp'; | ||
|
||
/** | ||
* The list of tasks to be executed by the `build()` method. Each entry is an Array containing the name of the | ||
* method inside `tasks` to execute and the message to show to the end user when executing it. | ||
* | ||
* @property {Array} | ||
*/ | ||
this.taskList = [ | ||
[ 'cleanUp', 'Cleaning the "' + target + '" directory...' ], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now (49b17a2) I've got:
BTW. I miss very much an information about where the build was created - where should I look for it now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed with 8880b20. |
||
[ 'copyToTmp', 'Copying source files for manipulation...' ], | ||
[ 'removeAmdNamespace', 'AMD cleanup...' ], | ||
[ 'optimize', 'Creating the optimized code...' ], | ||
[ 'cleanUpTmp', 'Removing the "' + this.tmp + '" directory...' ] | ||
]; | ||
} | ||
|
||
Builder.prototype = { | ||
/** | ||
* Builds a CKEditor release based on the current development code. | ||
* | ||
* @param {Function} [callback] Function to be called when build finishes. It receives `false` on error. | ||
*/ | ||
build: function( callback ) { | ||
var that = this; | ||
var stepCounter = 0; | ||
|
||
// Before starting, run the initial checkups. | ||
if ( !this.checkUp() ) { | ||
console.log( 'Build operation aborted.' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use http://gruntjs.com/api/grunt.log - e.g. BTW. I think I've read somewhere that using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIR it was because of the process output. If you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really - console.log is just a wrapper around stdout.write so the logs will be redirected if we want to. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additionally, the class is coded in a way that it is independent from grunt so it can use by pure node code as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I remembered something wrong. Just one thing then - There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed with 990f135. |
||
callback( false ); | ||
|
||
return; | ||
} | ||
|
||
runNext(); | ||
|
||
function runNext() { | ||
var next = that.taskList.shift(); | ||
|
||
if ( next ) { | ||
stepCounter++; | ||
console.log( stepCounter + '. ' + next[ 1 ] ); | ||
that.tasks[ next[ 0 ] ].call( that, runNext ); | ||
} else { | ||
if ( callback ) { | ||
callback(); | ||
} | ||
} | ||
} | ||
}, | ||
|
||
checkUp: function() { | ||
var fs = require( 'fs' ); | ||
|
||
// Stop if the tmp folder already exists. | ||
if ( fs.existsSync( this.tmp ) ) { | ||
console.log( 'The "' + this.tmp + '" directory already exists. Delete it and try again.' ); | ||
|
||
return false; | ||
} | ||
|
||
return true; | ||
}, | ||
|
||
/** | ||
* Holds individual methods for each task executed by the builder. | ||
* | ||
* All methods here MUST be called in the builder context by using | ||
* `builder.tasks.someMethod.call( builder, callback )`. | ||
*/ | ||
tasks: { | ||
/** | ||
* Deletes the `target` and `tmp` directories. | ||
* | ||
* @param {Function} callback Function to be called when the task is done. | ||
* @returns {Object} The callback returned value. | ||
*/ | ||
cleanUp: function( callback ) { | ||
var del = require( 'del' ); | ||
del.sync( this.target ); | ||
del.sync( this.tmp ); | ||
|
||
return callback(); | ||
}, | ||
|
||
/** | ||
* Copy the local source code of CKEditor and its dependencies to the `tmp` directory for processing. | ||
* | ||
* @param {Function} callback Function to be called when the task is done. | ||
* @returns {Object} The callback returned value. | ||
*/ | ||
copyToTmp: function( callback ) { | ||
var ncp = require( 'ncp' ).ncp; | ||
var path = require( 'path' ); | ||
var fs = require( 'fs' ); | ||
var tmp = this.tmp; | ||
|
||
var deps = require( '../../../package.json' ).dependencies; | ||
|
||
var toCopy = Object.keys( deps ).filter( function( name ) { | ||
return name.indexOf( 'ckeditor5-' ) === 0; | ||
} ); | ||
|
||
fs.mkdirSync( tmp ); | ||
|
||
function copy() { | ||
var module = toCopy.shift(); | ||
|
||
if ( !module ) { | ||
return callback(); | ||
} | ||
|
||
var dest = path.join( tmp + '/', module ); | ||
|
||
if ( !fs.existsSync( dest ) ) { | ||
fs.mkdirSync( dest ); | ||
} | ||
|
||
// Copy the "src" directory only. | ||
ncp( path.join( 'node_modules', module, 'src' ), path.join( dest, 'src' ), { | ||
dereference: true | ||
}, function( err ) { | ||
if ( err ) { | ||
throw err; | ||
} | ||
|
||
copy(); | ||
} ); | ||
} | ||
|
||
copy(); | ||
}, | ||
|
||
/** | ||
* Removes the `CKEDITOR` namespace from AMD calls in the `tmp` copy of the source code. | ||
* | ||
* @param {Function} callback Function to be called when the task is done. | ||
* @returns {Object} The callback returned value. | ||
*/ | ||
removeAmdNamespace: function( callback ) { | ||
var replace = require( 'replace' ); | ||
|
||
replace( { | ||
regex: /^\s*CKEDITOR\.(define|require)/mg, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have to do this? Can't the minified code be using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is necessary for r.js to find dependencies. Actually, to find modules and theirs deps. |
||
replacement: '$1', | ||
paths: [ this.tmp ], | ||
recursive: true, | ||
silent: true | ||
} ); | ||
|
||
callback(); | ||
}, | ||
|
||
/** | ||
* Creates the optimized release version of `ckeditor.js` in the `target` directory out of the `tmp` copy of the | ||
* source code. | ||
* | ||
* @param {Function} callback Function to be called when the task is done. | ||
* @returns {Object} The callback returned value. | ||
*/ | ||
optimize: function( callback ) { | ||
var requirejs = require( 'requirejs' ); | ||
|
||
var config = { | ||
out: this.target + '/ckeditor.js', | ||
|
||
baseUrl: this.tmp + '/ckeditor5-core/src/', | ||
paths: { | ||
'ckeditor': '../../../ckeditor', | ||
'ckeditor-dev': '../../../src/ckeditor-dev', | ||
'ckeditor-core': 'ckeditor' | ||
}, | ||
|
||
include: [ 'ckeditor' ], | ||
stubModules: [ 'ckeditor-dev' ], | ||
|
||
// optimize: 'none', | ||
optimize: 'uglify2', | ||
preserveLicenseComments: false, | ||
wrap: { | ||
startFile: [ 'src/build/start.frag', require.resolve( 'almond' ) ], | ||
endFile: 'src/build/end.frag' | ||
} | ||
}; | ||
|
||
requirejs.optimize( config, callback ); | ||
}, | ||
|
||
/** | ||
* Deletes `tmp` directory. | ||
* | ||
* @param {Function} callback Function to be called when the task is done. | ||
* @returns {Object} The callback returned value. | ||
*/ | ||
cleanUpTmp: function( callback ) { | ||
var del = require( 'del' ); | ||
del.sync( this.tmp ); | ||
|
||
return callback(); | ||
} | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function should be testable. We already had problem in CKEditor 4 that in order to test the base path we had to load multiple iframes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed with 9a86ebb.