Added simple single page ajax handling for a links.

This commit is contained in:
Jan Böhmer 2019-03-24 19:55:39 +01:00
parent ca8ef1d5bd
commit b3db1dd139
8 changed files with 325 additions and 63 deletions

View file

@ -134,6 +134,11 @@ body {
line-height: 1.1;
}
/* Blur content during loading*/
.loading-content {
filter: blur(2px);
}
/********************************
* Toasts
********************************/

View file

@ -6,6 +6,7 @@
*/
// any CSS you require will output into a single css file (app.css in this case)
require('../css/app.css');
// Need jQuery? Install it with "yarn add jquery", then uncomment to require it.
@ -44,4 +45,12 @@ window.$ = window.jQuery = require("jquery");
require('bootstrap-treeview/src/js/bootstrap-treeview');
require('../ts_src/ajax_ui');
import {ajaxUI} from "../ts_src/ajax_ui";
window.ajaxUI = ajaxUI;
//Start AjaxUI
$(document).ready(ajaxUI.start());
//console.log('Hello Webpack Encore! Edit me in assets/js/app.js');

212
assets/ts_src/ajax_ui.ts Normal file
View file

@ -0,0 +1,212 @@
/*
*
* part-db version 0.1
* Copyright (C) 2005 Christoph Lechner
* http://www.cl-projects.de/
*
* part-db version 0.2+
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
* http://code.google.com/p/part-db/
*
* Part-DB Version 0.4+
* Copyright (C) 2016 - 2019 Jan Böhmer
* https://github.com/jbtronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
import * as Cookies from "js-cookie";
/**
* Extract the title (The name between the <title> tags) of a HTML snippet.
* @param {string} html The HTML code which should be searched.
* @returns {string} The title extracted from the html.
*/
function extractTitle(html : string) : string {
let title : string = "";
let regex = /<title>(.*?)<\/title>/gi;
if (regex.test(html)) {
let matches = html.match(regex);
for(let match in matches) {
title = $(matches[match]).text();
}
}
return title;
}
class AjaxUI {
private trees_filled : boolean = false;
private statePopped : boolean = false;
public test()
{
alert("Test");
}
public constructor()
{
//Make back in the browser go back in history
window.onpopstate = this.onPopState;
$(document).ajaxError(this.onAjaxError.bind(this));
//$(document).ajaxComplete(this.onAjaxComplete.bind(this));
}
/**
* Starts the ajax ui und execute handlers registered in addStartAction().
* Should be called in a document.ready, after handlers are set.
*/
public start()
{
console.info("AjaxUI started!");
this.registerLinks();
}
/**
* Register all links, for loading via ajax.
*/
protected registerLinks()
{
$('a').not(".link-external, [data-no-ajax]").click(function (event) {
let a = $(this);
let href = $.trim(a.attr("href"));
//Ignore links without href attr and nav links ('they only have a #)
if(href != null && href != "" && href.charAt(0) !== '#') {
event.preventDefault();
ajaxUI.navigateTo(href);
}
}
)
console.debug('Links registered!');
}
public showProgressBar()
{
//Blur content background
$('#content').addClass('loading-content');
// @ts-ignore
$('#progressModal').modal({
keyboard: false,
backdrop: false,
show: true
});
}
public hideProgressBar()
{
// @ts-ignore
$('#progressModal').modal('hide');
//Remove the remaining things of the modal
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
$('body, .navbar').css('padding-right', "");
}
/**
* Navigates to the given URL
* @param url The url which should be opened.
* @param show_loading Show the loading bar during loading.
*/
public navigateTo(url : string, show_loading : boolean = true)
{
if(show_loading) {
this.showProgressBar();
}
$.ajax(url, {
success: this.onAjaxComplete
});
//$.ajax(url).promise().done(this.onAjaxComplete);
}
/**
* Called when an error occurs on loading ajax. Outputs the message to the console.
*/
private onAjaxError (event, request, settings) {
'use strict';
//Ignore aborted requests.
if (request.statusText =='abort') {
return;
}
console.log(event);
//If it was a server error and response is not empty, show it to user.
if(request.status == 500 && request.responseText !== "")
{
console.log("Response:" + request.responseText);
}
}
/**
* This function gets called every time, the "back" button in the browser is pressed.
* We use it to load the content from history stack via ajax and to rewrite url, so we only have
* to load #content-data
* @param event
*/
private onPopState(event)
{
let page : string = location.href;
ajaxUI.statePopped = true;
ajaxUI.navigateTo(page);
}
/**
* This function takes the response of an ajax requests, and does the things we need to do for our AjaxUI.
* This includes inserting the content and pushing history.
* @param responseText
* @param textStatus
* @param jqXHR
*/
private onAjaxComplete(responseText: string, textStatus: string, jqXHR: any)
{
console.debug("Ajax load completed!");
ajaxUI.hideProgressBar();
//Parse response to DOM structure
let dom = $.parseHTML(responseText);
//And replace the content container
$("#content").replaceWith($("#content", dom));
//Replace login menu too (so everything is up to date)
$("#login-content").replaceWith($('#login-content', dom));
//Set new title
let title = extractTitle(responseText);
document.title = title;
//Push to history, if we currently arent poping an old value.
if(!ajaxUI.statePopped) {
// @ts-ignore
history.pushState(null, title, this.url);
} else {
//Clear pop state
ajaxUI.statePopped;
}
//Do things on the new dom
ajaxUI.registerLinks();
}
}
export let ajaxUI = new AjaxUI();

