antville/code/Skin/Skin.js
Tobi Schäfer d2501c2d3a Replace for..each loops with for..of
💡 Needs Helma with enabled ES6 features in Rhino
2023-08-27 00:09:17 +02:00

463 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 20012014 by the Workers of Antville.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileOverview Defines the Skin prototype
*/
markgettext('Skin');
markgettext('skin');
markgettext('a skin // accusative');
/**
*
* @param {String} group
* @param {String} name
* @returns {Skin}
*/
Skin.getByName = function(group, name) {
var skinSet = (res.handlers.layout || path.layout).skins.get(group);
if (skinSet) {
var skin = skinSet.get(name);
if (skin) {
return skin;
}
}
return null;
}
/**
* @param {String} prototype
* @param {String} name
* @param {Layout} layout
*/
Skin.add = function(prototype, name, layout) {
var skin = new Skin(prototype, name);
layout.skins.add(skin);
return skin;
}
/**
*
* @param {Skin} skin
*/
Skin.remove = function() {
if (this.constructor === Skin) {
this.setSource(this.source);
this.source = null;
this.remove();
}
return;
}
/**
* @returns {String[]}
*/
Skin.getPrototypeOptions = function() {
var prototypes = [];
var content, file;
var skinFiles = app.getSkinfilesInPath(res.skinpath);
for (var name in skinFiles) {
// Include root skins only for root site
if (name === root.constructor.name && res.handlers.site !== root) {
continue;
}
if (skinFiles[name][name]) {
prototypes.push({value: name, display: name});
}
}
return prototypes.sort(new String.Sorter('display'));
}
/**
* @name Skin
* @constructor
* @param {String} prototype
* @param {String} name
* @property {Date} created
* @property {User} creator
* @property {Layout} layout
* @property {Date} modified
* @property {User} modifier
* @property {String} prototype
* @property {String} source
* @extends HopObject
*/
Skin.prototype.constructor = function(prototype, name) {
HopObject.confirmConstructor(this);
this.prototype = prototype || String.EMPTY;
this.name = name || String.EMPTY;
this.creator = this.modifier = session.user;
this.created = this.modified = new Date;
return this;
}
/**
*
* @param {String} action
* @returns {Boolean}
*/
Skin.prototype.getPermission = function(action) {
switch (action) {
case '.':
case 'main':
return true;
case 'edit':
return res.handlers.layout.getPermission('main');
}
return this.isPersistent() && res.handlers.skins.getPermission('main');
}
/**
*
* @param {String} action
* @returns {String}
*/
Skin.prototype.href = function(action) {
res.push();
res.write(res.handlers.layout.skins.href());
res.write(this.prototype);
res.write('/');
res.write(this.name);
res.write('/');
action && (res.write(action));
return res.pop();
}
Skin.prototype.main_action = function() {
if (res.handlers.site === root) {
res.contentType = 'text/plain';
res.write(this.getSource());
return;
}
res.redirect(this.href('edit'));
return;
}
Skin.prototype.edit_action = function() {
if (req.postParams.save) {
try {
var url = this.href(req.action);
this.update(req.postParams);
res.message = gettext('The changes were saved successfully.');
if (req.postParams.save == 1) {
res.redirect(url);
} else {
res.redirect(res.handlers.layout.skins.href('modified'));
}
} catch (ex) {
res.message = ex;
app.log(ex);
}
}
res.data.action = this.href(req.action);
res.data.title = gettext('Edit {0}.{1}', this.prototype, this.name);
res.data.body = this.renderSkinAsString('$Skin#edit');
res.handlers.skins.renderSkin('$Skins#page');
return;
}
/**
*
* @param {Object} data
*/
Skin.prototype.update = function(data) {
if (this.isTransient()) {
res.handlers.layout.skins.add(this);
this.source = this.getSource(); // Copies the skin file source to database
}
if (this.prototype === 'Site' && this.name === 'page') {
var macro = 'response.body';
if (!createSkin(data.source).containsMacro(macro)) {
var macro = ['<code><%', macro, '%></code>'].join(String.EMPTY);
throw Error(gettext('The {0} macro is missing. It is essential for accessing the site and must be present in this skin.', macro));
}
}
this.setSource(data.source);
this.touch();
return;
}
Skin.prototype.reset_action = function() {
if (req.postParams.proceed) {
try {
Skin.remove.call(this);
res.message = gettext('{0} was successfully reset.', gettext('Skin'));
res.redirect(res.handlers.layout.skins.href('modified'));
} catch(ex) {
res.message = ex;
app.log(ex);
}
}
res.data.action = this.href(req.action);
res.data.title = gettext('Confirm Reset');
res.data.body = this.renderSkinAsString('$HopObject#confirm', {
text: this.getConfirmText()
});
res.handlers.site.renderSkin('Site#page');
return;
}
Skin.prototype.compare_action = function() {
var originalSkin = this.source || String.EMPTY;
var diff = this.getSource().diff(originalSkin);
if (!diff) {
res.message = gettext('No differences were found.');
} else {
res.push();
var param = {}, leftLineNumber = rightLineNumber = 0;
for (let line of diff) {
if (line.deleted) {
param.right = encode(line.value);
param.leftStatus = 'added';
param.rightStatus = '';
for (let i=0; i<line.deleted.length; i++) {
leftLineNumber += 1;
param.leftLineNumber = leftLineNumber;
param.rightLineNumber = '';
param.left = encode(line.deleted[i]);
param.right = '';
this.renderSkin('$Skin#difference', param);
}
}
if (line.inserted) {
param.left = encode(line.value);
param.leftStatus = '';
param.rightStatus = 'removed';
for (let i=0; i<line.inserted.length; i++) {
rightLineNumber += 1;
param.leftLineNumber = '';
param.rightLineNumber = rightLineNumber;
param.left = '';
param.right = encode(line.inserted[i]);
this.renderSkin('$Skin#difference', param);
}
}
if (line.value !== null) {
leftLineNumber += 1;
rightLineNumber += 1;
param.leftLineNumber = leftLineNumber;
param.rightLineNumber = rightLineNumber;
param.leftStatus = param.rightStatus = '';
param.left = encode(line.value);
param.right = param.left;
this.renderSkin('$Skin#difference', param);
}
}
res.data.diff = res.pop();
}
res.data.title = gettext('Compare {0}', this.getTitle());
res.data.body = this.renderSkinAsString('$Skin#compare');
res.handlers.skins.renderSkin('$Skins#page');
return;
}
/**
*
* @return {String}
*/
Skin.prototype.getTitle = function() {
return this.prototype + '.' + this.name;
}
/**
*
* @param {String} name
* @return {Object}
*/
Skin.prototype.getFormOptions = function(name) {
switch (name) {
case 'prototype':
return Skin.getPrototypeOptions();
}
}
Skin.prototype.getFormValue = function(name) {
switch (name) {
case 'source':
return req.data.source || this.getSource();
}
return HopObject.prototype.getFormValue.apply(this, arguments);
}
/**
* @returns {String}
*/
Skin.prototype.getSource = function() {
var skin;
// FIXME: Maintain skin inheritance by checking if we target the Site skin of root
if (res.handlers.site === root && this.prototype === 'Site') {
skin = this.getSubskin('Root');
if (skin) {
return skin.getSource();
}
}
skin = this.getSubskin();
if (skin) {
return skin.getSource();
}
return null;
}
/**
*
* @param {String} source
*/
Skin.prototype.setSource = function(source) {
// FIXME: Maintain skin inheritance by checking if we target the Site skin of root
var prototype = (res.handlers.site === root && this.prototype === 'Site') ? 'Root' : this.prototype;
var skin = this.getMainSkin(prototype);
if (!skin) {
return;
}
res.push();
if (source != null) {
res.writeln('<% #' + this.name + ' %>');
res.writeln(source.trim().replace(/(<%\s*)#/g, '$1// #'));
}
var subskins = skin.getSubskinNames();
for (var i in subskins) {
if (subskins[i] !== this.name) {
res.writeln('<% #' + subskins[i] + ' %>');
source = skin.getSubskin(subskins[i]).source;
source && res.writeln(source.trim());
}
}
source = res.pop();
var file = this.getStaticFile();
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
var fos = new java.io.FileOutputStream(file);
var bos = new java.io.BufferedOutputStream(fos);
var writer = new java.io.OutputStreamWriter(bos, 'UTF-8');
writer.write(source);
writer.close();
bos.close();
fos.close();
this.clearCache();
return;
}
/**
*
* @returns {java.io.File}
*/
Skin.prototype.getStaticFile = function() {
// FIXME: Maintain skin inheritance by checking if we target the Site skin of root
var prototype = (res.handlers.site === root && this.prototype === 'Site') ? 'Root' : this.prototype;
return new java.io.File(res.skinpath[0], prototype + '/' + this.prototype + '.skin');
}
/**
* @param {String} prototype
* @returns {Skin}
*/
Skin.prototype.getMainSkin = function(prototype) {
var source, skinSet = app.getSkinfilesInPath(res.skinpath)[prototype || this.prototype];
if (skinSet) {
source = skinSet[this.prototype];
if (source !== null) {
return createSkin(source);
}
}
return null;
}
/**
*
* @param prototype
* @param name
* @returns {Skin}
*/
Skin.prototype.getSubskin = function(prototype, name) {
var mainSkin = this.getMainSkin(prototype);
if (mainSkin) {
return mainSkin.getSubskin(name || this.name);
}
return null;
}
/**
*
*/
Skin.prototype.render = function() {
return renderSkin(createSkin(this.getSource()));
}
/**
*
* @param {String} source
* @returns {Boolean}
*/
Skin.prototype.equals = function(source) {
// FIXME: The removal of linebreaks is necessary but it's not very nice
var re = /\r|\n/g;
var normalize = function(str) {
return str.replace(re, String.EMPTY);
}
return normalize(source) === normalize(this.getSource());
}
/**
* @returns {String}
*/
Skin.prototype.getConfirmText = function() {
return gettext('You are about to reset the skin {0}.{1}.',
this.prototype, this.name);
}
/**
* @returns {String}
*/
Skin.prototype.toString = function() {
return 'Skin #' + this._id + ': ' + this.prototype + '.' + this.name;
}
/**
*
*/
Skin.prototype.status_macro = function() {
return this.isTransient() ? 'inherited' : 'modified';
}
/**
*
*/
Skin.prototype.content_macro = function() {
return res.write(this.getSource());
}
Skin.prototype.macro_macro = function () {
var name = this.prototype === 'Global' ? this.name : this.prototype + '.' + this.name;
res.encode('<% ');
res.write('skin ');
res.write(quote(name, '\\s'));
res.encode(' %>');
return;
};
Skin.prototype.custom_macro = function () {
return this.isPersistent() && !this.source;
};