578 lines
26 KiB
JavaScript
578 lines
26 KiB
JavaScript
(function (window, document) {
|
||
'use strict';
|
||
|
||
var FIELD_CUSTOMIZER_ID = 'a555f4fc-d6a6-4421-8189-457449d9bbde';
|
||
var SITE_DEFAULTS_PROPERTY = 'PortalSettings.ExpiryIndicator.Defaults';
|
||
var WEB_OVERRIDE_PROPERTY = 'PortalSettings.ExpiryIndicator.Override';
|
||
var state = { context: null, field: null, config: null, loading: null };
|
||
|
||
function configuredExpiryField() {
|
||
var scripts = document.getElementsByTagName('script');
|
||
for (var index = scripts.length - 1; index >= 0; index--) {
|
||
var source = String(scripts[index].src || '');
|
||
if (source.indexOf('ExpiryIndicatorClassic.js') < 0) { continue; }
|
||
var match = /[?&]expiryField=([^&]+)/i.exec(source);
|
||
if (match) { return decodeURIComponent(match[1]); }
|
||
}
|
||
return '';
|
||
}
|
||
|
||
function discoverExpiryField() {
|
||
var id = listId(null);
|
||
if (!id) { return ''; }
|
||
try {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open('GET', listUrl(id) +
|
||
'/fields?$select=InternalName,ClientSideComponentId', false);
|
||
xhr.setRequestHeader('Accept', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('OData-Version', '3.0');
|
||
xhr.send(null);
|
||
if (xhr.status < 200 || xhr.status >= 300) { return ''; }
|
||
var data = JSON.parse(xhr.responseText || '{}');
|
||
var fields = data.d ? data.d.results : (data.value || []);
|
||
for (var index = 0; index < fields.length; index++) {
|
||
var componentId = String(fields[index].ClientSideComponentId || '').replace(/[{}]/g, '').toLowerCase();
|
||
if (componentId === FIELD_CUSTOMIZER_ID) { return fields[index].InternalName; }
|
||
}
|
||
} catch (ignore) { }
|
||
return '';
|
||
}
|
||
|
||
function pageContext() {
|
||
return window._spPageContextInfo || {};
|
||
}
|
||
|
||
function webUrl() {
|
||
return String(pageContext().webAbsoluteUrl || '').replace(/\/$/, '');
|
||
}
|
||
|
||
function siteUrl() {
|
||
return String(pageContext().siteAbsoluteUrl || webUrl()).replace(/\/$/, '');
|
||
}
|
||
|
||
function listId(context) {
|
||
return String((context && context.listName) || pageContext().pageListId || '').replace(/[{}]/g, '');
|
||
}
|
||
|
||
function request(method, url, body) {
|
||
return new Promise(function (resolve, reject) {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open(method, url, true);
|
||
xhr.setRequestHeader('Accept', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('Content-Type', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('OData-Version', '3.0');
|
||
if (method !== 'GET') {
|
||
var digest = document.getElementById('__REQUESTDIGEST');
|
||
if (digest) { xhr.setRequestHeader('X-RequestDigest', digest.value); }
|
||
}
|
||
xhr.onreadystatechange = function () {
|
||
if (xhr.readyState !== 4) { return; }
|
||
if (xhr.status >= 200 && xhr.status < 300) {
|
||
resolve(xhr.responseText ? JSON.parse(xhr.responseText) : {});
|
||
} else {
|
||
var message = xhr.status + ' ' + xhr.statusText;
|
||
try {
|
||
var error = JSON.parse(xhr.responseText);
|
||
message = error.error && error.error.message ? error.error.message.value : message;
|
||
} catch (ignore) { }
|
||
reject(new Error(message));
|
||
}
|
||
};
|
||
xhr.send(body ? JSON.stringify(body) : null);
|
||
});
|
||
}
|
||
|
||
function listUrl(id) {
|
||
return webUrl() + "/_api/web/lists(guid'" + id + "')";
|
||
}
|
||
|
||
function defaults(expiryField) {
|
||
return {
|
||
baseField: 'Created',
|
||
expiryField: expiryField || 'ExpiryDate',
|
||
default: {
|
||
lifeTime: { value: 2, unit: 'years' },
|
||
columnRule: []
|
||
},
|
||
rules: [],
|
||
nullText: 'Kein Ablaufdatum',
|
||
confirmExtension: true
|
||
};
|
||
}
|
||
|
||
function mergeConfig(baseValue, overrideValue) {
|
||
var base = baseValue || defaults();
|
||
var override = overrideValue || {};
|
||
var result = {
|
||
baseField: override.baseField || base.baseField || 'Created',
|
||
expiryField: override.expiryField || base.expiryField || 'ExpiryDate',
|
||
default: {
|
||
lifeTime: override.default && override.default.lifeTime ? override.default.lifeTime :
|
||
(base.default && base.default.lifeTime ? base.default.lifeTime : { value: 2, unit: 'years' }),
|
||
columnRule: override.default && override.default.columnRule instanceof Array ? override.default.columnRule :
|
||
(base.default && base.default.columnRule instanceof Array ? base.default.columnRule : [])
|
||
},
|
||
rules: override.rules instanceof Array ? override.rules : (base.rules instanceof Array ? base.rules : []),
|
||
nullText: typeof override.nullText === 'string' ? override.nullText : base.nullText,
|
||
confirmExtension: typeof override.confirmExtension === 'boolean' ? override.confirmExtension : base.confirmExtension
|
||
};
|
||
return result;
|
||
}
|
||
|
||
function propertyValue(payload, key) {
|
||
var properties = payload && payload.d ? payload.d : (payload || {});
|
||
var expected = String(key || '').replace(/_x002e_/gi, '.').toLowerCase();
|
||
for (var name in properties) {
|
||
var normalizedName = String(name || '').replace(/_x002e_/gi, '.').toLowerCase();
|
||
if (Object.prototype.hasOwnProperty.call(properties, name) && normalizedName === expected) {
|
||
try { return typeof properties[name] === 'string' ? JSON.parse(properties[name]) : properties[name]; }
|
||
catch (ignore) { return null; }
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function isBindingOnly(value) {
|
||
if (!value || typeof value !== 'object') { return false; }
|
||
return typeof value.expiryField === 'string' && !value.default && !value.rules &&
|
||
!value.baseField && typeof value.nullText === 'undefined' && typeof value.confirmExtension === 'undefined';
|
||
}
|
||
|
||
function loadConfig(context) {
|
||
var id = listId(context);
|
||
if (!id) { return Promise.reject(new Error('Keine Liste erkannt.')); }
|
||
if (state.loading && state.context === id) { return state.loading; }
|
||
state.context = id;
|
||
var fieldRequest = request('GET', listUrl(id) +
|
||
'/fields?$select=Id,InternalName,ClientSideComponentId,ClientSideComponentProperties');
|
||
var sitePropertiesRequest = request('GET', siteUrl() + '/_api/web/AllProperties').catch(function () { return {}; });
|
||
var webPropertiesRequest = siteUrl().toLowerCase() === webUrl().toLowerCase() ? Promise.resolve({}) :
|
||
request('GET', webUrl() + '/_api/web/AllProperties').catch(function () { return {}; });
|
||
state.loading = Promise.all([fieldRequest, sitePropertiesRequest, webPropertiesRequest])
|
||
.then(function (results) {
|
||
var data = results[0];
|
||
var fields = data.d ? data.d.results : (data.value || []);
|
||
var field;
|
||
for (var index = 0; index < fields.length; index++) {
|
||
var componentId = String(fields[index].ClientSideComponentId || '').replace(/[{}]/g, '').toLowerCase();
|
||
if (componentId === FIELD_CUSTOMIZER_ID) { field = fields[index]; break; }
|
||
}
|
||
if (!field) { throw new Error('Kein ExpiryIndicator-Feld gebunden.'); }
|
||
var inherited = mergeConfig(defaults(field.InternalName), propertyValue(results[1], SITE_DEFAULTS_PROPERTY));
|
||
inherited = mergeConfig(inherited, propertyValue(results[2], WEB_OVERRIDE_PROPERTY));
|
||
var config = inherited;
|
||
try {
|
||
if (field.ClientSideComponentProperties) {
|
||
var parsed = JSON.parse(field.ClientSideComponentProperties);
|
||
if (parsed.inheritSiteDefaults === true || parsed.override || isBindingOnly(parsed)) {
|
||
config = mergeConfig(inherited, parsed.override || {});
|
||
} else if (parsed.inheritSiteDefaults === false) {
|
||
config = mergeConfig(defaults(field.InternalName), parsed.override || {});
|
||
} else {
|
||
config = mergeConfig(defaults(field.InternalName), parsed);
|
||
}
|
||
}
|
||
} catch (ignore) { }
|
||
config.expiryField = field.InternalName;
|
||
state.field = field;
|
||
state.config = config;
|
||
return config;
|
||
});
|
||
return state.loading;
|
||
}
|
||
|
||
function ruleFields(config) {
|
||
var result = [];
|
||
function add(name) {
|
||
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name || '') && result.indexOf(name) < 0) { result.push(name); }
|
||
}
|
||
function visit(condition) {
|
||
if (!condition) { return; }
|
||
if (condition.conditions instanceof Array) {
|
||
for (var index = 0; index < condition.conditions.length; index++) { visit(condition.conditions[index]); }
|
||
} else { add(condition.columnName); }
|
||
}
|
||
for (var index = 0; index < (config.rules || []).length; index++) {
|
||
var rule = config.rules[index];
|
||
if (rule.condition) { visit(rule.condition); } else { add(rule.columnName); }
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function equalsIgnoreCase(left, right) {
|
||
return String(left).toLowerCase() === String(right).toLowerCase();
|
||
}
|
||
|
||
function valueMatches(rawValue, configuredValue) {
|
||
if (rawValue === null || typeof rawValue === 'undefined') { return String(configuredValue) === ''; }
|
||
var values = rawValue instanceof Array ? rawValue :
|
||
(rawValue.results instanceof Array ? rawValue.results : [rawValue]);
|
||
for (var index = 0; index < values.length; index++) {
|
||
var value = values[index];
|
||
if (value && typeof value === 'object') {
|
||
if (value.TermGuid && equalsIgnoreCase(value.TermGuid, configuredValue)) { return true; }
|
||
value = value.Title || value.LookupValue || value.Label || value.Value || '';
|
||
}
|
||
var text = String(value);
|
||
if (text === String(configuredValue)) { return true; }
|
||
var separator = text.lastIndexOf('|');
|
||
if (separator >= 0 && equalsIgnoreCase(text.substring(separator + 1), configuredValue)) { return true; }
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function conditionMatches(condition, values) {
|
||
if (condition && condition.conditions instanceof Array) {
|
||
if (condition.operator === 'and') {
|
||
for (var andIndex = 0; andIndex < condition.conditions.length; andIndex++) {
|
||
if (!conditionMatches(condition.conditions[andIndex], values)) { return false; }
|
||
}
|
||
return condition.conditions.length > 0;
|
||
}
|
||
if (condition.operator === 'or') {
|
||
for (var orIndex = 0; orIndex < condition.conditions.length; orIndex++) {
|
||
if (conditionMatches(condition.conditions[orIndex], values)) { return true; }
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
return !!condition && Object.prototype.hasOwnProperty.call(values, condition.columnName) &&
|
||
valueMatches(values[condition.columnName], condition.columnValue);
|
||
}
|
||
|
||
function validateRules(rules) {
|
||
var errors = [];
|
||
function safeName(value) { return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value || ''); }
|
||
function validateGroup(group, path, depth) {
|
||
if (depth > 10) { errors.push(path + ': maximale Verschachtelungstiefe 10 überschritten.'); return; }
|
||
if (!group || (group.operator !== 'and' && group.operator !== 'or')) {
|
||
errors.push(path + '.operator muss "and" oder "or" sein.');
|
||
}
|
||
if (!group || !(group.conditions instanceof Array) || !group.conditions.length) {
|
||
errors.push(path + '.conditions muss mindestens eine Bedingung enthalten.'); return;
|
||
}
|
||
for (var index = 0; index < group.conditions.length; index++) {
|
||
var condition = group.conditions[index];
|
||
var childPath = path + '.conditions[' + index + ']';
|
||
if (condition && typeof condition.operator !== 'undefined') { validateGroup(condition, childPath, depth + 1); }
|
||
else if (!condition || !safeName(condition.columnName) || typeof condition.columnValue === 'undefined') {
|
||
errors.push(childPath + ': columnName/columnValue fehlen oder sind ungültig.');
|
||
}
|
||
}
|
||
}
|
||
if (!(rules instanceof Array)) { return ['rules muss ein JSON-Array sein.']; }
|
||
for (var index = 0; index < rules.length; index++) {
|
||
var rule = rules[index];
|
||
if (rule && rule.condition) { validateGroup(rule.condition, 'rules[' + index + '].condition', 0); }
|
||
else if (!rule || !safeName(rule.columnName) || typeof rule.columnValue === 'undefined') {
|
||
errors.push('rules[' + index + '] benötigt condition oder columnName/columnValue.');
|
||
}
|
||
}
|
||
return errors;
|
||
}
|
||
|
||
function behavior(config, values) {
|
||
for (var index = 0; index < (config.rules || []).length; index++) {
|
||
var rule = config.rules[index];
|
||
var matched = rule.condition ? conditionMatches(rule.condition, values) :
|
||
Object.prototype.hasOwnProperty.call(values, rule.columnName) &&
|
||
valueMatches(values[rule.columnName], rule.columnValue);
|
||
if (matched) { return rule; }
|
||
}
|
||
return config.default;
|
||
}
|
||
|
||
function parseDate(value) {
|
||
if (!value) { return null; }
|
||
var match = /\/Date\((-?\d+)/.exec(String(value));
|
||
var result = match ? new Date(Number(match[1])) : new Date(value);
|
||
return isNaN(result.getTime()) ? null : result;
|
||
}
|
||
|
||
function formatDate(value) {
|
||
function pad(number) { return number < 10 ? '0' + number : String(number); }
|
||
return pad(value.getDate()) + '.' + pad(value.getMonth() + 1) + '.' + value.getFullYear();
|
||
}
|
||
|
||
function addDuration(source, duration) {
|
||
var result = new Date(source.getTime());
|
||
if (duration.unit === 'days') {
|
||
result.setUTCDate(result.getUTCDate() + duration.value);
|
||
return result;
|
||
}
|
||
var months = duration.unit === 'years' ? duration.value * 12 : duration.value;
|
||
var day = result.getUTCDate();
|
||
result.setUTCDate(1);
|
||
result.setUTCMonth(result.getUTCMonth() + months);
|
||
var lastDay = new Date(Date.UTC(result.getUTCFullYear(), result.getUTCMonth() + 1, 0)).getUTCDate();
|
||
result.setUTCDate(Math.min(day, lastDay));
|
||
return result;
|
||
}
|
||
|
||
function dayDifference(from, to) {
|
||
var fromDay = Date.UTC(from.getUTCFullYear(), from.getUTCMonth(), from.getUTCDate());
|
||
var toDay = Date.UTC(to.getUTCFullYear(), to.getUTCMonth(), to.getUTCDate());
|
||
return Math.round((toDay - fromDay) / 86400000);
|
||
}
|
||
|
||
function colorRule(days, rules) {
|
||
function matches(operator, threshold) {
|
||
if (operator === 'lessThan') { return days < threshold; }
|
||
if (operator === 'lessOrEqual') { return days <= threshold; }
|
||
if (operator === 'equal') { return days === threshold; }
|
||
if (operator === 'greaterOrEqual') { return days >= threshold; }
|
||
return operator === 'greaterThan' && days > threshold;
|
||
}
|
||
for (var index = 0; index < (rules || []).length; index++) {
|
||
if (matches(rules[index].operator, rules[index].daysUntilExpiry)) { return rules[index]; }
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function findRow(id) {
|
||
var rows = document.querySelectorAll('tr[iid]');
|
||
for (var index = 0; index < rows.length; index++) {
|
||
var parts = String(rows[index].getAttribute('iid') || '').split(',');
|
||
if (String(parts[1]) === String(id)) { return rows[index]; }
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function applyGradient(row, color, textColor, title) {
|
||
var allCells = row.querySelectorAll('td');
|
||
var cells = [];
|
||
for (var index = 0; index < allCells.length; index++) {
|
||
if (!allCells[index].querySelector('input[type="checkbox"]') &&
|
||
String(allCells[index].className).indexOf('ms-vb-itmcbx') < 0) {
|
||
cells.push(allCells[index]);
|
||
}
|
||
}
|
||
if (!cells.length) { return; }
|
||
var first = cells[0].getBoundingClientRect();
|
||
var last = cells[cells.length - 1].getBoundingClientRect();
|
||
var width = Math.max(1, last.right - first.left);
|
||
var gradient = 'linear-gradient(to right, #ffffff, ' + color + ')';
|
||
for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {
|
||
var rect = cells[cellIndex].getBoundingClientRect();
|
||
cells[cellIndex].style.backgroundColor = '#ffffff';
|
||
cells[cellIndex].style.backgroundImage = gradient;
|
||
cells[cellIndex].style.backgroundSize = width + 'px 100%';
|
||
cells[cellIndex].style.backgroundPosition = (-(rect.left - first.left)) + 'px 0';
|
||
cells[cellIndex].style.backgroundRepeat = 'no-repeat';
|
||
cells[cellIndex].style.color = textColor;
|
||
cells[cellIndex].title = title;
|
||
}
|
||
}
|
||
|
||
function render(context) {
|
||
loadConfig(context).then(function (config) {
|
||
var rows = context && context.ListData && context.ListData.Row ? context.ListData.Row : [];
|
||
var ids = [];
|
||
for (var index = 0; index < rows.length; index++) {
|
||
var id = Number(rows[index].ID || rows[index].Id);
|
||
if (id > 0) { ids.push(id); }
|
||
}
|
||
if (!ids.length) { return; }
|
||
var fields = [config.baseField, config.expiryField].concat(ruleFields(config));
|
||
var select = ['Id'];
|
||
for (var fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
|
||
if (select.indexOf(fields[fieldIndex]) < 0) { select.push(fields[fieldIndex]); }
|
||
}
|
||
var filters = [];
|
||
for (var idIndex = 0; idIndex < ids.length; idIndex++) { filters.push('Id eq ' + ids[idIndex]); }
|
||
return request('GET', listUrl(listId(context)) + '/items?$select=' + select.join(',') +
|
||
'&$filter=' + encodeURIComponent(filters.join(' or ')) + '&$top=' + ids.length)
|
||
.then(function (data) {
|
||
var items = data.d ? data.d.results : (data.value || []);
|
||
for (var itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||
var item = items[itemIndex];
|
||
var created = parseDate(item[config.baseField]);
|
||
var expiry = parseDate(item[config.expiryField]);
|
||
if (!created && !expiry) { continue; }
|
||
var selected = behavior(config, item);
|
||
var effective = expiry || addDuration(created, selected.lifeTime);
|
||
var days = dayDifference(new Date(), effective);
|
||
var rule = colorRule(days, selected.columnRule);
|
||
var row = findRow(item.Id);
|
||
var marker = row ? row.querySelector('[data-expiry-classic-item-id="' + item.Id + '"]') : null;
|
||
if (marker) {
|
||
marker.innerHTML = '';
|
||
marker.appendChild(document.createTextNode(formatDate(effective) +
|
||
(rule && rule.label ? ' ' + rule.label : '')));
|
||
marker.title = days + ' Resttage' + (!expiry ? ' – aus ' + config.baseField + ' berechnet' : '');
|
||
}
|
||
if (row && rule) {
|
||
applyGradient(row, rule.backgroundColor, rule.textColor,
|
||
days + ' Resttage' + (rule.label ? ' – ' + rule.label : ''));
|
||
}
|
||
}
|
||
});
|
||
}).catch(function (error) {
|
||
if (window.console && console.warn) { console.warn('ExpiryIndicator Classic:', error.message); }
|
||
});
|
||
}
|
||
|
||
function selectedIds() {
|
||
try {
|
||
var selected = SP.ListOperation.Selection.getSelectedItems();
|
||
var ids = [];
|
||
for (var index = 0; index < selected.length; index++) { ids.push(Number(selected[index].id)); }
|
||
return ids;
|
||
} catch (ignore) { return []; }
|
||
}
|
||
|
||
function extendOne(id, config) {
|
||
var fields = [config.baseField, config.expiryField].concat(ruleFields(config));
|
||
return request('GET', listUrl(state.context) + '/items(' + id + ')?$select=Id,' + fields.join(','))
|
||
.then(function (data) {
|
||
var item = data.d || data;
|
||
var created = parseDate(item[config.baseField]);
|
||
var expiry = parseDate(item[config.expiryField]);
|
||
var base = expiry || addDuration(created, behavior(config, item).lifeTime);
|
||
var updated = addDuration(base, { value: 1, unit: 'years' });
|
||
var body = { '__metadata': { 'type': item.__metadata.type } };
|
||
body[config.expiryField] = updated.toISOString();
|
||
return new Promise(function (resolve, reject) {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open('POST', listUrl(state.context) + '/items(' + id + ')', true);
|
||
xhr.setRequestHeader('Accept', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('Content-Type', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('OData-Version', '3.0');
|
||
xhr.setRequestHeader('IF-MATCH', '*');
|
||
xhr.setRequestHeader('X-HTTP-Method', 'MERGE');
|
||
var digest = document.getElementById('__REQUESTDIGEST');
|
||
if (digest) { xhr.setRequestHeader('X-RequestDigest', digest.value); }
|
||
xhr.onreadystatechange = function () {
|
||
if (xhr.readyState !== 4) { return; }
|
||
if (xhr.status >= 200 && xhr.status < 300) { resolve(); }
|
||
else { reject(new Error('#' + id + ': ' + xhr.status + ' ' + xhr.statusText)); }
|
||
};
|
||
xhr.send(JSON.stringify(body));
|
||
});
|
||
});
|
||
}
|
||
|
||
function extendSelected() {
|
||
var ids = selectedIds();
|
||
if (!ids.length) { alert('Bitte mindestens ein Element auswählen.'); return; }
|
||
loadConfig(state.context).then(function (config) {
|
||
if (config.confirmExtension && !confirm('Ablaufdatum für ' + ids.length + ' Element(e) um ein Jahr verlängern?')) {
|
||
return;
|
||
}
|
||
return Promise.all(ids.map(function (id) {
|
||
return extendOne(id, config).then(function () {
|
||
return { id: id, succeeded: true };
|
||
}, function (error) {
|
||
return { id: id, succeeded: false, error: error.message };
|
||
});
|
||
})).then(function (results) {
|
||
var succeeded = 0;
|
||
var errors = [];
|
||
for (var index = 0; index < results.length; index++) {
|
||
if (results[index].succeeded) { succeeded++; }
|
||
else { errors.push('#' + results[index].id + ': ' + results[index].error); }
|
||
}
|
||
var message = 'Erfolgreich aktualisiert: ' + succeeded + '; Fehler: ' + errors.length;
|
||
if (errors.length) { message += '\n\n' + errors.slice(0, 10).join('\n'); }
|
||
alert(message);
|
||
if (succeeded > 0) { window.location.reload(); }
|
||
});
|
||
}).catch(function (error) { alert(error.message); });
|
||
}
|
||
|
||
function canExtend() {
|
||
return selectedIds().length > 0;
|
||
}
|
||
|
||
function settingsRequested() {
|
||
return /(?:\?|&)expiryIndicatorSettings=(?:1|true|yes)(?:&|$)/i.test(window.location.search);
|
||
}
|
||
|
||
function openSettings() {
|
||
loadConfig(state.context).then(function (config) {
|
||
var overlay = document.createElement('div');
|
||
overlay.style.cssText = 'position:fixed;z-index:100000;inset:0;background:rgba(0,0,0,.35);padding:5vh 10vw';
|
||
var panel = document.createElement('div');
|
||
panel.style.cssText = 'background:#fff;padding:20px;height:80vh;font-family:Segoe UI,Arial;box-sizing:border-box';
|
||
panel.innerHTML = '<h2>ExpiryIndicator-Einstellungen</h2>' +
|
||
'<p>Vollständige JSON-Konfiguration für diese Liste/Bibliothek:</p>' +
|
||
'<textarea style="width:100%;height:60%;box-sizing:border-box;font-family:Consolas"></textarea>' +
|
||
'<div data-error style="color:#a4262c;min-height:24px"></div>' +
|
||
'<div style="text-align:right"><button data-cancel>Abbrechen</button> ' +
|
||
'<button data-save>Speichern</button></div>';
|
||
overlay.appendChild(panel);
|
||
document.body.appendChild(overlay);
|
||
var textarea = panel.querySelector('textarea');
|
||
textarea.value = JSON.stringify(config, null, 2);
|
||
panel.querySelector('[data-cancel]').onclick = function () { document.body.removeChild(overlay); };
|
||
panel.querySelector('[data-save]').onclick = function () {
|
||
var parsed;
|
||
try { parsed = JSON.parse(textarea.value); }
|
||
catch (error) { panel.querySelector('[data-error]').innerHTML = 'Ungültiges JSON: ' + error.message; return; }
|
||
var validationErrors = validateRules(parsed.rules);
|
||
if (validationErrors.length) {
|
||
panel.querySelector('[data-error]').innerHTML = validationErrors.join('<br>');
|
||
return;
|
||
}
|
||
parsed.expiryField = state.field.InternalName;
|
||
var body = {
|
||
'__metadata': { 'type': state.field.__metadata && state.field.__metadata.type || 'SP.Field' },
|
||
'ClientSideComponentProperties': JSON.stringify(parsed)
|
||
};
|
||
var fieldId = String(state.field.Id).replace(/[{}]/g, '');
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.open('POST', listUrl(state.context) + "/fields(guid'" + fieldId + "')", true);
|
||
xhr.setRequestHeader('Accept', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('Content-Type', 'application/json;odata=verbose');
|
||
xhr.setRequestHeader('OData-Version', '3.0');
|
||
xhr.setRequestHeader('IF-MATCH', '*');
|
||
xhr.setRequestHeader('X-HTTP-Method', 'MERGE');
|
||
var digest = document.getElementById('__REQUESTDIGEST');
|
||
if (digest) { xhr.setRequestHeader('X-RequestDigest', digest.value); }
|
||
xhr.onreadystatechange = function () {
|
||
if (xhr.readyState !== 4) { return; }
|
||
if (xhr.status >= 200 && xhr.status < 300) { window.location.reload(); }
|
||
else { panel.querySelector('[data-error]').innerHTML = 'Speichern fehlgeschlagen: ' + xhr.statusText; }
|
||
};
|
||
xhr.send(JSON.stringify(body));
|
||
};
|
||
}).catch(function (error) { alert(error.message); });
|
||
}
|
||
|
||
window.ExpiryIndicatorClassic = {
|
||
canExtend: canExtend,
|
||
extendSelected: extendSelected,
|
||
openSettings: openSettings,
|
||
render: render
|
||
};
|
||
|
||
function register() {
|
||
if (window.SPClientTemplates && SPClientTemplates.TemplateManager) {
|
||
var overrides = { OnPostRender: render };
|
||
var expiryField = configuredExpiryField() || discoverExpiryField();
|
||
if (expiryField) {
|
||
overrides.Templates = { Fields: {} };
|
||
overrides.Templates.Fields[expiryField] = {
|
||
View: function (context) {
|
||
var item = context.CurrentItem || {};
|
||
var id = Number(item.ID || item.Id);
|
||
var date = parseDate(item[expiryField]);
|
||
var value = date ? formatDate(date) : '';
|
||
var encoded = window.STSHtmlEncode ? STSHtmlEncode(value) : value;
|
||
return '<span data-expiry-classic-item-id="' + id + '">' + encoded + '</span>';
|
||
}
|
||
};
|
||
}
|
||
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrides);
|
||
}
|
||
if (settingsRequested()) { setTimeout(openSettings, 0); }
|
||
}
|
||
|
||
if (window.SPClientTemplates) { register(); }
|
||
else if (window._spBodyOnLoadFunctionNames) { window._spBodyOnLoadFunctionNames.push('ExpiryIndicatorClassicRegister'); }
|
||
window.ExpiryIndicatorClassicRegister = register;
|
||
if (window.NotifyScriptLoadedAndExecuteWaitingJobs) {
|
||
window.NotifyScriptLoadedAndExecuteWaitingJobs('ExpiryIndicatorClassic.js');
|
||
}
|
||
})(window, document);
|