mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 01:25:55 +02:00
Removed old frontend code
This commit is contained in:
parent
efb38173e6
commit
750bdc45d1
3 changed files with 1 additions and 1017 deletions
|
@ -17,15 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
* We recommend including the built version of this JavaScript file
|
||||
* (and its CSS file) in your base layout (base.html.twig).
|
||||
*/
|
||||
|
||||
// any CSS you require will output into a single css file (app.css in this case)
|
||||
|
||||
// Main CSS files
|
||||
import '../css/app.css';
|
||||
|
||||
|
@ -47,56 +38,3 @@ import "./tristate_checkboxes";
|
|||
|
||||
//Define jquery globally
|
||||
window.$ = window.jQuery = require("jquery")
|
||||
|
||||
|
||||
/**
|
||||
|
||||
require('bootstrap-select');
|
||||
require('jquery-form');
|
||||
require('corejs-typeahead/dist/typeahead.bundle.min');
|
||||
window.Bloodhound = require('corejs-typeahead/dist/bloodhound.js');
|
||||
|
||||
;
|
||||
|
||||
|
||||
|
||||
require('bootstrap-fileinput');
|
||||
|
||||
require('./datatables.js');
|
||||
|
||||
window.bootbox = require('bootbox');
|
||||
|
||||
require("marked");
|
||||
window.DOMPurify = require("dompurify");
|
||||
|
||||
// Includes required for tag input
|
||||
require('./tagsinput.js');
|
||||
require('../css/tagsinput.css');
|
||||
|
||||
//Tristate checkbox support
|
||||
require('./jquery.tristate.js');
|
||||
|
||||
require('darkmode-js');
|
||||
|
||||
//Equation rendering
|
||||
require('katex');
|
||||
window.renderMathInElement = require('katex/contrib/auto-render/auto-render').default;
|
||||
import 'katex/dist/katex.css';
|
||||
|
||||
window.ClipboardJS = require('clipboard');
|
||||
|
||||
require('../ts_src/ajax_ui');
|
||||
//import {ajaxUI} from "../ts_src/ajax_ui";
|
||||
|
||||
//window.ajaxUI = ajaxUI;
|
||||
|
||||
//Require all events;
|
||||
require('../ts_src/event_listeners');
|
||||
|
||||
|
||||
//Start AjaxUI AFTER all event has been registered
|
||||
//$(document).ready(ajaxUI.start());
|
||||
|
||||
*/
|
||||
|
||||
//console.log('Hello Webpack Encore! Edit me in assets/js/app.js');
|
|
@ -1,605 +0,0 @@
|
|||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 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 Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
protected BASE = "/";
|
||||
|
||||
private trees_filled : boolean = false;
|
||||
|
||||
private statePopped : boolean = false;
|
||||
|
||||
public xhr : XMLHttpRequest;
|
||||
|
||||
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(disabled : boolean = false)
|
||||
{
|
||||
if(disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.info("AjaxUI started!");
|
||||
|
||||
this.BASE = $("body").data("base-url");
|
||||
//If path doesn't end with slash, add it.
|
||||
if(this.BASE[this.BASE.length - 1] !== '/') {
|
||||
this.BASE = this.BASE + '/';
|
||||
}
|
||||
console.info("Base path is " + this.BASE);
|
||||
|
||||
//Show flash messages
|
||||
$(".toast").toast('show');
|
||||
|
||||
|
||||
/**
|
||||
* Save the XMLHttpRequest that jQuery used, to the class, so we can acess the responseURL property.
|
||||
* This is a work-around as long jQuery does not implement this property in its jQXHR objects.
|
||||
*/
|
||||
//@ts-ignore
|
||||
jQuery.ajaxSettings.xhr = function () {
|
||||
//@ts-ignore
|
||||
let xhr = new window.XMLHttpRequest();
|
||||
//Save the XMLHttpRequest to the class.
|
||||
ajaxUI.xhr = xhr;
|
||||
return xhr;
|
||||
};
|
||||
|
||||
|
||||
this.registerLinks();
|
||||
this.registerForm();
|
||||
this.fillTrees();
|
||||
|
||||
this.initDataTables();
|
||||
|
||||
//Trigger start event
|
||||
$(document).trigger("ajaxUI:start");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the trees with the given data.
|
||||
*/
|
||||
public fillTrees()
|
||||
{
|
||||
let categories = localStorage.getItem("tree_datasource_tree-categories");
|
||||
let devices = localStorage.getItem("tree_datasource_tree-devices");
|
||||
let tools = localStorage.getItem("tree_datasource_tree-tools");
|
||||
|
||||
if(categories == null) {
|
||||
categories = "categories";
|
||||
}
|
||||
|
||||
if(devices == null) {
|
||||
devices = "devices";
|
||||
}
|
||||
|
||||
if(tools == null) {
|
||||
tools = "tools";
|
||||
}
|
||||
|
||||
this.treeLoadDataSource("tree-categories", categories);
|
||||
this.treeLoadDataSource("tree-devices", devices);
|
||||
this.treeLoadDataSource("tree-tools", tools);
|
||||
|
||||
this.trees_filled = true;
|
||||
|
||||
//Register tree btns to expand all, or to switch datasource.
|
||||
$(".tree-btns").click(function (event) {
|
||||
event.preventDefault();
|
||||
$(this).parents("div.dropdown").removeClass('show');
|
||||
//$(this).closest(".dropdown-menu").removeClass('show');
|
||||
$(".dropdown-menu.show").removeClass("show");
|
||||
let mode = $(this).data("mode");
|
||||
let target = $(this).data("target");
|
||||
let text = $(this).text() + " \n<span class='caret'></span>"; //Add caret or it will be removed, when written into title
|
||||
|
||||
if (mode==="collapse") {
|
||||
// @ts-ignore
|
||||
$('#' + target).treeview('collapseAll', { silent: true });
|
||||
}
|
||||
else if(mode==="expand") {
|
||||
// @ts-ignore
|
||||
$('#' + target).treeview('expandAll', { silent: true });
|
||||
} else {
|
||||
localStorage.setItem("tree_datasource_" + target, mode);
|
||||
ajaxUI.treeLoadDataSource(target, mode);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given url into the tree with the given id.
|
||||
* @param target_id
|
||||
* @param datasource
|
||||
*/
|
||||
protected treeLoadDataSource(target_id, datasource) {
|
||||
let text : string = $(".tree-btns[data-mode='" + datasource + "']").html();
|
||||
text = text + " \n<span class='caret'></span>"; //Add caret or it will be removed, when written into title
|
||||
switch(datasource) {
|
||||
case "categories":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/categories');
|
||||
break;
|
||||
case "locations":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/locations');
|
||||
break;
|
||||
case "footprints":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/footprints');
|
||||
break;
|
||||
case "manufacturers":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/manufacturers');
|
||||
break;
|
||||
case "suppliers":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/suppliers');
|
||||
break;
|
||||
case "tools":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/tools');
|
||||
break;
|
||||
case "devices":
|
||||
ajaxUI.initTree("#" + target_id, 'tree/devices');
|
||||
ajaxUI.initTree("#" + target_id, 'tree/devices');
|
||||
break;
|
||||
}
|
||||
|
||||
$( "#" + target_id + "-title").html(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a treeview with data from the given url.
|
||||
* @param tree The Jquery selector for the tree (e.g. "#tree-tools")
|
||||
* @param url The url from where the data should be loaded
|
||||
*/
|
||||
public initTree(tree, url) {
|
||||
//let contextmenu_handler = this.onNodeContextmenu;
|
||||
$.getJSON(ajaxUI.BASE + url, function (data) {
|
||||
// @ts-ignore
|
||||
$(tree).treeview({
|
||||
data: data,
|
||||
enableLinks: false,
|
||||
showIcon: false,
|
||||
showBorder: true,
|
||||
searchResultBackColor: '#ffc107',
|
||||
searchResultColor: '#000',
|
||||
onNodeSelected: function(event, data) {
|
||||
if(data.href) {
|
||||
ajaxUI.navigateTo(data.href);
|
||||
}
|
||||
},
|
||||
//onNodeContextmenu: contextmenu_handler,
|
||||
expandIcon: "fas fa-plus fa-fw fa-treeview", collapseIcon: "fas fa-minus fa-fw fa-treeview"})
|
||||
.on('initialized', function() {
|
||||
$(this).treeview('collapseAll', { silent: true });
|
||||
|
||||
//Implement searching if needed.
|
||||
if($(this).data('treeSearch')) {
|
||||
let _this = this;
|
||||
let $search = $($(this).data('treeSearch'));
|
||||
$search.on( 'input', function() {
|
||||
$(_this).treeview('collapseAll', { silent: true });
|
||||
$(_this).treeview('search', [$search.val()]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register all links, for loading via ajax.
|
||||
*/
|
||||
public registerLinks()
|
||||
{
|
||||
// Unbind all old handlers, so the things are not executed multiple times.
|
||||
$('a').not(".link-external, [data-no-ajax], .page-link, [href^='javascript'], [href^='#']").unbind('click').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!');
|
||||
}
|
||||
|
||||
protected getFormOptions() : JQueryFormOptions
|
||||
{
|
||||
return {
|
||||
success: this.onAjaxComplete,
|
||||
beforeSerialize: function($form, options) : boolean {
|
||||
|
||||
//Update the content of textarea fields using CKEDITOR before submitting.
|
||||
//@ts-ignore
|
||||
if(typeof CKEDITOR !== 'undefined') {
|
||||
//@ts-ignore
|
||||
for (let name in CKEDITOR.instances) {
|
||||
//@ts-ignore
|
||||
CKEDITOR.instances[name].updateElement();
|
||||
}
|
||||
}
|
||||
|
||||
//Check every checkbox field, so that it will be submitted (only valid fields are submitted)
|
||||
$form.find("input[type=checkbox].tristate").prop('checked', true);
|
||||
|
||||
return true;
|
||||
},
|
||||
beforeSubmit: function (arr, $form, options) : boolean {
|
||||
//When data-with-progbar is specified, then show progressbar.
|
||||
if($form.data("with-progbar") != undefined) {
|
||||
ajaxUI.showProgressBar();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all forms for loading via ajax.
|
||||
*/
|
||||
public registerForm()
|
||||
{
|
||||
|
||||
let options = this.getFormOptions();
|
||||
|
||||
$('form').not('[data-no-ajax]').ajaxForm(options);
|
||||
|
||||
console.debug('Forms registered!');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Submits the given form via ajax.
|
||||
* @param form The form that will be submmitted.
|
||||
* @param btn The btn via which the form is submitted
|
||||
*/
|
||||
public submitForm(form, btn = null)
|
||||
{
|
||||
let options = ajaxUI.getFormOptions();
|
||||
|
||||
if(btn) {
|
||||
options.data = {};
|
||||
options.data[$(btn).attr('name')] = $(btn).attr('value');
|
||||
}
|
||||
|
||||
$(form).ajaxSubmit(options);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the progressbar
|
||||
*/
|
||||
public showProgressBar()
|
||||
{
|
||||
//Blur content background
|
||||
$('#content').addClass('loading-content');
|
||||
|
||||
// @ts-ignore
|
||||
$('#progressModal').modal({
|
||||
keyboard: false,
|
||||
backdrop: false,
|
||||
show: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the progressbar.
|
||||
*/
|
||||
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' || request.status == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Ignore ajax errors with 200 code (like the ones during 2FA authentication)
|
||||
if(request.status == 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Error getting the ajax data from server!");
|
||||
console.log(event);
|
||||
console.log(request);
|
||||
console.log(settings);
|
||||
|
||||
ajaxUI.hideProgressBar();
|
||||
|
||||
//Create error text
|
||||
let title = request.statusText;
|
||||
|
||||
switch(request.status) {
|
||||
case 500:
|
||||
title = 'Internal Server Error!';
|
||||
break;
|
||||
case 404:
|
||||
title = "Site not found!";
|
||||
break;
|
||||
case 403:
|
||||
title = "Permission denied!";
|
||||
break;
|
||||
}
|
||||
|
||||
var alert = bootbox.alert(
|
||||
{
|
||||
size: 'large',
|
||||
message: function() {
|
||||
let msg = "Error getting data from Server! <b>Status Code: " + request.status + "</b>";
|
||||
|
||||
msg += '<br><br><a class=\"btn btn-link\" data-toggle=\"collapse\" href=\"#iframe_div\" >' + 'Show response' + "</a>";
|
||||
msg += "<div class=\" collapse\" id='iframe_div'><iframe height='512' width='100%' id='iframe'></iframe></div>";
|
||||
|
||||
return msg;
|
||||
},
|
||||
title: title,
|
||||
callback: function () {
|
||||
//Remove blur
|
||||
$('#content').removeClass('loading-content');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//@ts-ignore
|
||||
alert.init(function (){
|
||||
var dstFrame = document.getElementById('iframe');
|
||||
//@ts-ignore
|
||||
var dstDoc = dstFrame.contentDocument || dstFrame.contentWindow.document;
|
||||
dstDoc.write(request.responseText);
|
||||
dstDoc.close();
|
||||
});
|
||||
|
||||
|
||||
|
||||
//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();
|
||||
|
||||
/* We need to do the url checking before the parseHTML, so that we dont get wrong url name, caused by scripts
|
||||
in the new content */
|
||||
// @ts-ignore
|
||||
let url = this.url;
|
||||
//Check if we were redirect to a new url, then we should use that as new url.
|
||||
if(ajaxUI.xhr.responseURL) {
|
||||
url = ajaxUI.xhr.responseURL;
|
||||
}
|
||||
|
||||
|
||||
//Parse response to DOM structure
|
||||
//We need to preserve javascript, so the table ca
|
||||
let dom = $.parseHTML(responseText, document, true);
|
||||
//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));
|
||||
|
||||
//Replace flash messages and show them
|
||||
$("#message-container").replaceWith($('#message-container', dom));
|
||||
$(".toast").toast('show');
|
||||
|
||||
//Set new title
|
||||
let title = extractTitle(responseText);
|
||||
document.title = title;
|
||||
|
||||
//Push to history, if we currently arent poping an old value.
|
||||
if(!ajaxUI.statePopped) {
|
||||
history.pushState(null, title, url);
|
||||
} else {
|
||||
//Clear pop state
|
||||
ajaxUI.statePopped = false;
|
||||
}
|
||||
|
||||
//Do things on the new dom
|
||||
ajaxUI.registerLinks();
|
||||
ajaxUI.registerForm();
|
||||
ajaxUI.initDataTables();
|
||||
|
||||
//Trigger reload event
|
||||
$(document).trigger("ajaxUI:reload");
|
||||
}
|
||||
|
||||
/**
|
||||
* Init all datatables marked with data-datatable based on their data-settings attribute.
|
||||
*/
|
||||
protected initDataTables()
|
||||
{
|
||||
//@ts-ignore
|
||||
$($.fn.DataTable.tables()).DataTable().fixedHeader.disable();
|
||||
//@ts-ignore
|
||||
$($.fn.DataTable.tables()).DataTable().destroy();
|
||||
|
||||
//Find all datatables and init it.
|
||||
let $tables = $('[data-datatable]');
|
||||
$.each($tables, function(index, table) {
|
||||
let $table = $(table);
|
||||
let settings = $table.data('settings');
|
||||
|
||||
//@ts-ignore
|
||||
var promise = $('#part_list').initDataTables(settings,
|
||||
{
|
||||
colReorder: true,
|
||||
responsive: true,
|
||||
"fixedHeader": { header: $(window).width() >= 768, //Only enable fixedHeaders on devices with big screen. Fixes scrolling issues on smartphones.
|
||||
headerOffset: $("#navbar").height()},
|
||||
"buttons": [ {
|
||||
"extend": 'colvis',
|
||||
'className': 'mr-2 btn-light',
|
||||
"text": "<i class='fa fa-cog'></i>"
|
||||
}],
|
||||
"select": $table.data('select') ?? false,
|
||||
"rowCallback": function( row, data, index ) {
|
||||
//Check if we have a level, then change color of this row
|
||||
if (data.level) {
|
||||
let style = "";
|
||||
switch(data.level) {
|
||||
case "emergency":
|
||||
case "alert":
|
||||
case "critical":
|
||||
case "error":
|
||||
style = "table-danger";
|
||||
break;
|
||||
case "warning":
|
||||
style = "table-warning";
|
||||
break;
|
||||
case "notice":
|
||||
style = "table-info";
|
||||
break;
|
||||
}
|
||||
|
||||
if (style){
|
||||
$(row).addClass(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Register links.
|
||||
promise.then(function() {
|
||||
ajaxUI.registerLinks();
|
||||
|
||||
//Set the correct title in the table.
|
||||
let title = $('#part-card-header-src');
|
||||
$('#part-card-header').html(title.html());
|
||||
$(document).trigger('ajaxUI:dt_loaded');
|
||||
|
||||
|
||||
if($table.data('part_table')) {
|
||||
//@ts-ignore
|
||||
$('#dt').on( 'select.dt deselect.dt', function ( e, dt, items ) {
|
||||
let selected_elements = dt.rows({selected: true});
|
||||
let count = selected_elements.count();
|
||||
|
||||
if(count > 0) {
|
||||
$('#select_panel').removeClass('d-none');
|
||||
} else {
|
||||
$('#select_panel').addClass('d-none');
|
||||
}
|
||||
|
||||
$('#select_count').text(count);
|
||||
|
||||
let selected_ids_string = selected_elements.data().map(function(value, index) {
|
||||
return value['id']; }
|
||||
).join(",");
|
||||
|
||||
$('#select_ids').val(selected_ids_string);
|
||||
|
||||
} );
|
||||
}
|
||||
|
||||
//Attach event listener to update links after new page selection:
|
||||
$('#dt').on('draw.dt column-visibility.dt', function() {
|
||||
ajaxUI.registerLinks();
|
||||
$(document).trigger('ajaxUI:dt_loaded');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
console.debug('Datatables inited.');
|
||||
}
|
||||
}
|
||||
|
||||
export let ajaxUI = new AjaxUI();
|
|
@ -1,349 +0,0 @@
|
|||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 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 Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {ajaxUI} from "./ajax_ui";
|
||||
import "bootbox";
|
||||
import "marked";
|
||||
import * as marked from "marked";
|
||||
import {parse} from "marked";
|
||||
import * as ZXing from "@zxing/library";
|
||||
|
||||
/************************************
|
||||
*
|
||||
* In this file all the functions that has to be called using AjaxUIoperation are registered.
|
||||
* You can use AjaxUI:start and AjaxUI:reload events.
|
||||
*
|
||||
***********************************/
|
||||
|
||||
// Add bootstrap treeview on divs with data-tree-data attribute
|
||||
$(document).on("ajaxUI:start ajaxUI:reload", function() {
|
||||
$("[data-tree-data]").each(function(index, element) {
|
||||
let data = $(element).data('treeData');
|
||||
|
||||
//@ts-ignore
|
||||
$(element).treeview({
|
||||
data: data,
|
||||
enableLinks: false,
|
||||
showIcon: false,
|
||||
showBorder: true,
|
||||
searchResultBackColor: '#ffc107',
|
||||
searchResultColor: '#000',
|
||||
showTags: true,
|
||||
//@ts-ignore
|
||||
wrapNode: true,
|
||||
//@ts-ignore
|
||||
tagsClass: 'badge badge-secondary badge-pill pull-right',
|
||||
expandIcon: "fas fa-plus fa-fw fa-treeview", collapseIcon: "fas fa-minus fa-fw fa-treeview",
|
||||
onNodeSelected: function(event, data) {
|
||||
if(data.href) {
|
||||
ajaxUI.navigateTo(data.href);
|
||||
}
|
||||
}
|
||||
}).on('initialized', function() {
|
||||
$(this).treeview('collapseAll', { silent: true });
|
||||
let selected = $(this).treeview('getSelected');
|
||||
$(this).treeview('revealNode', [ selected, {silent: true } ]);
|
||||
|
||||
//Implement searching if needed.
|
||||
if($(this).data('treeSearch')) {
|
||||
let _this = this;
|
||||
let $search = $($(this).data('treeSearch'));
|
||||
$search.on( 'input', function() {
|
||||
$(_this).treeview('collapseAll', { silent: true });
|
||||
$(_this).treeview('search', [$search.val()]);
|
||||
});
|
||||
}
|
||||
|
||||
//Add tree expand and reduce buttons if needed.
|
||||
if($(this).data('treeReduce')) {
|
||||
let _this = this;
|
||||
let $btn = $($(this).data('treeReduce'));
|
||||
$btn.click(function () {
|
||||
$(_this).treeview('collapseAll');
|
||||
});
|
||||
}
|
||||
if($(this).data('treeExpand')) {
|
||||
let _this = this;
|
||||
let $btn = $($(this).data('treeExpand'));
|
||||
$btn.click(function () {
|
||||
$(_this).treeview('expandAll');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("ajaxUI:start ajaxUI:reload", function() {
|
||||
$("[data-delete-form]").unbind('submit').submit(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
let form = this;
|
||||
|
||||
//Get the submit button
|
||||
let btn = document.activeElement;
|
||||
|
||||
let title = $(this).data("title");
|
||||
let message = $(this).data("message");
|
||||
|
||||
bootbox.confirm({
|
||||
message: message, title: title, callback: function (result) {
|
||||
//If the dialog was confirmed, then submit the form.
|
||||
if (result) {
|
||||
ajaxUI.submitForm(form, btn);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
//Register for forms with delete-buttons
|
||||
$("[data-delete-btn]").parents('form').unbind('submit').submit(function (event) {
|
||||
event.preventDefault();
|
||||
let form = this;
|
||||
//Get the submit button
|
||||
let btn = document.activeElement;
|
||||
|
||||
let title = $(btn).data("title");
|
||||
let message = $(btn).data("message");
|
||||
|
||||
//If not the button with the message was pressed, then simply submit the form.
|
||||
if(!btn.hasAttribute('data-delete-btn')) {
|
||||
ajaxUI.submitForm(form, btn);
|
||||
}
|
||||
|
||||
bootbox.confirm({
|
||||
message: message, title: title, callback: function (result) {
|
||||
//If the dialog was confirmed, then submit the form.
|
||||
if (result) {
|
||||
ajaxUI.submitForm(form, btn);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(document).on("ajaxUI:start ajaxUI:reload", function() {
|
||||
//@ts-ignore
|
||||
$(".tristate").tristate( {
|
||||
checked: "true",
|
||||
unchecked: "false",
|
||||
indeterminate: "indeterminate",
|
||||
});
|
||||
|
||||
$('.permission_multicheckbox:checkbox').change(function() {
|
||||
//Find the other checkboxes in this row, and change their value
|
||||
var $row = $(this).parents('tr');
|
||||
|
||||
//@ts-ignore
|
||||
var new_state = $(this).tristate('state');
|
||||
|
||||
//@ts-ignore
|
||||
$('.tristate:checkbox', $row).tristate('state', new_state);
|
||||
});
|
||||
});
|
||||
|
||||
//Re initialize fileinputs on reload
|
||||
$(document).on("ajaxUI:reload", function () {
|
||||
//@ts-ignore
|
||||
$(".file").fileinput();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* This listener keeps track of which tab is currently selected (using hash and localstorage) and will try to open
|
||||
* that tab on reload. That means that if the user changes something, he does not have to switch back to the tab
|
||||
* where he was before submit.
|
||||
*/
|
||||
$(document).on("ajaxUI:reload ajaxUI:start", function () {
|
||||
//Determine which tab should be shown (use hash if specified, otherwise use localstorage)
|
||||
var $activeTab = null;
|
||||
if (location.hash) {
|
||||
$activeTab = $('a[href=\'' + location.hash + '\']');
|
||||
} else if(localStorage.getItem('activeTab')) {
|
||||
$activeTab = $('a[href="' + localStorage.getItem('activeTab') + '"]');
|
||||
}
|
||||
|
||||
if($activeTab) {
|
||||
//Findout if the tab has any parent tab we have to show before
|
||||
var parents = $($activeTab).parents('.tab-pane');
|
||||
parents.each(function(n) {
|
||||
$('a[href="#' + $(this).attr('id') + '"]').tab('show');
|
||||
});
|
||||
//Finally show the active tab itself
|
||||
$activeTab.tab('show');
|
||||
}
|
||||
|
||||
$('body').on('click', 'a[data-toggle=\'tab\']', function (e) {
|
||||
e.preventDefault()
|
||||
var tab_name = this.getAttribute('href')
|
||||
if (history.replaceState) {
|
||||
history.replaceState(null, null, tab_name)
|
||||
}
|
||||
else {
|
||||
location.hash = tab_name
|
||||
}
|
||||
localStorage.setItem('activeTab', tab_name)
|
||||
|
||||
$(this).tab('show');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Load the higher resolution version of hover pictures.
|
||||
*/
|
||||
$(document).on("ajaxUI:reload ajaxUI:start ajaxUI:dt_loaded", function () {
|
||||
|
||||
$('.hoverpic[data-thumbnail]').popover({
|
||||
html: true,
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
content: function () {
|
||||
return '<img class="img-fluid" src="' + $(this).data('thumbnail') + '" />';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//Register typeaheads
|
||||
$(document).on("ajaxUI:reload ajaxUI:start attachment:create", function () {
|
||||
$('input[data-autocomplete]').each(function() {
|
||||
//@ts-ignore
|
||||
var engine = new Bloodhound({
|
||||
//@ts-ignore
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(''),
|
||||
//@ts-ignore
|
||||
queryTokenizer: Bloodhound.tokenizers.obj.whitespace(''),
|
||||
remote: {
|
||||
url: $(this).data('autocomplete'),
|
||||
wildcard: 'QUERY'
|
||||
}
|
||||
});
|
||||
|
||||
//@ts-ignore
|
||||
$(this).typeahead({
|
||||
hint: true,
|
||||
highlight: true,
|
||||
minLength: 1
|
||||
},
|
||||
{
|
||||
name: 'states',
|
||||
source: engine,
|
||||
limit: 250,
|
||||
templates: {
|
||||
suggestion: function(data) {
|
||||
if (typeof data === "string") {
|
||||
return "<div>" + data + "</div>";
|
||||
} else if(typeof data === "object" && typeof data.image === "string") {
|
||||
return "<div class='row m-0'><div class='col-2 pl-0 pr-1'><img class='typeahead-image' src='" + data.image + "'/></div><div class='col-10'>" + data.name + "</div></div>"
|
||||
}
|
||||
},
|
||||
},
|
||||
display: 'name',
|
||||
});
|
||||
|
||||
//Make the typeahead input fill the container (remove block-inline attr)
|
||||
$(this).parent(".twitter-typeahead").css('display', 'block');
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
$(document).on("ajaxUI:start ajaxUI:reload attachment:create", function() {
|
||||
let updater = function() {
|
||||
//@ts-ignore
|
||||
let selected_option = $(this)[0].selectedOptions[0];
|
||||
let filter_string = $(selected_option).data('filetype_filter');
|
||||
//Find associated file input
|
||||
|
||||
let $row = $(this).parents('tr');
|
||||
//Set accept filter
|
||||
$('input[type="file"]', $row).prop('accept', filter_string);
|
||||
};
|
||||
|
||||
//Register a change handler on all change listeners, and update it when the events are triggered
|
||||
$('select.attachment_type_selector').change(updater).each(updater);
|
||||
});
|
||||
|
||||
|
||||
$(document).on("ajaxUI:start ajaxUI:reload", function() {
|
||||
function setTooltip(btn, message) {
|
||||
$(btn).tooltip('hide')
|
||||
.attr('data-original-title', message)
|
||||
.tooltip('show');
|
||||
}
|
||||
|
||||
function hideTooltip(btn) {
|
||||
setTimeout(function() {
|
||||
$(btn).tooltip('hide');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
var clipboard = new ClipboardJS('.btn[data-clipboard-target], .btn[data-clipboard-text], .btn[data-clipboard-action]');
|
||||
clipboard.on('success', function(e) {
|
||||
setTooltip(e.trigger, 'Copied!');
|
||||
hideTooltip(e.trigger);
|
||||
});
|
||||
|
||||
clipboard.on('error', function(e) {
|
||||
setTooltip(e.trigger, 'Failed!');
|
||||
hideTooltip(e.trigger);
|
||||
});
|
||||
});
|
||||
|
||||
//Register U2F on page reload too...
|
||||
$(document).on("ajaxUI:reload", function() {
|
||||
//@ts-ignore
|
||||
window.u2fauth.ready(function () {
|
||||
const form = document.getElementById('u2fForm')
|
||||
if (!form) {
|
||||
return
|
||||
}
|
||||
const type = form.dataset.action
|
||||
|
||||
if (type === 'auth') {
|
||||
//@ts-ignore
|
||||
u2fauth.authenticate()
|
||||
} else if (type === 'reg' && form.addEventListener) {
|
||||
form.addEventListener('submit', function (event) {
|
||||
event.preventDefault()
|
||||
//@ts-ignore
|
||||
u2fauth.register()
|
||||
}, false)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
//Need for proper body padding, with every navbar height
|
||||
$(window).resize(function () {
|
||||
let height : number = $('#navbar').height() + 10;
|
||||
$('body').css('padding-top', height);
|
||||
$('#fixed-sidebar').css('top', height);
|
||||
});
|
||||
|
||||
$(window).on('load', function () {
|
||||
let height : number = $('#navbar').height() + 10;
|
||||
$('body').css('padding-top', height);
|
||||
$('#fixed-sidebar').css('top', height);
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue