Skip to content

Commit

Permalink
Establish base Snowboard framework in Backend (#548)
Browse files Browse the repository at this point in the history
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 <github@luketowers.ca>
  • Loading branch information
bennothommo and LukeTowers committed May 16, 2022
1 parent ac130c4 commit f79e672
Show file tree
Hide file tree
Showing 33 changed files with 1,251 additions and 1,082 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/code-quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ jobs:
- name: Run code quality checks on System Module
working-directory: ./modules/system
run: npx eslint .

- name: Install Node dependencies for Backend Module
working-directory: ./modules/backend
run: npm install

- name: Run code quality checks on Backend Module
working-directory: ./modules/backend
run: npx eslint .
14 changes: 14 additions & 0 deletions modules/backend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Ignore build files
**/node_modules/**
build/*.js
**/build/*.js
**/mix.webpack.js

# Ignore all JS except for Mix-based assets
assets/js
assets/vendor
behaviors/**/*.js
controllers/**/*.js
formwidgets/**/*.js
reportwidgets/**/*.js
widgets/**/*.js
36 changes: 36 additions & 0 deletions modules/backend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"env": {
"es6": true,
"browser": true
},
"globals": {
"Snowboard": "writable"
},
"extends": [
"airbnb-base",
"plugin:vue/vue3-recommended"
],
"rules": {
"class-methods-use-this": ["off"],
"indent": ["error", 4, {
"SwitchCase": 1
}],
"max-len": ["off"],
"new-cap": ["error", { "properties": false }],
"no-alert": ["off"],
"no-param-reassign": ["error", {
"props": false
}],
"vue/html-indent": ["error", 4],
"vue/html-self-closing": ["error", {
"html": {
"void": "never",
"normal": "any",
"component": "always"
},
"svg": "always",
"math": "always"
}],
"vue/multi-word-component-names": ["off"]
}
}
6 changes: 6 additions & 0 deletions modules/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Backend module ignores

# Ignore Mix files
node_modules
package-lock.json
mix.webpack.js
140 changes: 0 additions & 140 deletions modules/backend/assets/js/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,6 @@
* Winter General Utilities
*/

/*
* Ensure the CSRF token is added to all AJAX requests.
*/

$.ajaxPrefilter(function(options) {
var token = $('meta[name="csrf-token"]').attr('content')

if (token) {
if (!options.headers) options.headers = {}
options.headers['X-CSRF-TOKEN'] = token
}
})

/*
* Path helpers
*/
Expand All @@ -36,133 +23,6 @@ $.wn.backendUrl = function(url) {
return backendBasePath + '/' + url
}

/*
* Asset Manager
*
* Usage: assetManager.load({ css:[], js:[], img:[] }, onLoadedCallback)
*/

