/** * EGroupware eTemplate2 - JS Diff object * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage api * @link https://www.egroupware.org * @author Nathan Gray * @copyright Nathan Gray 2012 */ /*egw:uses /vendor/bower-asset/jquery/dist/jquery.js; /vendor/bower-asset/jquery-ui/jquery-ui.js; /vendor/bower-asset/diff2html/dist/diff2html.min.js; et2_core_valueWidget; */ import "../../../vendor/bower-asset/diff2html/dist/diff2html.min"; import {et2_register_widget, WidgetConfig} from "./et2_core_widget"; import {ClassWithAttributes} from "./et2_core_inheritance"; import {et2_valueWidget} from "./et2_core_valueWidget"; import {et2_IDetachedDOM} from "./et2_core_interfaces"; import {Et2Dialog} from "./Et2Dialog/Et2Dialog"; /** * Class that displays the diff between two [text] values * * @augments et2_valueWidget */ export class et2_diff extends et2_valueWidget implements et2_IDetachedDOM { static readonly _attributes = { "value": { "type": "any" } }; private readonly diff_options: { "inputFormat":"diff", "matching": "words" }; private div: HTMLDivElement; private mini: boolean = true; /** * Constructor */ constructor(_parent, _attrs? : WidgetConfig, _child? : object) { // Call the inherited constructor super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_diff._attributes, _child || {})); // included via etemplate2.css //this.egw().includeCSS('../../../vendor/bower-asset/dist/dist2html.css'); this.div = document.createElement("div"); jQuery(this.div).addClass('et2_diff'); } set_value( value) { jQuery(this.div).empty(); if(typeof value == 'string') { // Diff2Html likes to have files, we don't have them if(value.indexOf('---') !== 0) { value = "--- diff\n+++ diff\n"+value; } // @ts-ignore var diff = Diff2Html.getPrettyHtml(value, this.diff_options); // var ui = new Diff2HtmlUI({diff: diff}); // ui.draw(jQuery(this.div), this.diff_options); jQuery(this.div).append(diff); } else if(typeof value != 'object') { jQuery(this.div).append(value); } this.check_mini(); } check_mini( ) { if(!this.mini) { return false; } var view = jQuery(this.div).children(); this.minify(view); var self = this; jQuery('<span class="ui-icon ui-icon-circle-plus"> </span>') .appendTo(self.div) .css("cursor", "pointer") .click({diff: view, div: self.div, label: self.options.label}, function(e) { var diff = e.data.diff; var div = e.data.div; self.un_minify(diff); let dialog = new Et2Dialog(self.egw()); dialog.transformAttributes({ title: e.data.label, //modal: true, buttons: [{label: 'ok'}], class: "et2_diff", }); diff.attr("slot", "content"); dialog.addEventListener("open", () => { diff.appendTo(dialog); if(jQuery(this).parent().height() > jQuery(window).height()) { jQuery(this).height(jQuery(window).height() * 0.7); } }); dialog.addEventListener("close", () => { // Need to destroy the dialog, etemplate widget needs divs back where they were self.minify(this); // Put it back where it came from, or et2 will error when clear() is called diff.prependTo(div); }); document.body.appendChild(dialog); }); } set_label( _label) { this.options.label = _label; } /** * Make the diff into a mini-diff * * @param {DOMNode|String} view */ minify( view) { view = jQuery(view) .addClass('mini') // Dialog changes these, if resized .css('height', 'inherit') .show(); jQuery('th', view).hide(); jQuery('td.equal',view).hide() .prevAll().hide(); } /** * Expand mini-diff * * @param {DOMNode|String} view */ un_minify( view) { jQuery(view).removeClass('mini').show(); jQuery('th',view).show(); jQuery('td.equal',view).show(); } /** * Code for implementing et2_IDetachedDOM * Fast-clonable read-only widget that only deals with DOM nodes, not the widget tree */ /** * Build a list of attributes which can be set when working in the * "detached" mode in the _attrs array which is provided * by the calling code. * * @param {object} _attrs */ getDetachedAttributes(_attrs) { _attrs.push("value", "label"); } /** * Returns an array of DOM nodes. The (relativly) same DOM-Nodes have to be * passed to the "setDetachedAttributes" function in the same order. */ getDetachedNodes() { return [this.div]; } /** * Sets the given associative attribute->value array and applies the * attributes to the given DOM-Node. * * @param _nodes is an array of nodes which has to be in the same order as * the nodes returned by "getDetachedNodes" * @param _values is an associative array which contains a subset of attributes * returned by the "getDetachedAttributes" function and sets them to the * given values. */ setDetachedAttributes(_nodes, _values) { this.div = _nodes[0]; if(typeof _values['label'] != 'undefined') { this.set_label(_values['label']); } if(typeof _values['value'] != 'undefined') { this.set_value(_values['value']); } } } et2_register_widget(et2_diff, ["diff"]);