mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
lazy-load codemirror on code injection screen (#99)
refs TryGhost/Ghost#6149 - concats codemirror.js and css on build, keeping them out of vendor.js - add lazy-loader service to enable loading of external scripts
This commit is contained in:
parent
8c8365720b
commit
c0f21b37d3
@ -1,6 +1,8 @@
|
||||
/* global CodeMirror */
|
||||
import Component from 'ember-component';
|
||||
import run, {bind} from 'ember-runloop';
|
||||
import run, {bind, scheduleOnce} from 'ember-runloop';
|
||||
import injectService from 'ember-service/inject';
|
||||
|
||||
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
||||
import {InvokeActionMixin} from 'ember-invoke-action';
|
||||
|
||||
@ -18,9 +20,21 @@ const CmEditorComponent = Component.extend(InvokeActionMixin, {
|
||||
|
||||
_editor: null, // reference to CodeMirror editor
|
||||
|
||||
lazyLoader: injectService(),
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.get('lazyLoader').loadStyle('codemirror', 'codemirror/codemirror.css');
|
||||
|
||||
this.get('lazyLoader').loadScript('codemirror', 'codemirror/codemirror.js').then(() => {
|
||||
scheduleOnce('afterRender', this, function () {
|
||||
this._initCodeMirror();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_initCodeMirror() {
|
||||
let options = this.getProperties('lineNumbers', 'indentUnit', 'mode', 'theme');
|
||||
let editor = new CodeMirror(this.element, options);
|
||||
|
||||
|
53
ghost/admin/app/services/lazy-loader.js
Normal file
53
ghost/admin/app/services/lazy-loader.js
Normal file
@ -0,0 +1,53 @@
|
||||
import $ from 'jquery';
|
||||
import Ember from 'ember';
|
||||
import RSVP from 'rsvp';
|
||||
import Service from 'ember-service';
|
||||
import injectService from 'ember-service/inject';
|
||||
|
||||
const {testing} = Ember;
|
||||
|
||||
export default Service.extend({
|
||||
ajax: injectService(),
|
||||
ghostPaths: injectService(),
|
||||
|
||||
// This is needed so we can disable it in unit tests
|
||||
testing,
|
||||
|
||||
scriptPromises: {},
|
||||
|
||||
loadScript(key, url) {
|
||||
if (this.get('testing')) {
|
||||
return RSVP.resolve();
|
||||
}
|
||||
|
||||
if (this.get(`scriptPromises.${key}`)) {
|
||||
// Script is already loaded/in the process of being loaded,
|
||||
// so return that promise
|
||||
return this.get(`scriptPromises.${key}`);
|
||||
}
|
||||
|
||||
let ajax = this.get('ajax');
|
||||
let adminRoot = this.get('ghostPaths.adminRoot');
|
||||
|
||||
let scriptPromise = ajax.request(`${adminRoot}${url}`, {
|
||||
dataType: 'script',
|
||||
cache: true
|
||||
});
|
||||
|
||||
this.set(`scriptPromises.${key}`, scriptPromise);
|
||||
|
||||
return scriptPromise;
|
||||
},
|
||||
|
||||
loadStyle(key, url) {
|
||||
if (this.get('testing')) {
|
||||
return RSVP.resolve();
|
||||
}
|
||||
|
||||
if (!$(`#${key}-styles`).length) {
|
||||
let $style = $(`<link rel="stylesheet" id="${key}-styles" />`);
|
||||
$style.attr('href', `${this.get('ghostPaths.adminRoot')}${url}`);
|
||||
$('head').append($style);
|
||||
}
|
||||
}
|
||||
});
|
@ -2,11 +2,15 @@
|
||||
/* global require, module */
|
||||
|
||||
var EmberApp = require('ember-cli/lib/broccoli/ember-app'),
|
||||
concat = require('broccoli-concat'),
|
||||
mergeTrees = require('broccoli-merge-trees'),
|
||||
uglify = require('broccoli-uglify-js'),
|
||||
cleanCSS = require('broccoli-clean-css'),
|
||||
environment = EmberApp.env(),
|
||||
isProduction = environment === 'production',
|
||||
mythCompress = isProduction || environment === 'test',
|
||||
disabled = {enabled: false},
|
||||
assetLocation;
|
||||
assetLocation, codemirrorAssets;
|
||||
|
||||
assetLocation = function (fileName) {
|
||||
if (isProduction) {
|
||||
@ -15,6 +19,48 @@ assetLocation = function (fileName) {
|
||||
return '/assets/' + fileName;
|
||||
};
|
||||
|
||||
codemirrorAssets = function () {
|
||||
var codemirrorFiles = [
|
||||
'lib/codemirror.css',
|
||||
'theme/xq-light.css',
|
||||
'lib/codemirror.js',
|
||||
'mode/htmlmixed/htmlmixed.js',
|
||||
'mode/xml/xml.js',
|
||||
'mode/css/css.js',
|
||||
'mode/javascript/javascript.js'
|
||||
];
|
||||
|
||||
if (environment === 'test') {
|
||||
return {import: codemirrorFiles};
|
||||
}
|
||||
|
||||
return {
|
||||
public: {
|
||||
include: codemirrorFiles,
|
||||
destDir: '/',
|
||||
processTree: function (tree) {
|
||||
var jsTree = concat(tree, {
|
||||
outputFile: 'assets/codemirror/codemirror.js',
|
||||
headerFiles: ['lib/codemirror.js'],
|
||||
inputFiles: ['mode/**/*']
|
||||
});
|
||||
|
||||
var cssTree = concat(tree, {
|
||||
outputFile: 'assets/codemirror/codemirror.css',
|
||||
inputFiles: ['**/*.css']
|
||||
});
|
||||
|
||||
if (isProduction) {
|
||||
jsTree = uglify(jsTree);
|
||||
cssTree = cleanCSS(cssTree);
|
||||
}
|
||||
|
||||
return mergeTrees([jsTree, cssTree]);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = function (defaults) {
|
||||
var app = new EmberApp(defaults, {
|
||||
babel: {
|
||||
@ -45,17 +91,7 @@ module.exports = function (defaults) {
|
||||
'blueimp-md5': {
|
||||
import: ['js/md5.js']
|
||||
},
|
||||
codemirror: {
|
||||
import: [
|
||||
'lib/codemirror.js',
|
||||
'lib/codemirror.css',
|
||||
'theme/xq-light.css',
|
||||
'mode/htmlmixed/htmlmixed.js',
|
||||
'mode/xml/xml.js',
|
||||
'mode/css/css.js',
|
||||
'mode/javascript/javascript.js',
|
||||
]
|
||||
},
|
||||
codemirror: codemirrorAssets(),
|
||||
'jquery-deparam': {
|
||||
enabled: EmberApp.env() === 'test',
|
||||
import: ['jquery-deparam.js']
|
||||
|
@ -28,6 +28,10 @@
|
||||
"blueimp-md5": "2.3.0",
|
||||
"bower": "1.7.9",
|
||||
"broccoli-asset-rev": "2.4.4",
|
||||
"broccoli-clean-css": "1.1.0",
|
||||
"broccoli-concat": "2.2.0",
|
||||
"broccoli-merge-trees": "1.1.1",
|
||||
"broccoli-uglify-js": "0.2.0",
|
||||
"chalk": "1.1.3",
|
||||
"codemirror": "5.16.0",
|
||||
"csscomb": "3.1.8",
|
||||
|
67
ghost/admin/tests/integration/services/lazy-loader-test.js
Normal file
67
ghost/admin/tests/integration/services/lazy-loader-test.js
Normal file
@ -0,0 +1,67 @@
|
||||
/* jshint expr:true */
|
||||
import { expect } from 'chai';
|
||||
import {
|
||||
describeModule,
|
||||
it
|
||||
} from 'ember-mocha';
|
||||
import Pretender from 'pretender';
|
||||
import RSVP from 'rsvp';
|
||||
import $ from 'jquery';
|
||||
|
||||
describeModule(
|
||||
'service:lazy-loader',
|
||||
'Integration: Service: lazy-loader',
|
||||
{integration: true},
|
||||
function() {
|
||||
let server;
|
||||
let ghostPaths = {
|
||||
adminRoot: '/assets/'
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
server = new Pretender();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
server.shutdown();
|
||||
});
|
||||
|
||||
it('loads a script correctly and only once', function (done) {
|
||||
let subject = this.subject({
|
||||
ghostPaths,
|
||||
scriptPromises: {},
|
||||
testing: false
|
||||
});
|
||||
|
||||
server.get('/assets/test.js', function ({requestHeaders}) {
|
||||
expect(requestHeaders.Accept).to.match(/text\/javascript/);
|
||||
|
||||
return [200, {'Content-Type': 'text/javascript'}, 'window.testLoadScript = \'testvalue\''];
|
||||
});
|
||||
|
||||
subject.loadScript('test-script', 'test.js').then(() => {
|
||||
expect(subject.get('scriptPromises.test-script')).to.exist;
|
||||
expect(window.testLoadScript).to.equal('testvalue');
|
||||
expect(server.handlers[0].numberOfCalls).to.equal(1);
|
||||
|
||||
return subject.loadScript('test-script', 'test.js');
|
||||
}).then(() => {
|
||||
expect(server.handlers[0].numberOfCalls).to.equal(1);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('loads styles correctly', function () {
|
||||
let subject = this.subject({
|
||||
ghostPaths,
|
||||
testing: false
|
||||
});
|
||||
|
||||
subject.loadStyle('testing', 'style.css');
|
||||
|
||||
expect($('#testing-styles').length).to.equal(1);
|
||||
expect($('#testing-styles').attr('href')).to.equal('/assets/style.css');
|
||||
});
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue
Block a user