mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-30 10:39:18 +01:00
273 lines
7.2 KiB
TypeScript
273 lines
7.2 KiB
TypeScript
/**
|
|
* EGroupware eTemplate2 - JS Template base class
|
|
*
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package etemplate
|
|
* @subpackage api
|
|
* @link https://www.egroupware.org
|
|
* @author Andreas Stöckel
|
|
*/
|
|
|
|
/*egw:uses
|
|
et2_core_xml;
|
|
et2_core_DOMWidget;
|
|
*/
|
|
|
|
import './et2_core_interfaces';
|
|
import {et2_DOMWidget} from './et2_core_DOMWidget';
|
|
import {ClassWithAttributes} from "./et2_core_inheritance";
|
|
import {et2_register_widget, WidgetConfig} from "./et2_core_widget";
|
|
import {etemplate2} from "./etemplate2";
|
|
import {et2_cloneObject, et2_no_init} from "./et2_core_common";
|
|
import {et2_loadXMLFromURL} from "./et2_core_xml";
|
|
import {egw} from "../jsapi/egw_global";
|
|
|
|
/**
|
|
* Class which implements the "template" XET-Tag. When the id parameter is set,
|
|
* the template class checks whether another template with this id already
|
|
* exists. If yes, this template is removed from the DOM tree, copied and
|
|
* inserted in place of this template.
|
|
*/
|
|
export class et2_template extends et2_DOMWidget
|
|
{
|
|
static readonly _attributes : any = {
|
|
"template": {
|
|
"name": "Template",
|
|
"type": "string",
|
|
"description": "Name / ID of template with optional cache-buster ('?'+filemtime of template on server)",
|
|
"default": et2_no_init
|
|
},
|
|
"group": {
|
|
// TODO: Not implemented
|
|
"name": "Group",
|
|
"description":"Not implemented",
|
|
//"default": 0
|
|
"default": et2_no_init
|
|
},
|
|
"version": {
|
|
"name": "Version",
|
|
"type": "string",
|
|
"description": "Version of the template"
|
|
},
|
|
"lang": {
|
|
"name": "Language",
|
|
"type": "string",
|
|
"description": "Language the template is written in"
|
|
},
|
|
"content": {
|
|
"name": "Content index",
|
|
"default": et2_no_init,
|
|
"description": "Used for passing in specific content to the template other than what it would get by ID."
|
|
},
|
|
url: {
|
|
name: "URL of template",
|
|
type: "string",
|
|
description: "full URL to load template incl. cache-buster"
|
|
},
|
|
"onload": {
|
|
"name": "onload",
|
|
"type": "js",
|
|
"default": et2_no_init,
|
|
"description": "JS code which is executed after the template is loaded."
|
|
}
|
|
};
|
|
|
|
content : string;
|
|
div : HTMLDivElement;
|
|
loading : Promise<any>;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
constructor(_parent, _attrs? : WidgetConfig, _child? : object)
|
|
{
|
|
// Call the inherited constructor
|
|
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_template._attributes, _child || {}));
|
|
|
|
// Set this early, so it's available for creating namespace
|
|
if(_attrs.content)
|
|
{
|
|
this.content = _attrs.content;
|
|
}
|
|
// constructor was called here before!
|
|
|
|
this.div = document.createElement("div");
|
|
|
|
// Deferred object so we can load via AJAX
|
|
this.loading = new Promise<any>((resolve, reject) =>
|
|
{
|
|
|
|
// run transformAttributes now, to get server-side modifications (url!)
|
|
if(_attrs.template)
|
|
{
|
|
this.id = _attrs.template;
|
|
this.transformAttributes(_attrs);
|
|
this.options = et2_cloneObject(_attrs);
|
|
_attrs = {};
|
|
}
|
|
if(this.id != "" || this.options.template)
|
|
{
|
|
var parts = (this.options.template || this.id).split('?');
|
|
var cache_buster = parts.length > 1 ? parts.pop() : null;
|
|
var template_name = parts.pop();
|
|
|
|
// Check to see if XML is known
|
|
var xml = null;
|
|
var templates = etemplate2.templates; // use global eTemplate cache
|
|
if(!(xml = templates[template_name]))
|
|
{
|
|
// Check to see if ID is short form --> prepend parent/top-level name
|
|
if(template_name.indexOf('.') < 0)
|
|
{
|
|
var root = _parent ? _parent.getRoot() : null;
|
|
var top_name = root && root._inst ? root._inst.name : null;
|
|
if(top_name && template_name.indexOf('.') < 0)
|
|
{
|
|
template_name = top_name + '.' + template_name;
|
|
}
|
|
}
|
|
xml = templates[template_name];
|
|
if(!xml)
|
|
{
|
|
// Ask server
|
|
var url = this.options.url;
|
|
if(!this.options.url)
|
|
{
|
|
var splitted = template_name.split('.');
|
|
var app = splitted.shift();
|
|
url = egw.link('/'+ app + "/templates/default/" +
|
|
splitted.join('.')+ ".xet", {download:cache_buster? cache_buster :(new Date).valueOf()});
|
|
}
|
|
// if server did not give a cache-buster, fall back to current time
|
|
if (url.indexOf('?') == -1) url += '?download='+(new Date).valueOf();
|
|
|
|
if(this.options.url || splitted.length)
|
|
{
|
|
var fetch_url_callback = function(_xmldoc)
|
|
{
|
|
// Scan for templates and store them
|
|
for(var i = 0; i < _xmldoc.childNodes.length; i++)
|
|
{
|
|
var template = _xmldoc.childNodes[i];
|
|
if(template.nodeName.toLowerCase() != "template")
|
|
{
|
|
continue;
|
|
}
|
|
templates[template.getAttribute("id")] = template;
|
|
}
|
|
|
|
// Read the XML structure of the requested template
|
|
if(typeof templates[template_name] != 'undefined')
|
|
{
|
|
this.loadFromXML(templates[template_name]);
|
|
}
|
|
|
|
// Update flag
|
|
resolve();
|
|
}.bind(this);
|
|
|
|
et2_loadXMLFromURL(url, fetch_url_callback, this, function( error) {
|
|
url = egw.link('/'+ app + "/templates/default/" +
|
|
splitted.join('.')+ ".xet", {download:cache_buster? cache_buster :(new Date).valueOf()});
|
|
|
|
et2_loadXMLFromURL(url, fetch_url_callback, this);
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if(xml !== null && typeof xml !== "undefined")
|
|
{
|
|
this.egw().debug("log", "Loading template from XML: ", template_name);
|
|
this.loadFromXML(xml);
|
|
// Don't call this here - done by caller, or on whole widget tree
|
|
//this.loadingFinished();
|
|
|
|
// But resolve the promise
|
|
resolve();
|
|
}
|
|
else
|
|
{
|
|
this.egw().debug("warn", "Unable to find XML for ", template_name);
|
|
reject("Unable to find XML for " + template_name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No actual template - not an error, just nothing to do
|
|
resolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Override parent to support content attribute
|
|
* Templates always have ID set, but seldom do we want them to
|
|
* create a namespace based on their ID.
|
|
*/
|
|
checkCreateNamespace(_attrs)
|
|
{
|
|
if(_attrs.content)
|
|
{
|
|
var old_id = _attrs.id;
|
|
this.id = _attrs.content;
|
|
super.checkCreateNamespace.apply(this, arguments);
|
|
this.id = old_id;
|
|
}
|
|
}
|
|
|
|
_createNamespace() : boolean
|
|
{
|
|
return true;
|
|
}
|
|
|
|
getDOMNode()
|
|
{
|
|
return this.div;
|
|
}
|
|
|
|
attachToDOM()
|
|
{
|
|
if (this.div)
|
|
{
|
|
jQuery(this.div)
|
|
.off('.et2_template')
|
|
.bind("load.et2_template", this, function(e) {
|
|
e.data.load.call(e.data, this);
|
|
});
|
|
}
|
|
|
|
return super.attachToDOM();
|
|
}
|
|
|
|
/**
|
|
* Called after the template is fully loaded to handle any onload handlers
|
|
*/
|
|
load()
|
|
{
|
|
if(typeof this.options.onload == 'function')
|
|
{
|
|
// Make sure function gets a reference to the widget
|
|
var args = Array.prototype.slice.call(arguments);
|
|
if(args.indexOf(this) == -1) args.push(this);
|
|
|
|
return this.options.onload.apply(this, args);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Override to return the promise for deferred loading
|
|
*/
|
|
doLoadingFinished()
|
|
{
|
|
// Apply parent now, which actually puts into the DOM
|
|
super.doLoadingFinished();
|
|
|
|
// Fire load event when done loading
|
|
this.loading.then(function() {jQuery(this).trigger("load");}.bind(this.div));
|
|
|
|
// Not done yet, but widget will let you know
|
|
return this.loading;
|
|
}
|
|
}
|
|
et2_register_widget(et2_template, ["template"]); |