parent
25a4126f6d
commit
a2dbc73130
@ -0,0 +1,891 @@
|
||||
/**
|
||||
* @summary altEditor
|
||||
* @description Lightweight editor for DataTables
|
||||
* @version 2.0
|
||||
* @file dataTables.editor.free.js
|
||||
* @author kingkode (www.kingkode.com)
|
||||
* Modified by: Kasper Olesen (https://github.com/KasperOlesen), Luca Vercelli (https://github.com/luca-vercelli), Zack Hable (www.cobaltdevteam.com)
|
||||
* @contact www.kingkode.com/contact
|
||||
* @contact zack@cobaltdevteam.com
|
||||
* @copyright Copyright 2016 Kingkode
|
||||
*
|
||||
* This source file is free software, available under the following license: MIT
|
||||
* license
|
||||
*
|
||||
* This source file 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 license files for details.
|
||||
*
|
||||
*
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['jquery', 'datatables.net'], function ($) {
|
||||
return factory($, window, document);
|
||||
});
|
||||
}
|
||||
else if (typeof exports === 'object') {
|
||||
// CommonJS
|
||||
module.exports = function (root, $) {
|
||||
if (!root) {
|
||||
root = window;
|
||||
}
|
||||
|
||||
if (!$ || !$.fn.dataTable) {
|
||||
$ = require('datatables.net')(root, $).$;
|
||||
}
|
||||
|
||||
return factory($, root, root.document);
|
||||
};
|
||||
}
|
||||
else {
|
||||
// Browser
|
||||
factory(jQuery, window, document);
|
||||
}
|
||||
})
|
||||
(function ($, window, document, undefined) {
|
||||
'use strict';
|
||||
var DataTable = $.fn.dataTable;
|
||||
|
||||
var _instance = 0;
|
||||
|
||||
/**
|
||||
* altEditor provides modal editing of records for Datatables
|
||||
*
|
||||
* @class altEditor
|
||||
* @constructor
|
||||
* @param {object}
|
||||
* oTD DataTables settings object
|
||||
* @param {object}
|
||||
* oConfig Configuration object for altEditor
|
||||
*/
|
||||
var altEditor = function (dt, opts) {
|
||||
if (!DataTable.versionCheck || !DataTable.versionCheck('1.10.8')) {
|
||||
throw ("Warning: altEditor requires DataTables 1.10.8 or greater");
|
||||
}
|
||||
|
||||
// User and defaults configuration object
|
||||
this.c = $.extend(true, {}, DataTable.defaults.altEditor,
|
||||
altEditor.defaults, opts);
|
||||
|
||||
/**
|
||||
* @namespace Settings object which contains customisable information
|
||||
* for altEditor instance
|
||||
*/
|
||||
this.s = {
|
||||
/** @type {DataTable.Api} DataTables' API instance */
|
||||
dt: new DataTable.Api(dt),
|
||||
|
||||
/** @type {String} Unique namespace for events attached to the document */
|
||||
namespace: '.altEditor' + (_instance++)
|
||||
};
|
||||
|
||||
/**
|
||||
* @namespace Common and useful DOM elements for the class instance
|
||||
*/
|
||||
this.dom = {
|
||||
/** @type {jQuery} altEditor handle */
|
||||
modal: $('<div class="dt-altEditor-handle"/>'),
|
||||
};
|
||||
|
||||
/* Constructor logic */
|
||||
this._constructor();
|
||||
}
|
||||
|
||||
$.extend(
|
||||
altEditor.prototype,
|
||||
{
|
||||
/***************************************************************
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Constructor * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialise the RowReorder instance
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_constructor: function () {
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
|
||||
if (dt.settings()[0].oInit.onAddRow)
|
||||
that.onAddRow = dt.settings()[0].oInit.onAddRow;
|
||||
if (dt.settings()[0].oInit.onDeleteRow)
|
||||
that.onDeleteRow = dt.settings()[0].oInit.onDeleteRow;
|
||||
if (dt.settings()[0].oInit.onEditRow)
|
||||
that.onEditRow = dt.settings()[0].oInit.onEditRow;
|
||||
|
||||
this._setup();
|
||||
|
||||
dt.on('destroy.altEditor', function () {
|
||||
dt.off('.altEditor');
|
||||
$(dt.table().body()).off(that.s.namespace);
|
||||
$(document.body).off(that.s.namespace);
|
||||
});
|
||||
},
|
||||
|
||||
/***************************************************************
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Private methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/**
|
||||
* Setup dom and bind button actions
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_setup: function () {
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
this.random_id = ("" + Math.random()).replace(".", "");
|
||||
var modal_id = `altEditor-modal-${this.random_id}`;
|
||||
this.modal_selector = '#' + modal_id;
|
||||
this.language = DataTable.settings.values().next().value.oLanguage.altEditor || {};
|
||||
this.language.modalClose = this.language.modalClose || 'Close';
|
||||
this.language.edit = this.language.edit || {};
|
||||
this.language.edit = { title: this.language.edit.title || 'Edit record',
|
||||
button: this.language.edit.button || 'Edit'
|
||||
};
|
||||
this.language.delete = this.language.delete || {};
|
||||
this.language.delete = { title: this.language.delete.title || 'Delete record',
|
||||
button: this.language.delete.button || 'Delete' };
|
||||
this.language.add = this.language.add || {};
|
||||
this.language.add = { title: this.language.add.title || 'Add record',
|
||||
button: this.language.add.button || 'Add'
|
||||
};
|
||||
this.language.success = this.language.success || 'Success!';
|
||||
this.language.error = this.language.error || {};
|
||||
this.language.error = { message: this.language.error.message || 'There was an unknown error!',
|
||||
label: this.language.error.label || 'Error!',
|
||||
responseCode: this.language.error.responseCode || 'Response code: ',
|
||||
required: this.language.error.required || 'Field is required',
|
||||
unique: this.language.error.unique || 'Duplicated field'
|
||||
};
|
||||
var modal = '<div class="modal fade" id="' + modal_id + '" tabindex="-1" role="dialog">' +
|
||||
'<div class="modal-dialog">' +
|
||||
'<div class="modal-content">' +
|
||||
'<div class="modal-header">' +
|
||||
'<h4 style="padding-top: 1rem;padding-left: 1rem;" class="modal-title"></h4>' +
|
||||
'<button style="margin: initial;" type="button" class="close" data-dismiss="modal" aria-label="' + this.language.modalClose + '">' +
|
||||
'<span aria-hidden="true">×</span></button>' +
|
||||
'</div>' +
|
||||
'<div class="modal-body">' +
|
||||
'<p></p>' +
|
||||
'</div>' +
|
||||
'<div class="modal-footer">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
// add modal
|
||||
$('body').append(modal);
|
||||
|
||||
// add Edit Button
|
||||
if (dt.button('edit:name')) {
|
||||
dt.button('edit:name').action(function (e, dt, node, config) {
|
||||
that._openEditModal();
|
||||
|
||||
$(`#altEditor-edit-form-${that.random_id}`)
|
||||
.off('submit')
|
||||
.on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
that._editRowData();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// add Delete Button
|
||||
if (dt.button('delete:name')) {
|
||||
dt.button('delete:name').action(function (e, dt, node, config) {
|
||||
that._openDeleteModal();
|
||||
|
||||
$(`#altEditor-delete-form-${that.random_id}`)
|
||||
.off('submit')
|
||||
.on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
that._deleteRow();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// add Add Button
|
||||
if (dt.button('add:name')) {
|
||||
dt.button('add:name').action(function (e, dt, node, config) {
|
||||
that._openAddModal();
|
||||
|
||||
$(`#altEditor-add-form-${that.random_id}`)
|
||||
.off('submit')
|
||||
.on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
that._addRowData();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// bind 'unique' error messages
|
||||
$(this.modal_selector).bind('input', '[data-unique]', function(elm) {
|
||||
if ($(elm.target).attr('data-unique') == null || $(elm.target).attr('data-unique') === 'false') {
|
||||
return;
|
||||
}
|
||||
var target = $(elm.target);
|
||||
var colData = dt.column("th:contains('" + target.attr("name") + "')").data();
|
||||
// go through each item in this column
|
||||
var selectedCellData = null;
|
||||
if (dt.row({selected: true}).index() != null)
|
||||
selectedCellData = dt.cell(dt.row({selected: true}).index(), dt.column("th:contains('" + target.attr("name") + "')").index()).data();
|
||||
elm.target.setCustomValidity('');
|
||||
for (var j in colData) {
|
||||
// if the element is in the column and its not the selected one then its not unique
|
||||
if (target.val() == colData[j] && colData[j] != selectedCellData) {
|
||||
elm.target.setCustomValidity(that.language.error.unique);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add Refresh button
|
||||
if (this.s.dt.button('refresh:name')) {
|
||||
this.s.dt.button('refresh:name').action(function (e, dt, node, config) {
|
||||
if (dt.ajax && dt.ajax.url()) {
|
||||
dt.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit an event on the DataTable for listeners
|
||||
*
|
||||
* @param {string}
|
||||
* name Event name
|
||||
* @param {array}
|
||||
* args Event arguments
|
||||
* @private
|
||||
*/
|
||||
_emitEvent: function (name, args) {
|
||||
this.s.dt.iterator('table', function (ctx, i) {
|
||||
$(ctx.nTable).triggerHandler(name + '.dt', args);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open Edit Modal for selected row
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_openEditModal: function () {
|
||||
|
||||
var dt = this.s.dt;
|
||||
var adata = dt.rows({
|
||||
selected: true
|
||||
});
|
||||
|
||||
var columnDefs = this.completeColumnDefs();
|
||||
var data = this.createDialog(columnDefs, this.language.edit.title, this.language.edit.button,
|
||||
this.language.modalClose, 'editRowBtn', 'altEditor-edit-form');
|
||||
|
||||
var selector = this.modal_selector;
|
||||
|
||||
for (var j in columnDefs) {
|
||||
var arrIndex = "['" + columnDefs[j].name.toString().split(".").join("']['") + "']";
|
||||
var selectedValue = eval("adata.data()[0]" + arrIndex);
|
||||
var jquerySelector = "#" + columnDefs[j].name.toString().replace(/\./g, "\\.");
|
||||
$(selector).find(jquerySelector).val(this._quoteattr(selectedValue));
|
||||
$(selector).find(jquerySelector).trigger("change"); // required by select2
|
||||
}
|
||||
|
||||
$(selector + ' input[0]').focus();
|
||||
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:edit_dialog_opened");
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for "Edit" button
|
||||
*/
|
||||
_editRowData: function () {
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
|
||||
// Complete new row data
|
||||
var rowDataArray = {};
|
||||
|
||||
var adata = dt.rows({
|
||||
selected: true
|
||||
});
|
||||
|
||||
// Getting the inputs from the edit-modal
|
||||
$(`form[name="altEditor-edit-form-${this.random_id}"] *`).filter(':input').each(function (i) {
|
||||
rowDataArray[$(this).attr('id')] = $(this).val();
|
||||
});
|
||||
|
||||
//Getting the textArea from the modal
|
||||
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter('textarea').each(function (i) {
|
||||
rowDataArray[$(this).attr('id')] = $(this).val();
|
||||
});
|
||||
|
||||
console.log(rowDataArray); //DEBUG
|
||||
|
||||
that.onEditRow(that,
|
||||
rowDataArray,
|
||||
function(data,b,c,d,e){ that._editRowCallback(data,b,c,d,e); },
|
||||
function(data){ that._errorCallback(data);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open Delete Modal for selected row
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_openDeleteModal: function () {
|
||||
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
var adata = dt.rows({
|
||||
selected: true
|
||||
});
|
||||
var columnDefs = this.completeColumnDefs();
|
||||
const formName = 'altEditor-delete-form-' + this.random_id;
|
||||
|
||||
// TODO
|
||||
// we should use createDialog()
|
||||
// var data = this.createDialog(columnDefs, this.language.delete.title, this.language.delete.button,
|
||||
// this.language.modalClose, 'deleteRowBtn', 'altEditor-delete-form');
|
||||
|
||||
// Building delete-modal
|
||||
var data = "";
|
||||
|
||||
for (var j in columnDefs) {
|
||||
if (columnDefs[j].type.indexOf("hidden") >= 0) {
|
||||
data += "<input type='hidden' id='" + columnDefs[j].title + "' value='" + adata.data()[0][columnDefs[j].name] + "'></input>";
|
||||
}
|
||||
else {
|
||||
data += "<div style='margin-left: initial;margin-right: initial;' class='form-group row'><label for='"
|
||||
+ that._quoteattr(columnDefs[j].name)
|
||||
+ "'>"
|
||||
+ columnDefs[j].title
|
||||
+ ": </label> <input type='hidden' id='"
|
||||
+ that._quoteattr(columnDefs[j].title)
|
||||
+ "' name='"
|
||||
+ that._quoteattr(columnDefs[j].title)
|
||||
+ "' placeholder='"
|
||||
+ that._quoteattr(columnDefs[j].title)
|
||||
+ "' style='overflow:hidden' class='form-control' value='"
|
||||
+ that._quoteattr(adata.data()[0][columnDefs[j].name]) + "' >"
|
||||
+ adata.data()[0][columnDefs[j].name]
|
||||
+ "</input></div>";
|
||||
}
|
||||
}
|
||||
|
||||
var selector = this.modal_selector;
|
||||
$(selector).on('show.bs.modal', function () {
|
||||
var btns = '<button type="button" data-content="remove" class="btn btn-default" data-dismiss="modal">' + that.language.modalClose + '</button>' +
|
||||
'<button type="submit" data-content="remove" class="btn btn-danger" id="deleteRowBtn">' + that.language.delete.button + '</button>';
|
||||
$(selector).find('.modal-title').html(that.language.delete.title);
|
||||
$(selector).find('.modal-body').html(data);
|
||||
$(selector).find('.modal-footer').html(btns);
|
||||
const modalContent = $(selector).find('.modal-content');
|
||||
if (modalContent.parent().is('form')) {
|
||||
modalContent.parent().attr('name', formName);
|
||||
modalContent.parent().attr('id', formName);
|
||||
} else {
|
||||
modalContent.wrap("<form name='" + formName + "' id='" + formName + "' role='form'></form>");
|
||||
}
|
||||
});
|
||||
|
||||
$(selector).modal('show');
|
||||
$(selector + ' input[0]').focus();
|
||||
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:delete_dialog_opened");
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for "Delete" button
|
||||
*/
|
||||
_deleteRow: function () {
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
|
||||
var jsonDataArray = {};
|
||||
|
||||
var adata = dt.rows({
|
||||
selected: true
|
||||
});
|
||||
|
||||
// Getting the IDs and Values of the tablerow
|
||||
for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
|
||||
// .data is the attribute name, if any; .idx is the column index, so it should always exists
|
||||
var name = dt.context[0].aoColumns[i].data ? dt.context[0].aoColumns[i].data :
|
||||
dt.context[0].aoColumns[i].mData ? dt.context[0].aoColumns[i].mData :
|
||||
dt.context[0].aoColumns[i].idx;
|
||||
jsonDataArray[name] = adata.data()[0][name];
|
||||
}
|
||||
that.onDeleteRow(that,
|
||||
jsonDataArray,
|
||||
function(data){ that._deleteRowCallback(data); },
|
||||
function(data){ that._errorCallback(data);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open Add Modal for selected row
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_openAddModal: function () {
|
||||
var dt = this.s.dt;
|
||||
var columnDefs = this.completeColumnDefs();
|
||||
var data = this.createDialog(columnDefs, this.language.add.title, this.language.add.button,
|
||||
this.language.modalClose, 'addRowBtn', 'altEditor-add-form');
|
||||
|
||||
var selector = this.modal_selector;
|
||||
$(selector + ' input[0]').focus();
|
||||
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:add_dialog_opened");
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete DataTable.context[0].aoColumns with default values
|
||||
*/
|
||||
completeColumnDefs: function () {
|
||||
var columnDefs = [];
|
||||
var dt = this.s.dt;
|
||||
for (var i in dt.context[0].aoColumns) {
|
||||
var obj = dt.context[0].aoColumns[i];
|
||||
columnDefs[i] = {
|
||||
title: obj.sTitle,
|
||||
name: (obj.data ? obj.data : obj.mData),
|
||||
type: (obj.type ? obj.type : 'text'),
|
||||
rows: (obj.rows ? obj.rows : '5'),
|
||||
cols: (obj.cols ? obj.cols : '30'),
|
||||
options: (obj.options ? obj.options : []),
|
||||
readonly: (obj.readonly ? obj.readonly : false),
|
||||
disabled: (obj.disabled ? obj.disabled : false),
|
||||
required: (obj.required ? obj.required : false),
|
||||
msg: (obj.errorMsg ? obj.errorMsg : ''), // FIXME no more used
|
||||
hoverMsg: (obj.hoverMsg ? obj.hoverMsg : ''),
|
||||
pattern: (obj.pattern ? obj.pattern : '.*'),
|
||||
special: (obj.special ? obj.special : ''),
|
||||
unique: (obj.unique ? obj.unique : false),
|
||||
uniqueMsg: (obj.uniqueMsg ? obj.uniqueMsg : ''), // FIXME no more used
|
||||
maxLength: (obj.maxLength ? obj.maxLength : false),
|
||||
multiple: (obj.multiple ? obj.multiple : false),
|
||||
select2: (obj.select2 ? obj.select2 : false),
|
||||
datepicker: (obj.datepicker ? obj.datepicker : false),
|
||||
datetimepicker: (obj.datetimepicker ? obj.datetimepicker : false),
|
||||
editorOnChange: (obj.editorOnChange ? obj.editorOnChange : null)
|
||||
}
|
||||
}
|
||||
return columnDefs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create both Edit and Add dialogs
|
||||
* @param columnDefs as returned by completeColumnDefs()
|
||||
*/
|
||||
createDialog: function(columnDefs, title, buttonCaption, closeCaption, buttonClass, formName) {
|
||||
formName = [formName, this.random_id].join('-');
|
||||
var data = "";
|
||||
for (var j in columnDefs) {
|
||||
|
||||
//handle hidden fields
|
||||
if (columnDefs[j].type.indexOf("hidden") >= 0) {
|
||||
data += "<input type='hidden' id='" + columnDefs[j].name + "' ></input>";
|
||||
}
|
||||
else {
|
||||
// handle fields that are visible to the user
|
||||
data += "<div style='margin-left: initial;margin-right: initial;' class='form-group row' id='alteditor-row-" + this._quoteattr(columnDefs[j].name) +"'>";
|
||||
data += "<div class='col-sm-3 col-md-3 col-lg-3 text-right' style='padding-top:4px;'>";
|
||||
data += "<label for='" + columnDefs[j].name + "'>" + columnDefs[j].title + ":</label></div>";
|
||||
data += "<div class='col-sm-8 col-md-8 col-lg-8'>";
|
||||
|
||||
// Adding readonly-fields
|
||||
if (columnDefs[j].type.indexOf("readonly") >= 0) {
|
||||
// type=readonly is deprecated, kept for backward compatibility
|
||||
data += "<input type='text' readonly id='"
|
||||
+ this._quoteattr(columnDefs[j].name)
|
||||
+ "' name='"
|
||||
+ this._quoteattr(columnDefs[j].title)
|
||||
+ "' placeholder='"
|
||||
+ this._quoteattr(columnDefs[j].title)
|
||||
+ "' style='overflow:hidden' class='form-control form-control-sm' value=''>";
|
||||
}
|
||||
// Adding select-fields
|
||||
else if (columnDefs[j].type.indexOf("select") >= 0) {
|
||||
var options = "";
|
||||
var optionsArray = columnDefs[j].options;
|
||||
if (optionsArray.length > 0) {
|
||||
// array-style select or select2
|
||||
for (var i = 0; i < optionsArray.length; i++) {
|
||||
options += "<option value='" + this._quoteattr(optionsArray[i])
|
||||
+ "'>" + optionsArray[i] + "</option>";
|
||||
}
|
||||
} else {
|
||||
// object-style select or select2
|
||||
for (var x in optionsArray) {
|
||||
options += "<option value='" + this._quoteattr(x) + "' >"
|
||||
+ optionsArray[x] + "</option>";
|
||||
}
|
||||
}
|
||||
data += "<select class='form-control" + (columnDefs[j].select2 ? ' select2' : '')
|
||||
+ "' id='" + this._quoteattr(columnDefs[j].name)
|
||||
+ "' name='" + this._quoteattr(columnDefs[j].title) + "' "
|
||||
+ (columnDefs[j].multiple ? ' multiple ' : '')
|
||||
+ (columnDefs[j].readonly ? ' readonly ' : '')
|
||||
+ (columnDefs[j].disabled ? ' disabled ' : '')
|
||||
+ (columnDefs[j].required ? ' required ' : '')
|
||||
+ ">" + options
|
||||
+ "</select>";
|
||||
}
|
||||
//Adding Text Area
|
||||
else if (columnDefs[j].type.indexOf("textarea") >= 0)
|
||||
{
|
||||
data += "<textarea id='" + this._quoteattr(columnDefs[j].name)
|
||||
+ "' name='" + this._quoteattr(columnDefs[j].title)
|
||||
+ "'rows='" + this._quoteattr(columnDefs[j].rows)
|
||||
+ "' cols='"+ this._quoteattr(columnDefs[j].cols)
|
||||
+ "'>"
|
||||
+ "</textarea>";
|
||||
}
|
||||
// Adding text-inputs and errorlabels, but also new HTML5 typees (email, color, ...)
|
||||
else {
|
||||
data += "<input type='" + this._quoteattr(columnDefs[j].type)
|
||||
+ "' id='" + this._quoteattr(columnDefs[j].name)
|
||||
+ "' pattern='" + this._quoteattr(columnDefs[j].pattern)
|
||||
+ "' title='" + this._quoteattr(columnDefs[j].hoverMsg)
|
||||
+ "' name='" + this._quoteattr(columnDefs[j].title)
|
||||
+ "' placeholder='" + this._quoteattr(columnDefs[j].title)
|
||||
+ "' data-special='" + this._quoteattr(columnDefs[j].special)
|
||||
+ "' data-errorMsg='" + this._quoteattr(columnDefs[j].msg)
|
||||
+ "' data-uniqueMsg='" + this._quoteattr(columnDefs[j].uniqueMsg)
|
||||
+ "' data-unique='" + columnDefs[j].unique
|
||||
+ "' "
|
||||
+ (columnDefs[j].readonly ? ' readonly ' : '')
|
||||
+ (columnDefs[j].disabled ? ' disabled ' : '')
|
||||
+ (columnDefs[j].required ? ' required ' : '')
|
||||
+ (columnDefs[j].maxLength == false ? "" : " maxlength='" + columnDefs[j].maxLength + "'")
|
||||
+ " style='overflow:hidden' class='form-control form-control-sm' value=''>";
|
||||
}
|
||||
data += "<label id='" + this._quoteattr(columnDefs[j].name) + "label"
|
||||
+ "' class='errorLabel'></label>";
|
||||
data += "</div><div style='clear:both;'></div></div>";
|
||||
}
|
||||
}
|
||||
// data += "</form>";
|
||||
|
||||
var selector = this.modal_selector;
|
||||
$(selector).on('show.bs.modal', function () {
|
||||
var btns = '<button type="button" data-content="remove" class="btn btn-default" data-dismiss="modal">'+closeCaption+'</button>' +
|
||||
'<button type="submit" form="' + formName + '" data-content="remove" class="btn btn-primary" id="'+buttonClass+'">'+buttonCaption+'</button>';
|
||||
$(selector).find('.modal-title').html(title);
|
||||
$(selector).find('.modal-body').html(data);
|
||||
$(selector).find('.modal-footer').html(btns);
|
||||
const modalContent = $(selector).find('.modal-content');
|
||||
if (modalContent.parent().is('form')) {
|
||||
modalContent.parent().attr('name', formName);
|
||||
modalContent.parent().attr('id', formName);
|
||||
} else {
|
||||
modalContent.wrap("<form name='" + formName + "' id='" + formName + "' role='form'></form>");
|
||||
}
|
||||
});
|
||||
|
||||
$(selector).modal('show');
|
||||
$(selector + ' input[0]').focus();
|
||||
|
||||
var that = this;
|
||||
|
||||
// enable select 2 items, datepicker, datetimepickerm
|
||||
for (var j in columnDefs) {
|
||||
if (columnDefs[j].select2) {
|
||||
// Require select2 plugin
|
||||
$(selector).find("select#" + columnDefs[j].name).select2(columnDefs[j].select2);
|
||||
} else if (columnDefs[j].datepicker) {
|
||||
// Require jquery-ui
|
||||
$(selector).find("#" + columnDefs[j].name).datepicker(columnDefs[j].datepicker);
|
||||
} else if (columnDefs[j].datetimepicker) {
|
||||
// Require datetimepicker plugin
|
||||
$(selector).find("#" + columnDefs[j].name).datetimepicker(columnDefs[j].datetimepicker);
|
||||
}
|
||||
// custom onchange triggers
|
||||
if (columnDefs[j].editorOnChange) {
|
||||
var f = columnDefs[j].editorOnChange; // FIXME what if more than 1 editorOnChange ?
|
||||
$(selector).find("#" + columnDefs[j].name).on('change', function(elm) {
|
||||
f(elm, that);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for "Add" button
|
||||
*/
|
||||
_addRowData: function () {
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
|
||||
var rowDataArray = {};
|
||||
|
||||
// Getting the inputs from the modal
|
||||
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter(':input').each(function (i) {
|
||||
rowDataArray[$(this).attr('id')] = $(this).val();
|
||||
});
|
||||
|
||||
//Getting the textArea from the modal
|
||||
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter('textarea').each(function (i) {
|
||||
rowDataArray[$(this).attr('id')] = $(this).val();
|
||||
});
|
||||
|
||||
//console.log(rowDataArray); //DEBUG
|
||||
|
||||
that.onAddRow(that,
|
||||
rowDataArray,
|
||||
function(data){ that._addRowCallback(data); },
|
||||
function(data){ that._errorCallback(data);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after a row has been deleted on server
|
||||
*/
|
||||
_deleteRowCallback: function (response, status, more) {
|
||||
var selector = this.modal_selector;
|
||||
$(selector + ' .modal-body .alert').remove();
|
||||
|
||||
var message = '<div class="alert alert-success" role="alert">' +
|
||||
'<strong>' + this.language.success + '</strong>' +
|
||||
'</div>';
|
||||
$(selector + ' .modal-body').append(message);
|
||||
|
||||
this.s.dt.row({
|
||||
selected : true
|
||||
}).remove();
|
||||
this.s.dt.draw('page');
|
||||
|
||||
// Disabling submit button
|
||||
$("div"+selector).find("button#addRowBtn").prop('disabled', true);
|
||||
$("div"+selector).find("button#editRowBtn").prop('disabled', true);
|
||||
$("div"+selector).find("button#deleteRowBtn").prop('disabled', true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after a row has been inserted on server
|
||||
*/
|
||||
_addRowCallback: function (response, status, more) {
|
||||
|
||||
//TODO should honor dt.ajax().dataSrc
|
||||
|
||||
var data = (typeof response === "string") ? JSON.parse(response) : response;
|
||||
var selector = this.modal_selector;
|
||||
$(selector + ' .modal-body .alert').remove();
|
||||
|
||||
var message = '<div class="alert alert-success" role="alert">' +
|
||||
'<strong>' + this.language.success + '</strong>' +
|
||||
'</div>';
|
||||
$(selector + ' .modal-body').append(message);
|
||||
|
||||
this.s.dt.row.add(data).draw(false);
|
||||
|
||||
// Disabling submit button
|
||||
$("div" + selector).find("button#addRowBtn").prop('disabled', true);
|
||||
$("div" + selector).find("button#editRowBtn").prop('disabled', true);
|
||||
$("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after a row has been updated on server
|
||||
*/
|
||||
_editRowCallback: function (response, status, more) {
|
||||
|
||||
//TODO should honor dt.ajax().dataSrc
|
||||
|
||||
var data = (typeof response === "string") ? JSON.parse(response) : response;
|
||||
var selector = this.modal_selector;
|
||||
$(selector + ' .modal-body .alert').remove();
|
||||
|
||||
var message = '<div class="alert alert-success" role="alert">' +
|
||||
'<strong>' + this.language.success + '</strong>' +
|
||||
'</div>';
|
||||
$(selector + ' .modal-body').append(message);
|
||||
|
||||
this.s.dt.row({
|
||||
selected : true
|
||||
}).data(data);
|
||||
this.s.dt.draw('page');
|
||||
|
||||
// Disabling submit button
|
||||
$("div" + selector).find("button#addRowBtn").prop('disabled', true);
|
||||
$("div" + selector).find("button#editRowBtn").prop('disabled', true);
|
||||
$("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after AJAX server returned an error
|
||||
*/
|
||||
_errorCallback: function (response, status, more) {
|
||||
var error = response;
|
||||
var selector = this.modal_selector;
|
||||
$(selector + ' .modal-body .alert').remove();
|
||||
var errstr = this.language.error.message;
|
||||
if (error.responseJSON && error.responseJSON.errors) {
|
||||
errstr = "";
|
||||
for (var key in error.responseJSON.errors) {
|
||||
errstr += error.responseJSON.errors[key][0];
|
||||
}
|
||||
}
|
||||
var message = '<div class="alert alert-danger" role="alert">' +
|
||||
'<strong>' + this.language.error.label + '</strong> ' + (error.status == null ? "" : this.language.error.responseCode + error.status) + " " + errstr +
|
||||
'</div>';
|
||||
|
||||
$(selector + ' .modal-body').append(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Default callback for insertion: mock webservice, always success.
|
||||
*/
|
||||
onAddRow: function(dt, rowdata, success, error) {
|
||||
console.log("Missing AJAX configuration for INSERT");
|
||||
success(rowdata);
|
||||
},
|
||||
|
||||
/**
|
||||
* Default callback for editing: mock webservice, always success.
|
||||
*/
|
||||
onEditRow: function(dt, rowdata, success, error) {
|
||||
console.log("Missing AJAX configuration for UPDATE");
|
||||
success(rowdata);
|
||||
},
|
||||
|
||||
/**
|
||||
* Default callback for deletion: mock webservice, always success.
|
||||
*/
|
||||
onDeleteRow: function(dt, rowdata, success, error) {
|
||||
console.log("Missing AJAX configuration for DELETE");
|
||||
success(rowdata);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dinamically reload options in SELECT menu
|
||||
*/
|
||||
reloadOptions: function($select, options) {
|
||||
var oldValue = $select.val();
|
||||
$select.empty(); // remove old options
|
||||
if (options.length > 0) {
|
||||
// array-style select or select2
|
||||
$.each(options, function(key, value) {
|
||||
$select.append($("<option></option>")
|
||||
.attr("value", value).text(value));
|
||||
});
|
||||
} else {
|
||||
// object-style select or select2
|
||||
$.each(options, function(key, value) {
|
||||
$select.append($("<option></option>")
|
||||
.attr("value", value).text(key));
|
||||
});
|
||||
}
|
||||
$select.val(oldValue); // if still present, of course
|
||||
$select.trigger('change');
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitizes input for use in HTML
|
||||
* @param s
|
||||
* @param preserveCR
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
_quoteattr: function (s, preserveCR) {
|
||||
if (s == null)
|
||||
return "";
|
||||
preserveCR = preserveCR ? ' ' : '\n';
|
||||
if (Array.isArray(s)) {
|
||||
// for MULTIPLE SELECT
|
||||
var newArray = [];
|
||||
var x;
|
||||
for (x in s) newArray.push(s[x]);
|
||||
return newArray;
|
||||
}
|
||||
return ('' + s) /* Forces the conversion to string. */
|
||||
.replace(/&/g, '&') /* This MUST be the 1st replacement. */
|
||||
.replace(/'/g, ''') /* The 4 other predefined entities, required. */
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\r\n/g, preserveCR) /* Must be before the next replacement. */
|
||||
.replace(/[\r\n]/g, preserveCR);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* altEditor version
|
||||
*
|
||||
* @static
|
||||
* @type String
|
||||
*/
|
||||
altEditor.version = '2.0';
|
||||
|
||||
/**
|
||||
* altEditor defaults
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
altEditor.defaults = {
|
||||
/**
|
||||
* @type {Boolean} Ask user what they want to do, even for a single
|
||||
* option
|
||||
*/
|
||||
alwaysAsk: false,
|
||||
|
||||
/** @type {string|null} What will trigger a focus */
|
||||
focus: null, // focus, click, hover
|
||||
|
||||
/** @type {column-selector} Columns to provide auto fill for */
|
||||
columns: '', // all
|
||||
|
||||
/** @type {boolean|null} Update the cells after a drag */
|
||||
update: null, // false is editor given, true otherwise
|
||||
|
||||
/** @type {DataTable.Editor} Editor instance for automatic submission */
|
||||
editor: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Classes used by altEditor that are configurable
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
altEditor.classes = {
|
||||
/** @type {String} Class used by the selection button */
|
||||
btn: 'btn'
|
||||
};
|
||||
|
||||
// Attach a listener to the document which listens for DataTables
|
||||
// initialisation
|
||||
// events so we can automatically initialise
|
||||
$(document).on('preInit.dt.altEditor', function (e, settings, json) {
|
||||
if (e.namespace !== 'dt') {
|
||||
return;
|
||||
}
|
||||
|
||||
var init = settings.oInit.altEditor;
|
||||
var defaults = DataTable.defaults.altEditor;
|
||||
|
||||
if (init || defaults) {
|
||||
var opts = $.extend({}, init, defaults);
|
||||
|
||||
if (init !== false) {
|
||||
|
||||
var editor = new altEditor(settings, opts);
|
||||
// e is a jQuery event object
|
||||
// e.target is the underlying jQuery object, e.g. $('#mytable')
|
||||
// so that you can retrieve the altEditor object later
|
||||
e.target.altEditor = editor;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Alias for access
|
||||
DataTable.altEditor = altEditor;
|
||||
return altEditor;
|
||||
});
|
@ -1,250 +1,207 @@
|
||||
<div class="ui dividing header">Connection settings</div>
|
||||
<div class="twelve wide column">
|
||||
<div class="ui grid">
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Settings Validation:</label>
|
||||
</div>
|
||||
<div class="two wide column">
|
||||
<button id="sonarr_validate" class="test ui blue button" type="button">
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
<div class="seven wide column">
|
||||
<div id="sonarr_validated" class="ui read-only checkbox">
|
||||
<input id="sonarr_validated_checkbox" type="checkbox">
|
||||
<label id="sonarr_validation_result">Not Tested Recently</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% extends '_main.html' %}
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Hostname or IP Address</label>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<div class='field'>
|
||||
<div class="ui fluid input">
|
||||
<input id="settings_sonarr_ip" name="settings_sonarr_ip" class="sonarr_config" type="text"
|
||||
value="{{ settings.sonarr.ip }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapsed center aligned column">
|
||||
<div class="ui basic icon" data-tooltip="Hostname or IP4 Address of Sonarr" data-inverted="">
|
||||
<i class="help circle large icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block title %}Sonarr - Bazarr{% endblock %}
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Listening Port</label>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<div class='field'>
|
||||
<div class="ui fluid input">
|
||||
<input id="settings_sonarr_port" name="settings_sonarr_port" class="sonarr_config" type="text"
|
||||
value="{{ settings.sonarr.port }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapsed center aligned column">
|
||||
<div class="ui basic icon" data-tooltip="TCP Port of Sonarr" data-inverted="">
|
||||
<i class="help circle large icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block page_head %}
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Base URL</label>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<div class="ui fluid input">
|
||||
<input id="settings_sonarr_baseurl" name="settings_sonarr_baseurl" class="sonarr_config" type="text"
|
||||
value="{{ settings.sonarr.base_url }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapsed center aligned column">
|
||||
<div class="ui basic icon" data-tooltip="Base URL for Sonarr (default: '/')" data-inverted="">
|
||||
<i class="help circle large icon"></i>
|
||||
</div>
|
||||
{% endblock page_head %}
|
||||
|
||||
{% block bcleft %}
|
||||
<div class="">
|
||||
<button class="btn btn-outline" id="save_button">
|
||||
<div>
|
||||
<span class="fa-stack">
|
||||
<i class="fas fa-save fa-stack-2x align-top text-themecolor text-center font-20" aria-hidden="true"></i>
|
||||
<i id="save_button_checkmark" class="fas fa-check fa-stack-2x" style="color:green;"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="align-bottom text-themecolor small text-center">Save</div>
|
||||
</button>
|
||||
</div>
|
||||
{% endblock bcleft %}
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>SSL Enabled</label>
|
||||
</div>
|
||||
<div class="one wide column">
|
||||
<div id="sonarr_ssl_div" class="ui toggle checkbox" data-ssl={{ settings.sonarr.getboolean('ssl') }}>
|
||||
<input id="settings_sonarr_ssl" name="settings_sonarr_ssl" type="checkbox">
|
||||
<label></label>
|
||||
{% block bcright %}
|
||||
|
||||
{% endblock bcright %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container-fluid" style="padding-top: 3em;">
|
||||
<form class="form" name="settings_form" id="settings_form">
|
||||
<h4>Use Sonarr</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>Enabled</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_sonarr" name="settings-general-use_sonarr">
|
||||
<span class="custom-control-label" for="settings-general-use_sonarr"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>API Key</label>
|
||||
<div id="sonarr_div">
|
||||
<h4>Host</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>Hostname or IP Address</b>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<div class='field'>
|
||||
<div class="ui fluid input">
|
||||
<input id="settings_sonarr_apikey" name="settings_sonarr_apikey" class="sonarr_config"
|
||||
type="text" value="{{ settings.sonarr.apikey }}">
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-sonarr-ip" name="settings-sonarr-ip" value="{{settings.sonarr.ip}}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>Port Number</b>
|
||||
</div>
|
||||
<div class="collapsed center aligned column">
|
||||
<div class="ui basic icon" data-tooltip="API Key for Sonarr (32 alphanumeric characters)"
|
||||
data-inverted="">
|
||||
<i class="help circle large icon"></i>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-sonarr-port" name="settings-sonarr-port" value="{{settings.sonarr.port}}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>URL Base</b>
|
||||
</div>
|
||||
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Download Only Monitored</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-sonarr-base_url" name="settings-sonarr-base_url" value="{{settings.sonarr.base_url}}">
|
||||
</div>
|
||||
<div class="one wide column">
|
||||
<div id="settings_only_monitored_sonarr" class="ui toggle checkbox"
|
||||
data-monitored={{ settings.sonarr.getboolean('only_monitored') }}>
|
||||
<input name="settings_sonarr_only_monitored" type="checkbox">
|
||||
<label></label>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>SSL Enabled</b>
|
||||
</div>
|
||||
<div class="collapsed column">
|
||||
<div class="collapsed center aligned column">
|
||||
<div class="ui basic icon"
|
||||
data-tooltip="Automatic download of Subtitles will only happen for monitored episodes in Sonarr."
|
||||
data-inverted="">
|
||||
<i class="help circle large icon"></i>
|
||||
</div>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-sonarr-ssl" name="settings-sonarr-ssl">
|
||||
<span class="custom-control-label" for="settings-sonarr-ssl"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>API Key</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-sonarr-apikey" name="settings-sonarr-apikey" value="{{settings.sonarr.apikey}}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="ui dividing header">Synchronization</div>
|
||||
<div class="twelve wide column">
|
||||
<div class="ui grid">
|
||||
<div class="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
<label>Full Filesystem Scan</label>
|
||||
</div>
|
||||
<div class="three wide column">
|
||||
<div class='field'>
|
||||
<select name="settings_sonarr_sync" id="settings_sonarr_sync" class="ui fluid selection dropdown">
|
||||
<option value="Manually">Manually</option>
|
||||
<option value="Daily">Daily</option>
|
||||
<option value="Weekly">Weekly</option>
|
||||
</select>
|
||||
<h4>Options</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>Minimum Score</b>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<input type="number" min="0" max="100" step="1" onkeydown="return false" class="form-control" id="settings-general-minimum_score" name="settings-general-minimum_score" value="{{settings.general.minimum_score}}">
|
||||
</div>
|
||||
<div id="settings_sonarr_sync_day_div" class="three wide column">
|
||||
<div class='field'>
|
||||
<select name="settings_sonarr_sync_day" id="settings_sonarr_sync_day"
|
||||
class="ui fluid selection dropdown">
|
||||
% import calendar
|
||||
% for idx, i in enumerate(calendar.day_name):
|
||||
<option value="{{ idx }}">{{ i }}</option>
|
||||
%end
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 text-right">
|
||||
<b>Download Only Monitored</b>
|
||||
</div>
|
||||
<div id="settings_sonarr_sync_hour_div" class="two wide column">
|
||||
<div class='field'>
|
||||
<select name="settings_sonarr_sync_hour" id="settings_sonarr_sync_hour"
|
||||
class="ui fluid selection dropdown">
|
||||
% for i in range(24):
|
||||
<option value="{{ i }}">{{ i }}:00</option>
|
||||
%end
|
||||
</select>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-sonarr-only_monitored" name="settings-sonarr-only_monitored">
|
||||
<span class="custom-control-label" for="settings-sonarr-only_monitored"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<h4>PAth Mapping</h4>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<table class="dataTable table table-striped" id="path_mapping">
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% macro settings_sonarr() %}
|
||||
{% endblock body %}
|
||||
|
||||
{% block tail %}
|
||||
<script>
|
||||
if ($('#sonarr_ssl_div').data("ssl") === "True") {
|
||||
$("#sonarr_ssl_div").checkbox('check');
|
||||
$(document).ready(function () {
|
||||
// Hide checkmark over save button
|
||||
$('#save_button_checkmark').hide();
|
||||
|
||||
// Hide *_div on Select input changed to None
|
||||
$('#settings-general-use_sonarr').on('change', function() {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#sonarr_div').show();
|
||||
} else {
|
||||
$("#sonarr_ssl_div").checkbox('uncheck');
|
||||
$('#sonarr_div').hide();
|
||||
}
|
||||
});
|
||||
|
||||
if ($('#settings_only_monitored_sonarr').data("monitored") === "True") {
|
||||
$("#settings_only_monitored_sonarr").checkbox('check');
|
||||
} else {
|
||||
$("#settings_only_monitored_sonarr").checkbox('uncheck');
|
||||
}
|
||||
// Set Checkbox input values
|
||||
$('#settings-general-use_sonarr').prop('checked', {{'true' if settings.general.getboolean('use_sonarr')}});
|
||||
$('#settings-sonarr-ssl').prop('checked', {{'true' if settings.sonarr.getboolean('ssl')}});
|
||||
$('#settings-sonarr-only_monitored').prop('checked', {{'true' if settings.sonarr.getboolean('only_monitored')}});
|
||||
|
||||
$('#settings_sonarr_sync').dropdown('setting', 'onChange', function () {
|
||||
if ($('#settings_sonarr_sync').val() === "Manually") {
|
||||
$('#settings_sonarr_sync_day_div').hide();
|
||||
$('#settings_sonarr_sync_hour_div').hide();
|
||||
} else if ($('#settings_sonarr_sync').val() === "Daily") {
|
||||
$('#settings_sonarr_sync_day_div').hide();
|
||||
$('#settings_sonarr_sync_hour_div').show();
|
||||
} else if ($('#settings_sonarr_sync').val() === "Weekly") {
|
||||
$('#settings_sonarr_sync_day_div').show();
|
||||
$('#settings_sonarr_sync_hour_div').show();
|
||||
}
|
||||
$('#save_button').on('click', function() {
|
||||
var formdata = new FormData(document.getElementById("settings_form"));
|
||||
|
||||
// Make sure all checkbox input are sent with true/false value
|
||||
$('input[type=checkbox]').each(function () {
|
||||
formdata.set($(this).prop('id'), $(this).prop('checked'));
|
||||
});
|
||||
|
||||
$('#settings_sonarr_sync').dropdown('clear');
|
||||
$('#settings_sonarr_sync').dropdown('set selected', '{{settings.sonarr.full_update|safe}}');
|
||||
$('#settings_sonarr_sync').dropdown('refresh');
|
||||
$('#settings_sonarr_sync_day').dropdown('clear');
|
||||
$('#settings_sonarr_sync_day').dropdown('set selected', '{{settings.sonarr.full_update_day|safe}}');
|
||||
$('#settings_sonarr_sync_day').dropdown('refresh');
|
||||
$('#settings_sonarr_sync_hour').dropdown('clear');
|
||||
$('#settings_sonarr_sync_hour').dropdown('set selected', '{{settings.sonarr.full_update_hour|safe}}');
|
||||
$('#settings_sonarr_sync_hour').dropdown('refresh');
|
||||
|
||||
$('#sonarr_validate').on('click', function () {
|
||||
if ($('#sonarr_ssl_div').checkbox('is checked')) {
|
||||
protocol = 'https';
|
||||
} else {
|
||||
protocol = 'http';
|
||||
}
|
||||
const sonarr_url = $('#settings_sonarr_ip').val() + ":" + $('#settings_sonarr_port').val() + $('#settings_sonarr_baseurl').val().replace(/\/$/, "") + "/api/system/status?apikey=" + $('#settings_sonarr_apikey').val();
|
||||
|
||||
$.getJSON("{{base_url}}test_url/" + protocol + "/" + encodeURIComponent(sonarr_url), function (data) {
|
||||
if (data.status) {
|
||||
$('#sonarr_validated').checkbox('check');
|
||||
$('#sonarr_validation_result').text('Test Successful: Sonarr v' + data.version).css('color', 'green');
|
||||
$('.form').form('validate form');
|
||||
$('#loader').removeClass('active');
|
||||
} else {
|
||||
$('#sonarr_validated').checkbox('uncheck');
|
||||
$('#sonarr_validation_result').text('Test Failed').css('color', 'red');
|
||||
$('.form').form('validate form');
|
||||
$('#loader').removeClass('active');
|
||||
$.ajax({
|
||||
url: "{{ url_for('api.savesettings') }}",
|
||||
data: formdata,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
complete: function () {
|
||||
$('#save_button_checkmark').show();
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
$('#save_button_checkmark').hide();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.sonarr_config').on('keyup', function () {
|
||||
$('#sonarr_validated').checkbox('uncheck');
|
||||
$('#sonarr_validation_result').text('You Must Test Your Sonarr Connection Settings Before Saving.').css('color', 'red');
|
||||
$('.form').form('validate form');
|
||||
$('#loader').removeClass('active');
|
||||
table = $('#path_mapping').DataTable({
|
||||
data: [["/tvsonarr", "/tvbazarr"]],
|
||||
columns: [{
|
||||
title: "Path for Sonarr",
|
||||
type: "text"
|
||||
}, {
|
||||
title: "Path for Bazarr",
|
||||
type: "text"
|
||||
}],
|
||||
dom: 'Bfrtip', // Needs button container
|
||||
select: 'single',
|
||||
responsive: true,
|
||||
altEditor: true, // Enable altEditor
|
||||
buttons: [{
|
||||
text: 'Add',
|
||||
name: 'add' // do not change name
|
||||
},
|
||||
{
|
||||
extend: 'selected', // Bind to Selected row
|
||||
text: 'Edit',
|
||||
name: 'edit' // do not change name
|
||||
},
|
||||
{
|
||||
extend: 'selected', // Bind to Selected row
|
||||
text: 'Delete',
|
||||
name: 'delete' // do not change name
|
||||
}]
|
||||
});
|
||||
|
||||
$('#settings_sonarr_ssl').on('change', function () {
|
||||
$('#sonarr_validated').checkbox('uncheck');
|
||||
$('#sonarr_validation_result').text('You Must Test Your Sonarr Connection Settings Before Saving.').css('color', 'red');
|
||||
$('.form').form('validate form');
|
||||
$('#loader').removeClass('active');
|
||||
});
|
||||
|
||||
$("#sonarr_validated").checkbox('check');
|
||||
|
||||
|
||||
</script>
|
||||
{% endmacro %}
|
||||
{% endblock tail %}
|
||||
|
Loading…
Reference in new issue