Skip to content

Commit f79e672

Browse files
Establish base Snowboard framework in Backend (#548)
This PR establishes a base Snowboard framework in the Backend. While we won't likely have any specific Snowboard widgets or functionality in the 1.1 branch, it will allow people to use Snowboard in the Backend should they wish. Fixes #541. Co-authored-by: Luke Towers <[email protected]>
1 parent ac130c4 commit f79e672

33 files changed

+1251
-1082
lines changed

.github/workflows/code-quality.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,11 @@ jobs:
5858
- name: Run code quality checks on System Module
5959
working-directory: ./modules/system
6060
run: npx eslint .
61+
62+
- name: Install Node dependencies for Backend Module
63+
working-directory: ./modules/backend
64+
run: npm install
65+
66+
- name: Run code quality checks on Backend Module
67+
working-directory: ./modules/backend
68+
run: npx eslint .

modules/backend/.eslintignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Ignore build files
2+
**/node_modules/**
3+
build/*.js
4+
**/build/*.js
5+
**/mix.webpack.js
6+
7+
# Ignore all JS except for Mix-based assets
8+
assets/js
9+
assets/vendor
10+
behaviors/**/*.js
11+
controllers/**/*.js
12+
formwidgets/**/*.js
13+
reportwidgets/**/*.js
14+
widgets/**/*.js

modules/backend/.eslintrc.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"env": {
3+
"es6": true,
4+
"browser": true
5+
},
6+
"globals": {
7+
"Snowboard": "writable"
8+
},
9+
"extends": [
10+
"airbnb-base",
11+
"plugin:vue/vue3-recommended"
12+
],
13+
"rules": {
14+
"class-methods-use-this": ["off"],
15+
"indent": ["error", 4, {
16+
"SwitchCase": 1
17+
}],
18+
"max-len": ["off"],
19+
"new-cap": ["error", { "properties": false }],
20+
"no-alert": ["off"],
21+
"no-param-reassign": ["error", {
22+
"props": false
23+
}],
24+
"vue/html-indent": ["error", 4],
25+
"vue/html-self-closing": ["error", {
26+
"html": {
27+
"void": "never",
28+
"normal": "any",
29+
"component": "always"
30+
},
31+
"svg": "always",
32+
"math": "always"
33+
}],
34+
"vue/multi-word-component-names": ["off"]
35+
}
36+
}

modules/backend/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Backend module ignores
2+
3+
# Ignore Mix files
4+
node_modules
5+
package-lock.json
6+
mix.webpack.js

modules/backend/assets/js/backend.js

-140
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,6 @@
22
* Winter General Utilities
33
*/
44

5-
/*
6-
* Ensure the CSRF token is added to all AJAX requests.
7-
*/
8-
9-
$.ajaxPrefilter(function(options) {
10-
var token = $('meta[name="csrf-token"]').attr('content')
11-
12-
if (token) {
13-
if (!options.headers) options.headers = {}
14-
options.headers['X-CSRF-TOKEN'] = token
15-
}
16-
})
17-
185
/*
196
* Path helpers
207
*/
@@ -36,133 +23,6 @@ $.wn.backendUrl = function(url) {
3623
return backendBasePath + '/' + url
3724
}
3825