AssetManager = function() {

var o = {

load: function(collection, callback) {
var jsList = (collection.js) ? collection.js : [],
cssList = (collection.css) ? collection.css : [],
imgList = (collection.img) ? collection.img : []

jsList = $.grep(jsList, function(item){
return $('head script[src="'+item+'"]').length == 0
})

cssList = $.grep(cssList, function(item){
return $('head link[href="'+item+'"]').length == 0
})

var cssCounter = 0,
jsLoaded = false,
imgLoaded = false

if (jsList.length === 0 && cssList.length === 0 && imgList.length === 0) {
callback && callback()
return
}

o.loadJavaScript(jsList, function(){
jsLoaded = true
checkLoaded()
})

$.each(cssList, function(index, source){
o.loadStyleSheet(source, function(){
cssCounter++
checkLoaded()
})
})

o.loadImage(imgList, function(){
imgLoaded = true
checkLoaded()
})

function checkLoaded() {
if (!imgLoaded)
return false

if (!jsLoaded)
return false

if (cssCounter < cssList.length)
return false

callback && callback()
}
},

/*
* Loads StyleSheet files
*/
loadStyleSheet: function(source, callback) {
var cssElement = document.createElement('link')

cssElement.setAttribute('rel', 'stylesheet')
cssElement.setAttribute('type', 'text/css')
cssElement.setAttribute('href', source)
cssElement.addEventListener('load', callback, false)

if (typeof cssElement != 'undefined') {
document.getElementsByTagName('head')[0].appendChild(cssElement)
}

return cssElement
},

/*
* Loads JavaScript files in sequence
*/
loadJavaScript: function(sources, callback) {
if (sources.length <= 0)
return callback()

var source = sources.shift(),
jsElement = document.createElement('script');

jsElement.setAttribute('type', 'text/javascript')
jsElement.setAttribute('src', source)
jsElement.addEventListener('load', function() {
o.loadJavaScript(sources, callback)
}, false)

if (typeof jsElement != 'undefined') {
document.getElementsByTagName('head')[0].appendChild(jsElement)
}
},

/*
* Loads Image files
*/
loadImage: function(sources, callback) {
if (sources.length <= 0)
return callback()

var loaded = 0
$.each(sources, function(index, source){
var img = new Image()
img.onload = function() {
if (++loaded == sources.length && callback)
callback()
}
img.src = source
})
}

};

return o;
};

assetManager = new AssetManager();

/*
* String escape
*/
Expand Down
42 changes: 2 additions & 40 deletions modules/backend/assets/js/winter-min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 107 additions & 0 deletions modules/backend/assets/ui/js/ajax/Handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Backend AJAX handler.
*
* This is a utility script that resolves some backwards-compatibility issues with the functionality
* that relies on the old framework, and ensures that Snowboard works well within the Backend
* environment.
*
* Functions:
* - Adds the "render" jQuery event to Snowboard requests that widgets use to initialise.
* - Ensures the CSRF token is included in requests.
*
* @copyright 2021 Winter.
* @author Ben Thomson <git@alfreido.com>
*/
export default class Handler extends Snowboard.Singleton {
/**
* Event listeners.
*
* @returns {Object}
*/
listens() {
return {
ready: 'ready',
ajaxFetchOptions: 'ajaxFetchOptions',
ajaxUpdateComplete: 'ajaxUpdateComplete',
};
}

/**
* Ready handler.
*
* Adds the jQuery AJAX prefilter that the old framework uses to inject the CSRF token in AJAX
* calls, and fires off a "render" event.
*/
ready() {
if (!window.jQuery) {
return;
}

window.jQuery.ajaxPrefilter((options) => {
if (this.hasToken()) {
if (!options.headers) {
options.headers = {};
}
options.headers['X-CSRF-TOKEN'] = this.getToken();
}
});

// Add "render" event for backwards compatibility
window.jQuery(document).trigger('render');
}

/**
* Fetch options handler.
*
* Ensures that the CSRF token is included in Snowboard requests.
*
* @param {Object} options
*/
ajaxFetchOptions(options) {
if (this.hasToken()) {
options.headers['X-CSRF-TOKEN'] = this.getToken();
}
}

/**
* Update complete handler.
*
* Fires off a "render" event when partials are updated so that any widgets included in
* responses are correctly initialised.
*/
ajaxUpdateComplete() {
if (!window.jQuery) {
return;
}

// Add "render" event for backwards compatibility
window.jQuery(document).trigger('render');
}

/**
* Determines if a CSRF token is available.
*
* @returns {Boolean}
*/
hasToken() {
const tokenElement = document.querySelector('meta[name="csrf-token"]');

if (!tokenElement) {
return false;
}
if (!tokenElement.hasAttribute('content')) {
return false;
}

return true;
}

/**
* Gets the CSRF token.
*
* @returns {String}
*/
getToken() {
return document.querySelector('meta[name="csrf-token"]').getAttribute('content');
}
}
Loading

0 comments on commit f79e672

Please sign in to comment.