Skip to content

Commit

Permalink
Merge pull request #17 from plone/rnixx_single_valued_relation_field
Browse files Browse the repository at this point in the history
Rnixx single valued relation field
  • Loading branch information
pbauer committed Oct 24, 2014
2 parents 1b3d661 + b4f6081 commit 8da81da
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 96 deletions.
5 changes: 3 additions & 2 deletions docs/HISTORY.txt
Expand Up @@ -4,8 +4,9 @@ Changelog
1.0.9 (unreleased)
------------------

- Nothing changed yet.

* Implement ``renderForValue`` on ``ContentTreeBase`` in order to make
single valued relation fields work.
[rnixx]

1.0.8 (2014-10-21)
------------------
Expand Down
122 changes: 86 additions & 36 deletions plone/formwidget/contenttree/jquery-contenttree/contenttree.js
Expand Up @@ -3,8 +3,11 @@ if(jQuery) (function($){

$.extend($.fn, {
showDialog: function() {
$(document.body).append($(document.createElement("div")).addClass("contenttreeWindowBlocker"))
this[0].oldparent = $(this).parent()[0]; // store old parent element
$(document.body)
.append($(document.createElement("div"))
.addClass("contenttreeWindowBlocker"));
// store old parent element
this[0].oldparent = $(this).parent()[0];
$(".contenttreeWindowBlocker").before(this);
$(this).show();
$(this).width($(window).width() * 0.75);
Expand All @@ -14,63 +17,98 @@ if(jQuery) (function($){
'top': $(window).height() * 0.125
});
},

contentTreeAdd: function() {
var contenttree_window = (this).parents(".contenttreeWindow");
var input_box = $('#'+ contenttree_window[0].id.replace(/-contenttree-window$/,"-widgets-query"));
var input_box = $('#'+ contenttree_window[0].id
.replace(/-contenttree-window$/,"-widgets-query"));
contenttree_window.find('.navTreeCurrentItem > a').each(function () {
formwidget_autocomplete_new_value(input_box,$(this).attr('href'),$.trim($(this).text()));
formwidget_autocomplete_new_value(
input_box,
$(this).attr('href'),
$.trim($(this).text())
);
});

$(this).contentTreeCancel();
input_box.parents('.datagridwidget-cell').triggerHandler('change');
},

contentTreeCancel: function() {
$(".contenttreeWindowBlocker").remove();
var popup = $(this).parents(".contenttreeWindow");
popup.hide();
$(popup[0].oldparent).append(popup);
popup[0].oldparent = null;
},
contentTree: function(o, h) {

contentTree: function(o, h) {
// Defaults
if(!o) var o = {};
if(o.script == undefined) o.script = 'fetch';
if (!o) {
var o = {};
}
if (o.script == undefined) {
o.script = 'fetch';
}

if(o.folderEvent == undefined) o.folderEvent = 'click';
if(o.selectEvent == undefined) o.selectEvent = 'click';
if (o.folderEvent == undefined) {
o.folderEvent = 'click';
}
if (o.selectEvent == undefined) {
o.selectEvent = 'click';
}

if(o.expandSpeed == undefined) o.expandSpeed = -1;
if(o.collapseSpeed == undefined) o.collapseSpeed = -1;
if (o.expandSpeed == undefined) {
o.expandSpeed = -1;
}
if (o.collapseSpeed == undefined) {
o.collapseSpeed = -1;
}

if(o.multiFolder == undefined) o.multiFolder = true;
if(o.multiSelect == undefined) o.multiSelect = false;
if (o.multiFolder == undefined) {
o.multiFolder = true;
}
if (o.multiSelect == undefined) {
o.multiSelect = false;
}

function loadTree(c, t, r) {
$(c).addClass('wait');
$.post(o.script, { href: t, rel: r}, function(data) {
$.post(o.script, {href: t, rel: r}, function(data) {
$(c).removeClass('wait').append(data);
$(c).find('ul:hidden').slideDown({ duration: o.expandSpeed });
$(c).find('ul:hidden').slideDown({
duration: o.expandSpeed
});
bindTree(c);
});
}

function handleFolderEvent() {
var li = $(this).parent();
if(li.hasClass('collapsed')) {
if(!o.multiFolder) {
li.parent().find('ul:visible').slideUp({ duration: o.collapseSpeed });
li.parent().find('li.navTreeFolderish').removeClass('expanded').addClass('collapsed');
if (li.hasClass('collapsed')) {
if (!o.multiFolder) {
li.parent().find('ul:visible').slideUp({
duration: o.collapseSpeed
});
li.parent().find('li.navTreeFolderish')
.removeClass('expanded')
.addClass('collapsed');
}

if(li.find('ul').length == 0)
loadTree(li, escape($(this).attr('href')), escape($(this).attr('rel')));
if (li.find('ul').length == 0)
loadTree(
li,
escape($(this).attr('href')),
escape($(this).attr('rel'))
);
else
li.find('ul:hidden').slideDown({ duration: o.expandSpeed });

li.find('ul:hidden').slideDown({
duration: o.expandSpeed
});
li.removeClass('collapsed').addClass('expanded');
} else {
li.find('ul').slideUp({ duration: o.collapseSpeed });
li.find('ul').slideUp({
duration: o.collapseSpeed
});
li.removeClass('expanded').addClass('collapsed');
}
return false;
Expand All @@ -80,11 +118,15 @@ if(jQuery) (function($){
var li = $(this).parent();
var selected = true;
var root = $(this).parents('ul.navTree');
if(!li.hasClass('navTreeCurrentItem')) {
var multi_key = ((event.ctrlKey) || (navigator.userAgent.toLowerCase().indexOf('macintosh') != -1 && event.metaKey));

if(!o.multiSelect || !multi_key) {
root.find('li.navTreeCurrentItem').removeClass('navTreeCurrentItem');
if (!li.hasClass('navTreeCurrentItem')) {
var multi_key = (
(event.ctrlKey) ||
(navigator.userAgent.toLowerCase()
.indexOf('macintosh') != -1 && event.metaKey));

if (!o.multiSelect || !multi_key) {
root.find('li.navTreeCurrentItem')
.removeClass('navTreeCurrentItem');
}

li.addClass('navTreeCurrentItem');
Expand All @@ -100,15 +142,23 @@ if(jQuery) (function($){
function bindTree(t) {
$(t).find('li.navTreeFolderish a').unbind(o.folderEvent);
$(t).find('li.selectable a').unbind(o.selectEvent);
$(t).find('li a').bind('click', function() { return false; });
$(t).find('li.navTreeFolderish a').bind(o.folderEvent, handleFolderEvent);
$(t).find('li.selectable a').bind(o.selectEvent, handleSelectEvent);
$(t).find('li a').bind('click', function() {
return false;
});
$(t).find('li.navTreeFolderish a').bind(
o.folderEvent,
handleFolderEvent
);
$(t).find('li.selectable a').bind(
o.selectEvent,
handleSelectEvent
);
}

if ($(this).children('ul.navTree').length <= 0) {
$(this).each(function() {
loadTree(this, o.rootUrl, 0);
});
$(this).each(function() {
loadTree(this, o.rootUrl, 0);
});
}

}
Expand Down
144 changes: 86 additions & 58 deletions plone/formwidget/contenttree/widget.py
Expand Up @@ -3,8 +3,11 @@
from Acquisition.interfaces import IAcquirer

from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
from zope.interface import implementsOnly, implementer
from zope.interface import implementsOnly
from zope.interface import implementer
from zope.component import getMultiAdapter
from zope.pagetemplate.interfaces import IPageTemplate
from zope.schema.vocabulary import SimpleTerm
from zope.i18n import translate

import z3c.form.interfaces
Expand Down Expand Up @@ -110,6 +113,52 @@ def __call__(self):
return self.fragment_template(children=children, level=int(level))


ADDITIONAL_JS = """\
$('#%(id)s-widgets-query').each(function() {
if ($(this).siblings('input.searchButton').length != 0) {
return;
}
var input = document.createElement('input');
$(input)
.attr({
'type': 'button',
'value': '%(button_val)s'
})
.addClass('searchButton')
.click(function () {
var parent = $(this).parents("*[id$='-autocomplete']");
var window = parent.siblings("*[id$='-contenttree-window']");
window.showDialog('%(url)s', %(expandSpeed)d);
$('#' + parent.attr('id').replace(
'autocomplete', 'contenttree')).contentTree({
script: '%(url)s',
folderEvent: '%(folderEvent)s',
selectEvent: '%(selectEvent)s',
expandSpeed: %(expandSpeed)d,
collapseSpeed: %(collapseSpeed)s,
multiFolder: %(multiFolder)s,
multiSelect: %(multiSelect)s,
rootUrl: '%(rootUrl)s'
},
function(event, selected, data, title) {
});
})
.insertAfter($(this));
});
$('#%(id)s-contenttree-window').find('.contentTreeAdd')
.unbind('click')
.click(function () {
$(this).contentTreeAdd();
});
$('#%(id)s-contenttree-window').find('.contentTreeCancel')
.unbind('click')
.click(function () {
$(this).contentTreeCancel();
});
$('#%(id)s-widgets-query').after(" ");
"""


class ContentTreeBase(Explicit):
implementsOnly(IContentTreeWidget)

Expand Down Expand Up @@ -167,80 +216,59 @@ def render(self):
else:
return self.input_template(self)

def renderForValue(self, value):
try:
return super(ContentTreeBase, self).renderForValue(value)
except LookupError, e:
if value != z3c.form.widget.SequenceWidget.noValueToken:
raise e
item = {
'id': '%s-0' % self.id,
'name': self.name,
'value': '',
'checked': 'checked',
}
template = getMultiAdapter(
(self.context, self.request, self.form, self.field, self),
IPageTemplate, name=self.mode + '_single'
)
return template(self, item)

def js_extra(self):
# Get bound source to extract path
source = self.bound_source
form_url = self.request.getURL()
url = "%s/++widget++%s/@@contenttree-fetch" % (form_url, self.name)

return """\
$('#%(id)s-widgets-query').each(function() {
if($(this).siblings('input.searchButton').length != 0) { return; }
$(document.createElement('input'))
.attr({
'type': 'button',
'value': '%(button_val)s'
})
.addClass('searchButton')
.click( function () {
var parent = $(this).parents("*[id$='-autocomplete']")
var window = parent.siblings("*[id$='-contenttree-window']")
window.showDialog('%(url)s', %(expandSpeed)d);
$('#' + parent.attr('id').replace('autocomplete', 'contenttree')).contentTree(
{
script: '%(url)s',
folderEvent: '%(folderEvent)s',
selectEvent: '%(selectEvent)s',
expandSpeed: %(expandSpeed)d,
collapseSpeed: %(collapseSpeed)s,
multiFolder: %(multiFolder)s,
multiSelect: %(multiSelect)s,
rootUrl: '%(rootUrl)s'
},
function(event, selected, data, title) {
// alert(event + ', ' + selected + ', ' + data + ', ' + title);
}
);
}).insertAfter($(this));
});
$('#%(id)s-contenttree-window').find('.contentTreeAdd').unbind('click').click(function () {
$(this).contentTreeAdd();
});
$('#%(id)s-contenttree-window').find('.contentTreeCancel').unbind('click').click(function () {
$(this).contentTreeCancel();
});
$('#%(id)s-widgets-query').after(" ");
""" % dict(url=url,
id=self.name.replace('.', '-'),
folderEvent=self.folderEvent,
selectEvent=self.selectEvent,
expandSpeed=self.expandSpeed,
collapseSpeed=self.collapseSpeed,
multiFolder=str(self.multiFolder).lower(),
multiSelect=str(self.multi_select).lower(),
rootUrl=source.navigation_tree_query['path']['query'],
name=self.name,
klass=self.klass,
title=self.title,
button_val=translate(
_(u'label_contenttree_browse', default=u'browse...'),
context=self.request))
return ADDITIONAL_JS % dict(
url=url,
id=self.name.replace('.', '-'),
folderEvent=self.folderEvent,
selectEvent=self.selectEvent,
expandSpeed=self.expandSpeed,
collapseSpeed=self.collapseSpeed,
multiFolder=str(self.multiFolder).lower(),
multiSelect=str(self.multi_select).lower(),
rootUrl=source.navigation_tree_query['path']['query'],
name=self.name,
klass=self.klass,
title=self.title,
button_val=translate(
_(u'label_contenttree_browse', default=u'browse...'),
context=self.request
),
)


class ContentTreeWidget(ContentTreeBase, AutocompleteSelectionWidget):
"""ContentTree widget that allows single selection.
"""

klass = u"contenttree-widget"
display_template = ViewPageTemplateFile('display_single.pt')


class MultiContentTreeWidget(ContentTreeBase, AutocompleteMultiSelectionWidget):
"""ContentTree widget that allows multiple selection
"""

klass = u"contenttree-widget"
multi_select = True
display_template = ViewPageTemplateFile('display_multiple.pt')
Expand Down

0 comments on commit 8da81da

Please sign in to comment.