Browse files

Added z3cform widget

  • Loading branch information...
1 parent 80cd704 commit 90c05082de3747c9a3dd2b50f23da541f97bf63c @naro naro committed Mar 17, 2012
View
3 CHANGES.txt
@@ -7,6 +7,9 @@ Changelog
* Added Italian translation
[giacomos]
+- Added dexterity version of the widget. See Readme.
+ [naro]
+
0.3.2 (2012-03-04)
------------------
View
43 README.txt
@@ -37,7 +37,13 @@ Plone 4::
eggs =
...
collective.virtualtreecategories
-
+
+Dexterity::
+
+ eggs =
+ ...
+ collective.virtualtreecategories [dexterity]
+
Control panel
-------------
@@ -49,3 +55,38 @@ Archetypes widget
.. figure:: http://plone.org/products/collective.virtualtreecategories/documentation/manuals/project-description/AT%20Widget.png/image_preview
+Dexterity widget
+----------------
+
+If you want to use this widget in your dexterity content type, you need to
+specify [dexterity] extra in eggs section of the buildout. You also
+need to use Keyword field from collective.z3cform.keywordwidget for your schema field
+and finally set VirtualTreeCategoriesFieldWidget as widget for the field.
+```Please note, this feature requires collective.z3cform.keywordwidget > 1.1.1 or svn
+branch currently.```
+
+Example::
+
+ from zope import schema
+ from plone.directives import form
+ from collective.z3cform.keywordwidget.field import Keywords
+ from collective.virtualtreecategories.dexterity.widget import VirtualTreeCategoriesFieldWidget
+
+ class ICustomCategorization(form.Schema):
+
+ subjects = Keywords(
+ title=u'Categories',
+ value_type=schema.TextLine(),
+ required=False,
+ missing_value=(),
+ index_name='Subject',
+ )
+ form.widget(subjects=VirtualTreeCategoriesFieldWidget)
+
+ new_subjects = schema.Tuple(
+ title=u'New categories',
+ description=u'Enter new keywords, one per line.',
+ value_type=schema.TextLine(),
+ required=False,
+ missing_value=(),
+ )
View
2 setup.py
@@ -45,6 +45,8 @@ def read(*rnames):
extras_require={
'tests': tests_require,
'plone3': ['collective.js.jquery'],
+ 'dexterity': ['plone.app.dexterity',
+ 'collective.z3cform.keywordwidget'],
},
entry_points="""
# -*- Entry points: -*-
View
3 src/collective/virtualtreecategories/browser/resources/virtualtreecategories.css
@@ -1,3 +1,6 @@
+#content ul#VTCFilterTree ul { margin-left: 0; list-style-type: none;}
+#content ul#VTCFilterTree ul a { padding-left: 24px;}
+
#keywords, #VTCTree {
float: left;
width: 35%;
View
3 src/collective/virtualtreecategories/configure.zcml
@@ -19,6 +19,9 @@
file="permissions.zcml"
zcml:condition="have plone-41" />
+ <include package=".dexterity"
+ zcml:condition="installed plone.dexterity" />
+
<!-- Include the sub-packages that have their own configure.zcml files -->
<include package=".browser" />
View
0 src/collective/virtualtreecategories/dexterity/__init__.py
No changes.
View
29 src/collective/virtualtreecategories/dexterity/configure.zcml
@@ -0,0 +1,29 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="collective.virtualtreecategories">
+
+ <class class=".widget.VirtualTreeCategoriesWidget">
+ <require permission="zope.Public"
+ interface=".interfaces.IVirtualTreeCategoriesWidget" />
+ </class>
+
+ <z3c:widgetTemplate
+ mode="input"
+ widget=".interfaces.IVirtualTreeCategoriesWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="vtc_input.pt"
+ />
+
+ <z3c:widgetTemplate
+ mode="display"
+ widget=".interfaces.IVirtualTreeCategoriesWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="vtc_display.pt"
+ />
+
+ <adapter
+ factory=".widget.VirtualTreeCategoriesDataConverter"
+ />
+
+</configure>
View
5 src/collective/virtualtreecategories/dexterity/interfaces.py
@@ -0,0 +1,5 @@
+from collective.z3cform.keywordwidget.interfaces import IInAndOutKeywordWidget
+
+
+class IVirtualTreeCategoriesWidget(IInAndOutKeywordWidget):
+ pass
View
26 src/collective/virtualtreecategories/dexterity/vtc_display.pt
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ tal:omit-tag="">
+<span id="" class=""
+ tal:attributes="id view/id;
+ class view/klass;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup"><tal:block
+ repeat="value view/displayValue"
+ ><span class="selected-option"
+ tal:content="value"
+ /><tal:block condition="not:repeat/value/end">, </tal:block
+ ></tal:block
+></span>
+</html>
View
252 src/collective/virtualtreecategories/dexterity/vtc_input.pt
@@ -0,0 +1,252 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ tal:define="portal_url context/@@plone_portal_state/portal_url"
+ tal:omit-tag="">
+<style type="text/css" media="screen">@import url(++resource++collective.virtualtreecategories.jsTree/tree_component.css);</style>
+<style type="text/css" media="screen">@import url(++resource++collective.virtualtreecategories.resources/virtualtreecategories.css);</style>
+<script type="text/javascript" src="++resource++collective.virtualtreecategories.jsTree/css.js"></script>
+<script type="text/javascript" src="++resource++collective.virtualtreecategories.jsTree/jquery.tree_component.js"></script>
+<script type="text/javascript" tal:attributes="src string:${portal_url}/virtualtreecategories_widget.js"></script>
+<script type="text/javascript">
+/* <![CDATA[ */
+function moveItems(from, to)
+ {
+ // shortcuts for selection fields
+ var src = document.getElementById(from);
+ var tgt = document.getElementById(to);
+
+ if (src.selectedIndex == -1) selectionError();
+ else
+ {
+ // iterate over all selected items
+ // --> attribute "selectedIndex" doesn't support multiple selection.
+ // Anyway, it works here, as a moved item isn't selected anymore,
+ // thus "selectedIndex" indicating the "next" selected item :)
+ while (src.selectedIndex > -1)
+ if (src.options[src.selectedIndex].selected)
+ {
+ // create a new virtal object with values of item to copy
+ temp = new Option(src.options[src.selectedIndex].text,
+ src.options[src.selectedIndex].value);
+ // append virtual object to targe
+ tgt.options[tgt.length] = temp;
+ // want to select newly created item
+ temp.selected = true;
+ // delete moved item in source
+ src.options[src.selectedIndex] = null;
+ }
+ }
+ }
+
+// move item from "from" selection to "to" selection
+function from2to(name)
+ {
+ moveItems(name+"-from", name+"-to");
+ copyDataForSubmit(name);
+ }
+
+// move item from "to" selection back to "from" selection
+function to2from(name)
+ {
+ moveItems(name+"-to", name+"-from");
+ copyDataForSubmit(name);
+ }
+
+function swapFields(a, b)
+ {
+ // swap text
+ var temp = a.text;
+ a.text = b.text;
+ b.text = temp;
+ // swap value
+ temp = a.value;
+ a.value = b.value;
+ b.value = temp;
+ // swap selection
+ temp = a.selected;
+ a.selected = b.selected;
+ b.selected = temp;
+ }
+
+// move selected item in "to" selection one up
+function moveUp(name)
+ {
+ // shortcuts for selection field
+ var toSel = document.getElementById(name+"-to");
+
+ if (toSel.selectedIndex == -1)
+ selectionError();
+ else if (toSel.options[0].selected)
+ alert("Cannot move further up!");
+ else for (var i = 0; i < toSel.length; i++)
+ if (toSel.options[i].selected)
+ {
+ swapFields(toSel.options[i-1], toSel.options[i]);
+ copyDataForSubmit(name);
+ }
+ }
+
+// move selected item in "to" selection one down
+function moveDown(name)
+ {
+ // shortcuts for selection field
+ var toSel = document.getElementById(name+"-to");
+
+ if (toSel.selectedIndex == -1) {
+ selectionError();
+ } else if (toSel.options[toSel.length-1].selected) {
+ alert("Cannot move further down!");
+ } else {
+ for (var i = toSel.length-1; i >= 0; i--) {
+ if (toSel.options[i].selected) {
+ swapFields(toSel.options[i+1], toSel.options[i]);
+ }
+ }
+ copyDataForSubmit(name);
+ }
+ }
+
+// copy each item of "toSel" into one hidden input field
+function copyDataForSubmit(name)
+ {
+ // shortcuts for selection field and hidden data field
+ var toSel = document.getElementById(name+"-to");
+ var toDataContainer = document.getElementById(name+"-toDataContainer");
+
+ // delete all child nodes (--> complete content) of "toDataContainer" span
+ while (toDataContainer.hasChildNodes())
+ toDataContainer.removeChild(toDataContainer.firstChild);
+
+ // create new hidden input fields - one for each selection item of
+ // "to" selection
+ for (var i = 0; i < toSel.options.length; i++)
+ {
+ // create virtual node with suitable attributes
+ var newNode = document.createElement("input");
+ var newAttr = document.createAttribute("name");
+ newAttr.nodeValue = name.replace(/-/g, '.')+':list';
+ newNode.setAttributeNode(newAttr);
+
+ newAttr = document.createAttribute("type");
+ newAttr.nodeValue = "hidden";
+ newNode.setAttributeNode(newAttr);
+
+ newAttr = document.createAttribute("value");
+ newAttr.nodeValue = toSel.options[i].value;
+ newNode.setAttributeNode(newAttr);
+
+ // actually append virtual node to DOM tree
+ toDataContainer.appendChild(newNode);
+ }
+ }
+
+// error message for missing selection
+function selectionError()
+ {alert("Must select something!")}
+
+/* ]]> */
+</script>
+
+<ul id="VTCFilterTree"
+ data-widgettype="dexterity"
+ tal:attributes="data-widgetid view/id"></ul>
+<table border="0" class="ordered-selection-field">
+ <tr>
+ <td>
+ <select id="from" name="from" class="" multiple="" size="5"
+ tal:attributes="id string:${view/id}-from;
+ name string:${view/name}.from;
+ class view/klass;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup;
+ disabled view/disabled;
+ tabindex view/tabindex;
+ onfocus view/onfocus;
+ onblur view/onblur;
+ onchange view/onchange;
+ multiple view/multiple;
+ size view/size">
+ <option tal:repeat="entry view/notselectedItems"
+ tal:attributes="value entry/value"
+ tal:content="nocall:entry/content" i18n:translate=""/>
+ </select>
+ </td>
+ <td>
+ <button onclick="javascript:from2to()"
+ name="from2toButton" type="button" value="&rarr;"
+ tal:attributes="onClick string:javascript:from2to('${view/id}')"
+ >&rarr;</button>
+ <br />
+ <button onclick="javascript:to2from()"
+ name="to2fromButton" type="button" value="&larr;"
+ tal:attributes="onClick string:javascript:to2from('${view/id}')"
+ >&larr;</button>
+ </td>
+ <td>
+ <select id="to" name="to" class="" multiple="" size="5"
+ tal:attributes="id string:${view/id}-to;
+ name string:${view/name}.to;
+ class view/klass;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup;
+ disabled view/disabled;
+ tabindex view/tabindex;
+ onfocus view/onfocus;
+ onblur view/onblur;
+ onchange view/onchange;
+ multiple view/multiple;
+ size view/size">
+ <option tal:repeat="entry view/selectedItems"
+ tal:attributes="value entry/value"
+ tal:content="nocall:entry/content" i18n:translate=""/>
+ </select>
+ <input name="foo-empty-marker" type="hidden"
+ tal:attributes="name string:${view/name}-empty-marker"/>
+ <span id="toDataContainer"
+ tal:attributes="id string:${view/id}-toDataContainer">
+ <script type="text/javascript" tal:content="string:
+ copyDataForSubmit('${view/id}');">
+ // initial copying of field "field.to" --> "field"
+ copyDataForSubmit("<i tal:replace="${view/id}"/>");
+ </script>
+ </span>
+ </td>
+ <td>
+ <button
+ onclick="javascript:moveUp()"
+ name="upButton" type="button" value="&uarr;"
+ tal:attributes="onClick string:javascript:moveUp('${view/id}')"
+ >&uarr;</button>
+ <br />
+ <button
+ onclick="javascript:moveDown()"
+ name="downButton" type="button" value="&darr;"
+ tal:attributes="onClick string:javascript:moveDown('${view/id}')"
+ >&darr;</button>
+ </td>
+ </tr>
+</table>
+</html>
View
27 src/collective/virtualtreecategories/dexterity/widget.py
@@ -0,0 +1,27 @@
+import zope.component
+import zope.interface
+from z3c.form.interfaces import IFormLayer, IFieldWidget
+from z3c.form.widget import FieldWidget
+from collective.z3cform.keywordwidget.widget import InAndOutKeywordWidget
+from collective.z3cform.keywordwidget.interfaces import IKeywordCollection
+from collective.z3cform.keywordwidget.field import KeywordsDataConverter
+from zope.interface import implementsOnly
+from collective.virtualtreecategories.dexterity.interfaces import IVirtualTreeCategoriesWidget
+
+
+class VirtualTreeCategoriesWidget(InAndOutKeywordWidget):
+ implementsOnly(IVirtualTreeCategoriesWidget)
+ klass = u'virtualtreecategories-widget'
+
+
+@zope.component.adapter(IKeywordCollection, IFormLayer)
+@zope.interface.implementer(IFieldWidget)
+def VirtualTreeCategoriesFieldWidget(field, request):
+ """ IFieldWidget factory for VirtualTreeCategoriesWidget
+ """
+ return FieldWidget(field, VirtualTreeCategoriesWidget(request))
+
+
+class VirtualTreeCategoriesDataConverter(KeywordsDataConverter):
+ """A special converter between collections and sequence widgets."""
+ zope.component.adapts(IKeywordCollection, IVirtualTreeCategoriesWidget)
View
19 ...lective/virtualtreecategories/skins/virtualtreecategories/virtualtreecategories_widget.js
@@ -12,9 +12,9 @@
};
return category_path;
};
- function category_selected_deselected(node, tree_obj, deselecting) {
+ function category_selected_deselected(node, tree_obj, selected_selector, unselected_selector, deselecting) {
var selected_keywords = [];
- jq('select#subject_selected option').each(function() {
+ jq(selected_selector+' option').each(function() {
selected_keywords.push(this.value)
});
var selected_categories = [];
@@ -36,7 +36,7 @@
selected: selected_keywords
},
success:function(data) {
- var $master = jq('select#subject_unselected');
+ var $master = jq(unselected_selector);
$master.empty();
jq.each(data.keywords, function() { $master.append('<option value="'+this+'">'+this+'</option>') });
},
@@ -46,6 +46,15 @@
};
$(document).ready(function () {
var $tree = jq('ul#VTCFilterTree');
+ var widgetid = $tree.attr('data-widgetid');
+ var widgettype = $tree.attr('data-widgettype');
+ if (widgettype == 'archetypes') {
+ var selected_selector = 'select#'+widgetid+'_selected';
+ var unselected_selector = 'select#'+widgetid+'_unselected';
+ } else if (widgettype == 'dexterity') {
+ var selected_selector = 'select#'+widgetid+'-to';
+ var unselected_selector = 'select#'+widgetid+'-from';
+ }
$tree.tree({
data : {
type : "json",
@@ -66,10 +75,10 @@
},
callback : {
onselect : function(node, tree_obj) {
- category_selected_deselected(node, tree_obj, false);
+ category_selected_deselected(node, tree_obj, selected_selector, unselected_selector, false);
},
ondeselect : function(node, tree_obj) {
- category_selected_deselected(node, tree_obj, true);
+ category_selected_deselected(node, tree_obj, selected_selector, unselected_selector, true);
}
}
});
View
4 ...lective/virtualtreecategories/skins/virtualtreecategories/virtualtreecategories_widget.pt
@@ -74,7 +74,9 @@
i18n:domain="collective.virtualtreecategories">
Unselect all nodes to show all available keywords
</div>
- <ul id="VTCFilterTree"></ul>
+ <ul id="VTCFilterTree"
+ data-widgettype="archetypes"
+ tal:attributes="data-widgetid fieldName;"></ul>
<div class="visualClear"><!-- --></div>
<table cellpadding="2" cellspacing="2">
<tr>
View
3 src/collective/virtualtreecategories/widget.py
@@ -15,7 +15,8 @@ class VirtualTreeCategoriesWidget(AddRemoveWidget):
'++resource++collective.virtualtreecategories.jsTree/css.js',
'++resource++collective.virtualtreecategories.jsTree/jquery.tree_component.js',
'virtualtreecategories_widget.js'),
- 'helper_css': ('++resource++collective.virtualtreecategories.jsTree/tree_component.css', ),
+ 'helper_css': ('++resource++collective.virtualtreecategories.jsTree/tree_component.css',
+ '++resource++collective.virtualtreecategories.resources/virtualtreecategories.css', ),
})
security = ClassSecurityInfo()

0 comments on commit 90c0508

Please sign in to comment.