15
assets/tsconfig.json Normal file
View file

@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"typeRoots": ["../node_modules"],
"types": ["jquery", "js-cookie", "bootstrap"]
},
"exclude": [
"node_modules"
],
"include": [
"./ts_src/*"
]
}

View file

@ -17,6 +17,9 @@
},
"dependencies": {
"@ckeditor/ckeditor5-build-classic": "^12.0.0",
"@types/bootstrap": "^4.3.0",
"@types/jquery": "^3.3.29",
"@types/js-cookie": "^2.2.1",
"awesome-bootstrap-checkbox": "^1.0.1",
"bootstrap-select": "^1.13.8",
"bootstrap-treeview": "jbtronics/bootstrap-treeview",
@ -24,7 +27,10 @@
"datatables.net-buttons-bs4": "^1.5.4",
"datatables.net-fixedheader-bs4": "^3.1.5",
"datatables.net-select-bs4": "^1.2.7",
"js-cookie": "^2.2.0",
"jszip": "^3.2.0",
"pdfmake": "^0.1.53"
"pdfmake": "^0.1.53",
"ts-loader": "^5.3.3",
"typescript": "^3.3.4000"
}
}

View file

@ -13,7 +13,8 @@
<meta name="msapplication-config" content="{{ asset('icons/browserconfig.xml') }}">
<meta name="theme-color" content="#ffffff">
<title>{% block title %}{{ partdb_title }}{% endblock %}</title>
<title>{% filter trim %}{% block title %}{{ partdb_title}}{% endblock %}{% endfilter %}</title>
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{% endblock %}
@ -88,7 +89,7 @@
<span class="ml-2 text-muted">{% trans %}barcode.scan{% endtrans %}</span>
</a>
<ul class="navbar-nav ml-3">
<ul class="navbar-nav ml-3" id="login-content">
<li class="nav-item dropdown">
<a href="#" class="dropdown-toggle link-anchor nav-link" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
{% if app.user %}<i class="fa fa-user" aria-hidden="true"></i>{% else %}<i class="far fa-user" aria-hidden="true"></i>{% endif %} <span class="caret"></span></a>
@ -104,10 +105,10 @@
{% endif %}
<li role="separator" class="dropdown-divider"></li>
<a class="dropdown-item disabled" href="#">{% trans %}user.language_select{% endtrans %}</a>
<a class="dropdown-item" href="{{ path(app.request.attributes.get('_route'),
<a class="dropdown-item" data-no-ajax href="{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')|merge({'_locale': 'en'})) }}">
{% trans %}language.english{% endtrans %}</a>
<a class="dropdown-item" href="{{ path(app.request.attributes.get('_route'),
<a class="dropdown-item" data-no-ajax href="{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')|merge({'_locale': 'de'})) }}">
{% trans %}language.german{% endtrans %}</a>
</ul>
@ -233,59 +234,6 @@
<div class="col-md-9 col-lg-10 offset-md-3 offset-lg-2 pl-0" id="main">
<div class="container-fluid mr-0 pr-0" id="content">
<div id="content-data">
{#
{if isset($messages)}
{assign "alert_style" "alert-info"}
{assign "alert_icon" "fas fa-info"}
{foreach $messages as $msg}
{if isset($msg.color) && $msg.color == "red"}
{assign "alert_style" "alert-danger"}
{assign "alert_icon" "fas fa-exclamation"}
{elseif isset($msg.color) && ( $msg.color == "green" || $msg.color == "darkgreen")}
{assign "alert_style" "alert-success"}
{assign "alert_icon" "fas fa-check"}
{elseif isset($msg.color) && ($msg.color == "yellow" || $msg.color == "orange")}
{assign "alert_style" "alert-warning"}
{assign "alert_icon" "fas fa-bell"}
{/if}
{/foreach}
<div class="alert {$alert_style}" id="messages">
<div class="row vertical-align">
<div class="col-md-1">
<i class="{$alert_icon} fa-5x" style="text-align: center; width: 1em;"></i>
</div>
<div class="col-md-11">
<div>
{if !empty($messages_div_title)}<h4>{$messages_div_title}</h4>{/if}
<form action="" method="post" class="no-progbar">
{foreach $messages as $msg}
{if isset($msg.text)}
{if isset($msg.strong) && $msg.strong}<strong>{/if}
{$msg.text nofilter}
{if isset($msg.strong) && $msg.strong}</strong>{/if}
{/if}
{if isset($msg.html)}
{$msg.html nofilter}
{/if}
{if !isset($msg.no_linebreak) || !$msg.no_linebreak}<br>{/if}
{/foreach}
{if !empty($reload_link)}
<a href="{$reload_link}">
<br>
<button class="btn btn-secondary">Seite neu laden</button>
</a>
{/if}
</form>
</div>
</div>
</div>
</div>
#}
{# Here will be the real content be injected#}
{% block content %}
@ -297,6 +245,26 @@
</div>
</div>
</main>
{# Modal for loading bar #}
<div class="modal border-primary" id="progressModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{% trans %}loading.caption{% endtrans %}
<small class="text-muted">{% trans %}loading.message{% endtrans %}</small></h5>
</div>
<div class="modal-body">
<div class="progress-bar progress-bar-striped active progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0"
aria-valuemax="100" style="width: 100%;">
<span>{% trans %}loading.bar{% endtrans %}</span>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
{{ encore_entry_script_tags('app') }}

View file

@ -18,6 +18,7 @@ Encore
* and one CSS file (e.g. app.css) if you JavaScript imports CSS.
*/
.addEntry('app', './assets/js/app.js')
//.addEntry('ajaxUI', './assets/ts_src/ajax_ui.ts')
//.addEntry('page1', './assets/js/page1.js')
//.addEntry('page2', './assets/js/page2.js')
@ -45,7 +46,7 @@ Encore
//.enableSassLoader()
// uncomment if you use TypeScript
//.enableTypeScriptLoader()
.enableTypeScriptLoader()
// uncomment if you're having problems with a jQuery plugin
.autoProvidejQuery()

View file

@ -650,6 +650,26 @@
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
"@types/bootstrap@^4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-4.3.0.tgz#4cac01617f56239a5146945a98bde64274838c35"
integrity sha512-v1BkpRVgNH9eXE+RtWFP1wh/+SAkPZaxHthS6umqf1sGV0tAvHdPHZpAOB+H74e91ElOxtS56dxbon+lXWk4AQ==
dependencies:
"@types/jquery" "*"
popper.js "^1.14.1"
"@types/jquery@*", "@types/jquery@^3.3.29":
version "3.3.29"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.29.tgz#680a2219ce3c9250483722fccf5570d1e2d08abd"
integrity sha512-FhJvBninYD36v3k6c+bVk1DSZwh7B5Dpb/Pyk3HKVsiohn0nhbefZZ+3JXbWQhFyt0MxSl2jRDdGQPHeOHFXrQ==
dependencies:
"@types/sizzle" "*"
"@types/js-cookie@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.1.tgz#aa6f6d5e5aaf7d97959e9fa938ac2501cf1a76f4"
integrity sha512-VIVurImEhQ95jxtjs8baVU5qCzVfwYfuMrpXwdRykJ5MCI5iY7/jB4cDSgwBVeYqeXrhT7GfJUwoDOmN0OMVCA==
"@types/node@*":
version "11.11.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.3.tgz#7c6b0f8eaf16ae530795de2ad1b85d34bf2f5c58"
@ -660,6 +680,11 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@types/sizzle@*":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
"@types/tapable@*":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
@ -1468,7 +1493,7 @@ chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@ -2381,7 +2406,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
enhanced-resolve@^4.1.0:
enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==
@ -3623,6 +3648,11 @@ jquery@>=1.7, jquery@^3.3.1:
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==
js-cookie@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
integrity sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s=
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
@ -4835,7 +4865,7 @@ png-js@>=0.1.0:
resolved "https://registry.yarnpkg.com/png-js/-/png-js-0.1.1.tgz#1cc7c212303acabe74263ec3ac78009580242d93"
integrity sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=
popper.js@^1.14.7:
popper.js@^1.14.1, popper.js@^1.14.7:
version "1.14.7"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e"
integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==
@ -5692,7 +5722,7 @@ selfsigned@^1.9.1:
dependencies:
node-forge "0.7.5"
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
@ -6316,6 +6346,17 @@ trim-right@^1.0.1:
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
ts-loader@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-5.3.3.tgz#8b4af042e773132d86b3c99ef0acf3b4d325f473"
integrity sha512-KwF1SplmOJepnoZ4eRIloH/zXL195F51skt7reEsS6jvDqzgc/YSbz9b8E07GxIUwLXdcD4ssrJu6v8CwaTafA==
dependencies:
chalk "^2.3.0"
enhanced-resolve "^4.0.0"
loader-utils "^1.0.2"
micromatch "^3.1.4"
semver "^5.0.1"
tslib@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
@ -6346,6 +6387,11 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.3.4000:
version "3.3.4000"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0"
integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"