39-
/*
40-
* Asset Manager
41-
*
42-
* Usage: assetManager.load({ css:[], js:[], img:[] }, onLoadedCallback)
43-
*/
44-
45-
AssetManager = function() {
46-
47-
var o = {
48-
49-
load: function(collection, callback) {
50-
var jsList = (collection.js) ? collection.js : [],
51-
cssList = (collection.css) ? collection.css : [],
52-
imgList = (collection.img) ? collection.img : []
53-
54-
jsList = $.grep(jsList, function(item){
55-
return $('head script[src="'+item+'"]').length == 0
56-
})
57-
58-
cssList = $.grep(cssList, function(item){
59-
return $('head link[href="'+item+'"]').length == 0
60-
})
61-
62-
var cssCounter = 0,
63-
jsLoaded = false,
64-
imgLoaded = false
65-
66-
if (jsList.length === 0 && cssList.length === 0 && imgList.length === 0) {
67-
callback && callback()
68-
return
69-
}
70-
71-
o.loadJavaScript(jsList, function(){
72-
jsLoaded = true
73-
checkLoaded()
74-
})
75-
76-
$.each(cssList, function(index, source){
77-
o.loadStyleSheet(source, function(){
78-
cssCounter++
79-
checkLoaded()
80-
})
81-
})
82-
83-
o.loadImage(imgList, function(){
84-
imgLoaded = true
85-
checkLoaded()
86-
})
87-
88-
function checkLoaded() {
89-
if (!imgLoaded)
90-
return false
91-
92-
if (!jsLoaded)
93-
return false
94-
95-
if (cssCounter < cssList.length)
96-
return false
97-
98-
callback && callback()
99-
}
100-
},
101-
102-
/*
103-
* Loads StyleSheet files
104-
*/
105-
loadStyleSheet: function(source, callback) {
106-
var cssElement = document.createElement('link')
107-
108-
cssElement.setAttribute('rel', 'stylesheet')
109-
cssElement.setAttribute('type', 'text/css')
110-
cssElement.setAttribute('href', source)
111-
cssElement.addEventListener('load', callback, false)
112-
113-
if (typeof cssElement != 'undefined') {
114-
document.getElementsByTagName('head')[0].appendChild(cssElement)
115-
}
116-
117-
return cssElement
118-
},
119-
120-
/*
121-
* Loads JavaScript files in sequence
122-
*/
123-
loadJavaScript: function(sources, callback) {
124-
if (sources.length <= 0)
125-
return callback()
126-
127-
var source = sources.shift(),
128-
jsElement = document.createElement('script');
129-
130-
jsElement.setAttribute('type', 'text/javascript')
131-
jsElement.setAttribute('src', source)
132-
jsElement.addEventListener('load', function() {
133-
o.loadJavaScript(sources, callback)
134-
}, false)
135-
136-
if (typeof jsElement != 'undefined') {
137-
document.getElementsByTagName('head')[0].appendChild(jsElement)
138-
}
139-
},
140-
141-
/*
142-
* Loads Image files
143-
*/
144-
loadImage: function(sources, callback) {
145-
if (sources.length <= 0)
146-
return callback()
147-
148-
var loaded = 0
149-
$.each(sources, function(index, source){
150-
var img = new Image()
151-
img.onload = function() {
152-
if (++loaded == sources.length && callback)
153-
callback()
154-
}
155-
img.src = source
156-
})
157-
}
158-
159-
};
160-
161-
return o;
162-
};
163-
164-
assetManager = new AssetManager();
165-
16626
/*
16727
* String escape
16828
*/

modules/backend/assets/js/winter-min.js

+2-40
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Backend AJAX handler.
3+
*
4+
* This is a utility script that resolves some backwards-compatibility issues with the functionality
5+
* that relies on the old framework, and ensures that Snowboard works well within the Backend
6+
* environment.
7+
*
8+
* Functions:
9+
* - Adds the "render" jQuery event to Snowboard requests that widgets use to initialise.
10+
* - Ensures the CSRF token is included in requests.
11+
*
12+
* @copyright 2021 Winter.
13+
* @author Ben Thomson <[email protected]>
14+
*/
15+
export default class Handler extends Snowboard.Singleton {
16+
/**
17+
* Event listeners.
18+
*
19+
* @returns {Object}
20+
*/
21+
listens() {
22+
return {
23+
ready: 'ready',
24+
ajaxFetchOptions: 'ajaxFetchOptions',
25+
ajaxUpdateComplete: 'ajaxUpdateComplete',
26+
};
27+
}
28+
29+
/**
30+
* Ready handler.
31+
*
32+
* Adds the jQuery AJAX prefilter that the old framework uses to inject the CSRF token in AJAX
33+
* calls, and fires off a "render" event.
34+
*/
35+
ready() {
36+
if (!window.jQuery) {
37+
return;
38+
}
39+
40+
window.jQuery.ajaxPrefilter((options) => {
41+
if (this.hasToken()) {
42+
if (!options.headers) {
43+
options.headers = {};
44+
}
45+
options.headers['X-CSRF-TOKEN'] = this.getToken();
46+
}
47+
});
48+
49+
// Add "render" event for backwards compatibility
50+
window.jQuery(document).trigger('render');
51+
}
52+
53+
/**
54+
* Fetch options handler.
55+
*
56+
* Ensures that the CSRF token is included in Snowboard requests.
57+
*
58+
* @param {Object} options
59+
*/
60+
ajaxFetchOptions(options) {
61+
if (this.hasToken()) {
62+
options.headers['X-CSRF-TOKEN'] = this.getToken();
63+
}
64+
}
65+
66+
/**
67+
* Update complete handler.
68+
*
69+
* Fires off a "render" event when partials are updated so that any widgets included in
70+
* responses are correctly initialised.
71+
*/
72+
ajaxUpdateComplete() {
73+
if (!window.jQuery) {
74+
return;
75+
}
76+
77+
// Add "render" event for backwards compatibility
78+
window.jQuery(document).trigger('render');
79+
}
80+
81+
/**
82+
* Determines if a CSRF token is available.
83+
*
84+
* @returns {Boolean}
85+
*/
86+
hasToken() {
87+
const tokenElement = document.querySelector('meta[name="csrf-token"]');
88+
89+
if (!tokenElement) {
90+
return false;
91+
}
92+
if (!tokenElement.hasAttribute('content')) {
93+
return false;
94+
}
95+
96+
return true;
97+
}
98+
99+
/**
100+
* Gets the CSRF token.
101+
*
102+
* @returns {String}
103+
*/
104+
getToken() {
105+
return document.querySelector('meta[name="csrf-token"]').getAttribute('content');
106+
}
107+
}

0 commit comments

Comments
 (0)