Commit 3c63549f authored by Romain Courteaud's avatar Romain Courteaud

erp5_forge: action to commit from erp5js

* add color in the commit tree
* send one json only
* display the list of removed files in the gadget diff
* translate gadget
* desactivated changelog
parent 0a1ce503
......@@ -16,13 +16,13 @@
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
<string>action_type/object_onlyxhtml_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
<value> <string>object_onlyxhtml_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_onlyjio_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_onlyjio_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>git_commit_action</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Manage portal</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>4.5</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Git</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/BusinessTemplate_viewVcsStatusDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: here.getInstallationState() not in (\'installed\', \'replaced\') and here.isVcsType(\'git\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
import json
vcs_tool = context.getVcsTool()
result_dict = {
'added_list': [],
'modified_list': [],
'deleted_list': []
}
for path in modified:
result_dict['modified_list'].append({
'path': path,
# 'edit_path': vcs_tool.editPath(path, True),
'diff': vcs_tool.diff(path)
})
for path in added:
result_dict['added_list'].append({
'path': path
})
for path in deleted:
result_dict['deleted_list'].append({
'path': path
})
if REQUEST is not None:
REQUEST.RESPONSE.setHeader('Content-Type', 'application/hal+json')
return json.dumps(result_dict, indent=2)
else:
return result_dict
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>added=(), modified=(), deleted=(), REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BusinessTemplate_doVcsDiffAsJson</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>BusinessTemplate_doVcsCommit</string> </value>
</item>
<item>
<key> <string>action_title</string> </key>
<value> <string>Commit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>your_commit_json</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BusinessTemplate_viewVcsStatusDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>BusinessTemplate_viewVcsStatusDialog</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>ERP5 Form</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>VCS Status</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>gadget_url</string>
<string>renderjs_extra</string>
<string>title</string>
<string>validator_field_id</string>
<string>validator_form_id</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_commit_json</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>renderjs_extra</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>validator_form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_gadget_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value> <string>gadget_vcs_status.html</string> </value>
</item>
<item>
<key> <string>renderjs_extra</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Gadget</string> </value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>my_core_mode_text_content_validator</string> </value>
</item>
<item>
<key> <string>validator_form_id</string> </key>
<value> <string>erp5_core/Base_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [(\'default_push\', preferences.getPreferredVcsPushMode() and not here.getVcsTool().getAheadCount()), (\'default_changelog\', "{}: ".format(context.getTitle())), (\'diff_url\', \'%s/BusinessTemplate_doVcsDiffAsJson\' % here.absolute_url()), (\'get_tree_url\', \'%s/tree.xml\' % here.absolute_url()), (\'remote_url\', here.getVcsTool().getRemoteUrl()), (\'remote_comment\', here.getVcsTool().getRemoteComment())]</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>string:</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
div[data-gadget-url$="gadget_vcs_status.html"] {
background-color: #FFFFFF;
}
div[data-gadget-url$="gadget_vcs_status.html"] li li {
padding-left: 1em;
}
div[data-gadget-url$="gadget_vcs_status.html"] li input.showhide {
display: none;
}
div[data-gadget-url$="gadget_vcs_status.html"] li input.showhide:checked ~ label.show {
display: none;
}
div[data-gadget-url$="gadget_vcs_status.html"] li input.showhide:checked ~ ul {
display: none;
}
div[data-gadget-url$="gadget_vcs_status.html"] li input.showhide:not(:checked) ~ label.hide {
display: none;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label {
display: inline-block;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label.showhide {
width: 1em;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label input {
margin: 0 3pt;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label.added {
color: #22CC22;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label.modified {
color: #FF6600;
}
div[data-gadget-url$="gadget_vcs_status.html"] li label.removed {
color: red;
}
div[data-gadget-url$="gadget_vcs_status.html"] button {
color: #212529;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
display: inline-block;
margin-right: 6pt;
}
div[data-gadget-url$="gadget_vcs_status.html"] button:disabled,
div[data-gadget-url$="gadget_vcs_status.html"] button[disabled] {
color: #999999;
}
div[data-gadget-url$="gadget_vcs_status.html"] button:before {
padding-right: 0.2em;
}
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>must_revalidate_http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_vcs_status.css</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/css</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<!DOCTYPE html>
<html>
<head>
<!--
data-i18n=Added Files
data-i18n=Modified Files
data-i18n=Removed Files
data-i18n=Tree
data-i18n=Diff
data-i18n=Changelog
data-i18n=Expand
data-i18n=Push
-->
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>VCS status gadget</title>
<link rel=stylesheet href="gadget_vcs_status.css">
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="jio.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<script src="gadget_vcs_status.js" type="text/javascript"></script>
</head>
<body>
<div class="vcsheader"></div>
<div class="vcsbody"></div>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>must_revalidate_http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_vcs_status.html</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*global window, rJS, RSVP, domsugar, jIO, console, document, NodeFilter,
FormData */
/*jslint nomen: true, maxlen:80, indent:2*/
(function (window, rJS, RSVP, domsugar, jIO, console, document, NodeFilter) {
"use strict";
var whitelist = {
node_list: {
P: true,
UL: true,
LI: true,
INPUT: true,
LABEL: true
},
attribute_list: {
type: true,
class: true,
id: true,
for: true,
name: true,
value: true
}
},
DISPLAY_TREE = 'display_tree',
DISPLAY_DIFF = 'display_diff',
DISPLAY_CHANGELOG = 'display_changelog';
function getTranslationDict(gadget) {
var word_list = ['Added Files', 'Modified Files', 'Removed Files',
'Tree', 'Diff', 'Changelog', 'Expand', 'Push'];
return gadget.getTranslationList(word_list)
.push(function (result_list) {
var result = {},
i;
for (i = 0; i < word_list.length; i += 1) {
result[word_list[i]] = result_list[i];
}
return result;
});
}
function keepOnlyChildren(current_node) {
var fragment = document.createDocumentFragment();
while (current_node.firstChild) {
fragment.appendChild(current_node.firstChild);
}
current_node.parentNode.replaceChild(
fragment,
current_node
);
}
function renderTreeXml(gadget, tree_xml_element) {
var iterator,
current_node,
next_node,
parent_node,
value,
ul_node,
attribute,
attribute_list,
child_list,
len,
finished = false,
id = -1,
name,
state_value = JSON.parse(gadget.state.value);
// Replace the tree element by a fragment
next_node = domsugar('ul');
while (tree_xml_element.firstChild) {
next_node.appendChild(tree_xml_element.firstChild);
}
tree_xml_element = next_node;
iterator = document.createNodeIterator(
tree_xml_element,
NodeFilter.SHOW_ELEMENT,
function () {
return NodeFilter.FILTER_ACCEPT;
}
);
while (!finished) {
current_node = iterator.nextNode();
finished = (current_node === null);
if (!finished) {
if (current_node.nodeName === 'item') {
child_list = [];
// Open/hide element
if (current_node.firstChild) {
id += 1;
child_list.push(
domsugar('input', {type: 'checkbox', id: 'showhide' + id,
class: 'showhide'}),
domsugar('label', {for: 'showhide' + id, class: 'showhide show',
text: '-'}),
domsugar('label', {for: 'showhide' + id, class: 'showhide hide',
text: '+'})
);
} else {
child_list.push(
domsugar('label', {class: 'showhide', text: ' '})
);
}
// Select element
parent_node = current_node.closest('ul');
if (parent_node !== null) {
parent_node = parent_node.parentNode;
}
if (parent_node !== null) {
parent_node = parent_node.querySelector('input.vcs_to_commit');
}
value = current_node.getAttribute('text');
if ((parent_node !== null) && (parent_node !== current_node)) {
if (parent_node.value) {
value = parent_node.value + '/' + value;
}
} else {
value = '';
}
name = {
'green': 'added',
'orange': 'modified',
'red': 'removed'
}[current_node.getAttribute('aCol')];
child_list.push(domsugar('label', {
class: name
}, [
domsugar('input', {
type: 'checkbox',
class: 'vcs_to_commit',
value: value,
name: name,
checked: ((state_value[name] === undefined) ||
(state_value[name].indexOf(value) === -1)) ? '' :
'checked'
}),
current_node.getAttribute('text')
]));
// Child items
if (current_node.firstChild) {
ul_node = domsugar('ul');
while (current_node.firstChild) {
ul_node.appendChild(current_node.firstChild);
}
child_list.push(ul_node);
}
current_node.parentNode.replaceChild(
domsugar('li', child_list),
current_node
);
} else if (!whitelist.node_list[current_node.nodeName]) {
keepOnlyChildren(current_node);
} else {
// Cleanup attributes
attribute_list = current_node.attributes;
len = attribute_list.length;
while (len !== 0) {
len = len - 1;
attribute = attribute_list[len].name;
if (!whitelist.attribute_list[attribute]) {
current_node.removeAttribute(attribute);
}
}
}
}
}
return tree_xml_element;
}
function renderGadgetHeader(gadget, loading, translation_dict) {
var element_list = [
domsugar('p', [
'Repository: ',
domsugar('a', {
text: gadget.state.remote_url,
href: gadget.state.remote_url
}),
' (' + gadget.state.remote_comment + ')'
])
],
tree_icon = 'ui-icon-check-square',
diff_icon = 'ui-icon-search-plus',
changelog_icon = 'ui-icon-git';
if (loading) {
if (gadget.state.display_step === DISPLAY_TREE) {
tree_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_DIFF) {
diff_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_CHANGELOG) {
changelog_icon = 'ui-icon-spinner';
} else {
throw new Error("Can't render header state " +
gadget.state.display_step);
}
}
element_list.push(
domsugar('button', {
type: 'button',
text: translation_dict.Tree,
disabled: (gadget.state.display_step === DISPLAY_TREE),
class: 'display-tree-btn ui-btn-icon-left ' + tree_icon
}),
domsugar('button', {
type: 'button',
text: translation_dict.Diff,
disabled: (gadget.state.display_step === DISPLAY_DIFF),
class: 'diff-tree-btn ui-btn-icon-left ' + diff_icon
}),
domsugar('button', {
type: 'button',
text: translation_dict.Changelog,
disabled: (gadget.state.display_step === DISPLAY_CHANGELOG),
class: 'changelog-btn ui-btn-icon-left ' + changelog_icon
})
);
if ((!loading) && (gadget.state.display_step === DISPLAY_TREE)) {
element_list.push(
domsugar('button', {
type: 'button',
text: translation_dict.Expand,
class: 'expand-tree-btn ui-btn-icon-left ui-icon-arrows-v'
})
);
}
domsugar(gadget.element.querySelector('div.vcsheader'), element_list);
}
function updateFullTreeCheckbox(checkbox) {
var i,
element_list,
parent_checkbox,
is_checked,
is_indeterminate;
// https://css-tricks.com/indeterminate-checkboxes/
// Check/uncheck all children checkboxes
element_list = checkbox.parentElement
.parentElement
.querySelectorAll('input.vcs_to_commit');
for (i = 0; i < element_list.length; i += 1) {
element_list[i].checked = checkbox.checked;
element_list[i].indeterminate = false;
}
// Check/uncheck/undefine all parent checkboxes
while (checkbox !== null) {
parent_checkbox = checkbox.closest('ul')
.parentNode
.querySelector('input.vcs_to_commit');
if (parent_checkbox === checkbox) {
// Top checkbox
checkbox = null;
} else {
// check the state of all child chexbox
element_list = parent_checkbox.closest('li')
.querySelector('ul')
.children;
is_checked = true;
is_indeterminate = false;
for (i = 0; i < element_list.length; i += 1) {
is_checked = is_checked &&
element_list[i].querySelector('input.vcs_to_commit')
.checked;
is_indeterminate =
is_indeterminate ||
element_list[i].querySelector('input.vcs_to_commit')
.checked ||
element_list[i].querySelector('input.vcs_to_commit')
.indeterminate;
}
parent_checkbox.checked = is_checked;
parent_checkbox.indeterminate = (!is_checked) && is_indeterminate;
checkbox = parent_checkbox;
}
}
}
function renderTreeView(gadget, extract) {
var translation_dict;
return getTranslationDict(gadget)
.push(function (result) {
translation_dict = result;
renderGadgetHeader(gadget, true, translation_dict);
var form_data = new FormData();
form_data.append('show_unmodified:int', 0);
// form_data.append('bt_id', 'erp5');
form_data.append('do_extract:int', extract ? 1 : 0);
return jIO.util.ajax({
"type": "POST",
"url": gadget.state.get_tree_url,
"xhrFields": {
withCredentials: true
},
"dataType": "document",
"data": form_data
});
})
.push(function (evt) {
renderGadgetHeader(gadget, false, translation_dict);
domsugar(gadget.element.querySelector('div.vcsbody'), [
renderTreeXml(gadget, evt.target.response.querySelector('tree'))
]);
// Update the tree parent
var element_list = gadget.element
.querySelectorAll('input.vcs_to_commit'),
i;
for (i = 0; i < element_list.length; i += 1) {
if (element_list[i].checked) {
updateFullTreeCheckbox(element_list[i]);
}
}
});
}
function getContentFromTreeView(gadget) {
var result = JSON.parse(gadget.state.value),
checkbox_list = gadget.element.querySelectorAll('input.vcs_to_commit'),
i,
name;
result.added = [];
result.modified = [];
result.removed = [];
for (i = 0; i < checkbox_list.length; i += 1) {
name = checkbox_list[i].name;
if (name && checkbox_list[i].checked) {
result[name].push(checkbox_list[i].value);
}
}
gadget.state.value = JSON.stringify(result);
}
function expandTreeView(gadget) {
var element_list = gadget.element.querySelectorAll('input.showhide'),
// Do not crash if no checkbox is displayed
is_checked = (element_list.length !== 0) && (!element_list[0].checked),
i;
for (i = 0; i < element_list.length; i += 1) {
element_list[0].checked = is_checked;
}
}
function declareAndRenderDiff(gadget, path, diff) {
return gadget.declareGadget('gadget_erp5_side_by_side_diff.html')
.push(function (diff_gadget) {
return RSVP.all([
diff_gadget.element,
path,
diff_gadget.render({value: diff})
]);
});
}
function renderDiffView(gadget) {
var result = JSON.parse(gadget.state.value),
ajax_result,
diff_count = result.modified.length,
translation_dict;
return getTranslationDict(gadget)
.push(function (result2) {
translation_dict = result2;
renderGadgetHeader(gadget, true, translation_dict);
var form_data = new FormData(),
key_list = ['modified', 'added', 'removed'],
key,
i,
j;
for (i = 0; i < key_list.length; i += 1) {
key = key_list[i];
for (j = 0; j < result[key].length; j += 1) {
form_data.append(key + ':list', result[key][j]);
}
}
return jIO.util.ajax({
"type": "POST",
"url": gadget.state.diff_url,
"xhrFields": {
withCredentials: true
},
"dataType": "json",
"data": form_data
});
})
.push(function (evt) {
ajax_result = evt.target.response;
var promise_list = [],
i;
for (i = 0; i < diff_count; i += 1) {
promise_list.push(
declareAndRenderDiff(
gadget,
ajax_result.modified_list[i].path,
ajax_result.modified_list[i].diff
)
);
}
return RSVP.all(promise_list);
})
.push(function (result_list) {
var i,
element_list = [];
element_list.push(domsugar('h3', {
text: translation_dict['Modified Files']
}));
for (i = 0; i < result_list.length; i += 1) {
element_list.push(
domsugar('label', [
domsugar('input', {
type: 'checkbox',
class: 'vcs_to_commit',
value: result_list[i][1],
name: 'modified',
checked: 'checked'
}),
result_list[i][1]
]),
result_list[i][0]
);
}
element_list.push(domsugar('h3', {
text: translation_dict['Added Files']
}));
for (i = 0; i < ajax_result.added_list.length; i += 1) {
element_list.push(
domsugar('label', [
domsugar('input', {
type: 'checkbox',
class: 'vcs_to_commit',
value: ajax_result.added_list[i].path,
name: 'added',
checked: 'checked'
}),
ajax_result.added_list[i].path
])
);
}
element_list.push(domsugar('h3', {
text: translation_dict['Removed Files']
}));
for (i = 0; i < result.removed.length; i += 1) {
element_list.push(
domsugar('label', [
domsugar('input', {
type: 'checkbox',
class: 'vcs_to_commit',
value: result.removed[i],
name: 'removed',
checked: 'checked'
}),
result.removed[i]
])
);
}
renderGadgetHeader(gadget, false, translation_dict);
domsugar(gadget.element.querySelector('div.vcsbody'), element_list);
});
}
function renderChangelogView(gadget) {
var result = JSON.parse(gadget.state.value);
return getTranslationDict(gadget)
.push(function (translation_dict) {
renderGadgetHeader(gadget, false, translation_dict);
domsugar(gadget.element.querySelector('div.vcsbody'), [
domsugar('label', {text: translation_dict.Push}, [
' ',
domsugar('input', {
type: 'checkbox',
checked: result.push || gadget.state.default_push || false
})
]),
domsugar('h3', {text: translation_dict.Changelog}),
domsugar('textarea', {
value: result.changelog || gadget.state.default_changelog || ''
}),
domsugar('h3', {text: translation_dict['Added Files']}),
domsugar('pre', {text: result.added.join('\n')}),
domsugar('h3', {text: translation_dict['Modified Files']}),
domsugar('pre', {text: result.modified.join('\n')}),
domsugar('h3', {text: translation_dict['Removed Files']}),
domsugar('pre', {text: result.removed.join('\n')})
]);
});
}
function getContentFromChangelogView(gadget) {
var result = JSON.parse(gadget.state.value);
result.changelog = gadget.element.querySelector('textarea').value;
// Ensure user set a changelog
if (result.changelog === gadget.state.default_changelog) {
result.changelog = '';
}
result.push = gadget.element.querySelector('input').checked;
gadget.state.value = JSON.stringify(result);
}
rJS(window)
.declareAcquiredMethod("getTranslationList", "getTranslationList")
.declareMethod('render', function (options) {
return this.changeState({
display_step: DISPLAY_TREE,
// Only build the bt5 during the first query
extract: 1,
diff_url: options.diff_url,
get_tree_url: options.get_tree_url,
remote_comment: options.remote_comment,
remote_url: options.remote_url,
key: options.key,
default_changelog: options.default_changelog,
default_push: options.default_push,
value: options.value || JSON.stringify({
added: [],
modified: [],
removed: [],
changelog: '',
push: false
}),
editable: (options.editable === undefined) ? true : options.editable
});
})
.onStateChange(function (modification_dict) {
var gadget = this;
if (gadget.state.display_step === DISPLAY_TREE) {
console.log(modification_dict);
if (modification_dict.hasOwnProperty('display_step')) {
return renderTreeView(gadget,
modification_dict.hasOwnProperty('extract'));
}
if (modification_dict.hasOwnProperty('expand_tree')) {
return expandTreeView(gadget);
}
}
if (modification_dict.display_step === DISPLAY_DIFF) {
return renderDiffView(gadget);
}
if (modification_dict.display_step === DISPLAY_CHANGELOG) {
return renderChangelogView(gadget);
}
if (modification_dict.hasOwnProperty('display_step')) {
throw new Error('Unhandled display step: ' + gadget.state.display_step);
}
})
.onEvent("change", function (evt) {
var gadget = this,
tag_name = evt.target.tagName;
// Only handle vcs_to_commit checkbox
if ((tag_name !== 'INPUT') ||
(evt.target.className !== 'vcs_to_commit')) {
return;
}
if (gadget.state.display_step !== DISPLAY_TREE) {
return;
}
updateFullTreeCheckbox(evt.target);
}, false, false)
.onEvent("click", function (evt) {
// Only handle click on BUTTON and IMG element
var gadget = this,
tag_name = evt.target.tagName,
queue;
if (tag_name !== 'BUTTON') {
return;
}
// Disable any button. It must be managed by this gadget
evt.preventDefault();
// Always get content to ensure the possible displayed form
// is checked and content propagated to the gadget state value
queue = gadget.getContent();
if (evt.target.className.indexOf("expand-tree-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_TREE,
expand_tree: new Date()
});
});
}
if (evt.target.className.indexOf("display-tree-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_TREE
});
});
}
if (evt.target.className.indexOf("diff-tree-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_DIFF
});
});
}
if (evt.target.className.indexOf("changelog-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_CHANGELOG
});
});
}
throw new Error('Unhandled button: ' + evt.target.textContent);
}, false, false)
//////////////////////////////////////////////////
// Used when submitting the form
//////////////////////////////////////////////////
.declareMethod('getContent', function () {
var gadget = this,
display_step = gadget.state.display_step,
queue;
if (gadget.state.display_step === DISPLAY_TREE) {
queue = new RSVP.Queue(getContentFromTreeView(gadget));
} else if (gadget.state.display_step === DISPLAY_DIFF) {
queue = new RSVP.Queue(getContentFromTreeView(gadget));
} else if (gadget.state.display_step === DISPLAY_CHANGELOG) {
queue = new RSVP.Queue(getContentFromChangelogView(gadget));
} else {
throw new Error('getContent form not handled: ' + display_step);
}
return queue
.push(function () {
var result = {};
if (gadget.state.editable) {
result[gadget.state.key] = gadget.state.value;
}
return result;
});
}, {mutex: 'changestate'})
.declareMethod('checkValidity', function () {
return true;
}, {mutex: 'changestate'})
.declareAcquiredMethod("notifyChange", "notifyChange")
.onEvent('change', function change() {
return RSVP.all([
this.checkValidity(),
this.notifyChange("change")
]);
}, false, false)
.onEvent('input', function input() {
return RSVP.all([
this.checkValidity(),
this.notifyChange("input")
]);
}, false, false)
.declareAcquiredMethod("notifyFocus", "notifyFocus")
.onEvent('focus', function focus() {
return this.notifyFocus();
}, true, false)
.declareAcquiredMethod("notifyBlur", "notifyBlur")
.onEvent('blur', function blur() {
return this.notifyBlur();
}, true, false);
}(window, rJS, RSVP, domsugar, jIO, console, document, NodeFilter));
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>must_revalidate_http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_vcs_status.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
@orange: #FF6600;
@white: #FFFFFF;
@green: #22CC22;
@red: red;
div[data-gadget-url$="gadget_vcs_status.html"] {
background-color: @white;
li {
li {
padding-left: 1em;
}
input.showhide {
display: none;
&:checked ~ label.show {
display: none;
}
&:checked ~ ul {
display: none;
}
&:not(:checked) ~ label.hide {
display: none;
}
}
label {
&.showhide {
width: 1em;
}
display: inline-block;
input {
margin: 0 3pt;
}
&.added {
color: @green;
}
&.modified {
color: @orange;
}
&.removed {
color: @red;
}
}
}
button {
color: #212529;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
display: inline-block;
margin-right: 6pt;
&:disabled, &[disabled] {
color: #999999;
}
&:before {
padding-right: 0.2em;
}
}
}
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_vcs_status.less</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/less</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -15,6 +15,7 @@ Business Template | create_report
Business Template | create_skin_folder
Business Template | create_working_copy
Business Template | git_commit
Business Template | git_commit_action
Business Template | manage_field_library
Business Template | rename_proxy_field
Business Template | svn_cleanup_locks
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment