from pylons import c
from tg import request
from urllib import urlencode
import json
from formencode import validators as fev
import ew as ew_core
import ew.jinja2_ew as ew
def onready(text):
return ew.JSScript('$(function(){%s});' % text);
class LabelList(fev.UnicodeString):
def _to_python(self, value, state):
value = super(LabelList, self)._to_python(value, state)
return value.split(',')
def _from_python(self, value, state):
value = ','.join(value)
value = super(LabelList, self)._from_python(value, state)
return value
class LabelEdit(ew.InputField):
template='jinja:widgets/label_edit.html'
validator = LabelList()
defaults=dict(
ew.InputField.defaults,
name=None,
value=None,
className='',
show_label=True)
def from_python(self, value, state=None):
return value
def resources(self):
yield ew.resource.JSLink('js/jquery.tag.editor.js')
yield onready('''
$('input.label_edit').tagEditor({
confirmRemoval: false,
completeOnSeparator: true,
completeOnBlur: true
});
''')
class ProjectUserSelect(ew.InputField):
template='jinja:widgets/project_user_select.html'
defaults=dict(
ew.InputField.defaults,
name=None,
value=None,
show_label=True,
className=None)
def __init__(self, **kw):
super(ProjectUserSelect, self).__init__(**kw)
if not isinstance(self.value, list):
self.value=[self.value]
def from_python(self, value, state=None):
return value
def resources(self):
for r in super(ProjectUserSelect, self).resources(): yield r
yield ew.resource.CSSLink('css/autocomplete.css')
yield onready('''
$('input.project_user_select').autocomplete({
source: function(request, response) {
$.ajax({
url: "%suser_search",
dataType: "json",
data: {
term: request.term
},
success: function(data) {
response(data.users);
}
});
},
minLength: 2
});''' % c.project.url())
class AttachmentList(ew_core.Widget):
template='jinja:widgets/attachment_list.html'
defaults=dict(
ew_core.Widget.defaults,
attachments=None,
edit_mode=None)
class AttachmentAdd(ew_core.Widget):
template='jinja:widgets/attachment_add.html'
defaults=dict(
ew_core.Widget.defaults,
action=None,
name=None)
def resources(self):
for r in super(AttachmentAdd, self).resources(): yield r
yield onready('''
$("input.attachment_form_add_button").click(function(){
$(this).hide();
$(".attachment_form_fields", this.parentNode).show();
});
''')
class SubmitButton(ew.SubmitButton):
attrs={'class':'ui-state-default ui-button ui-button-text'}
class AutoResizeTextarea(ew.TextArea):
defaults=dict(
ew.TextArea.defaults,
name=None,
value=None,
css_class='auto_resize')
def resources(self):
yield ew.resource.JSLink('js/jquery.autoresize.min.js')
yield onready('''
$('textarea.auto_resize').autoResize({
// Quite slow animation:
animateDuration : 300,
// More extra space:
extraSpace : 0
}).change();
''')
class MarkdownEdit(AutoResizeTextarea):
template='jinja:widgets/markdown_edit.html'
validator = fev.UnicodeString()
defaults=dict(
AutoResizeTextarea.defaults,
name=None,
value=None,
show_label=True)
def from_python(self, value, state=None):
return value
def resources(self):
for r in super(MarkdownEdit, self).resources(): yield r
yield ew.resource.JSLink('js/sf_markitup.js')
yield ew.resource.CSSLink('css/markitup_sf.css')
class PageList(ew_core.Widget):
template='jinja:widgets/page_list.html'
defaults=dict(
ew_core.Widget.defaults,
name=None,
limit=None,
count=0,
page=0,
show_label=False)
@property
def url_params(self, **kw):
url_params = dict()
for k,v in request.params.iteritems():
if k not in ['limit','count','page']:
url_params[k] = v
return url_params
class PageSize(ew_core.Widget):
template='jinja:widgets/page_size.html'
defaults=dict(
ew_core.Widget.defaults,
limit=None,
name=None,
count=0,
show_label=False)
@property
def url_params(self, **kw):
url_params = dict()
for k,v in request.params.iteritems():
if k not in ['limit','count','page']:
url_params[k] = v
return url_params
def resources(self):
yield onready('''
$('select.results_per_page').change(function(){
this.form.submit();})''')
class FileChooser(ew.InputField):
template='jinja:widgets/file_chooser.html'
validator=fev.FieldStorageUploadConverter()
defaults=dict(
ew.InputField.defaults,
name=None)
def resources(self):
for r in super(FileChooser, self).resources(): yield r
yield ew.resource.JSLink('js/jquery.file_chooser.js')
yield onready('''
var num_files = 0;
var chooser = $('input.file_chooser').file();
chooser.choose(function(e, input) {
var holder = document.createElement('div');
holder.style.clear = 'both';
e.target.parentNode.appendChild(holder);
$(holder).append(input.val());
$(holder).append(input);
input.attr('name', e.target.id + '-' + num_files);
input.hide();
++num_files;
var delete_link = document.createElement('a');
delete_link.className = 'btn ico';
var icon = document.createElement('b');
icon.className = 'ui-icon ui-icon-close';
delete_link.appendChild(icon);
$(delete_link).click(function(){
this.parentNode.parentNode.removeChild(this.parentNode);
});
$(holder).append(delete_link);
});''')
class JQueryMixin(object):
js_widget_name = None
js_plugin_file = None
js_params = [
'container_cls'
]
container_cls = 'container'
def resources(self):
for r in super(JQueryMixin, self).resources():
yield r
if self.js_plugin_file is not None: yield self.js_plugin_file
opts = dict(
(k, getattr(self, k))
for k in self.js_params )
yield onready('''
$(document).bind('clone', function () {
$('.%s').%s(%s) });
$(document).trigger('clone');
''' % (self.container_cls, self.js_widget_name, json.dumps(opts)));
class SortableRepeatedMixin(JQueryMixin):
js_widget_name = 'SortableRepeatedField'
js_plugin_file = ew.JSLink('js/sortable_repeated_field.js')
js_params = JQueryMixin.js_params + [
'field_cls',
'flist_cls',
'stub_cls',
'msg_cls',
]
defaults=dict(
container_cls='sortable-repeated-field',
field_cls='sortable-field',
flist_cls='sortable-field-list',
stub_cls='sortable-field-stub',
msg_cls='sortable-field-message',
empty_msg='No fields have been defined',
nonempty_msg='Drag and drop the fields to reorder',
repetitions=0)
button = ew.InputField(
css_class='add', field_type='button', value='New Field')
class SortableRepeatedField(SortableRepeatedMixin, ew.RepeatedField):
template='genshi:allura.templates.widgets.sortable_repeated_field'
defaults=dict(
ew.RepeatedField.defaults,
**SortableRepeatedMixin.defaults)
class SortableTable(SortableRepeatedMixin, ew.TableField):
template='genshi:allura.templates.widgets.sortable_table'
defaults=dict(
ew.TableField.defaults,
**SortableRepeatedMixin.defaults)
class StateField(JQueryMixin, ew.CompoundField):
template='genshi:allura.templates.widgets.state_field'
js_params = JQueryMixin.js_params + [
'selector_cls',
'field_cls',
]
defaults=dict(
ew.CompoundField.defaults,
js_widget_name = 'StateField',
js_plugin_file = ew.JSLink('js/state_field.js'),
js_params = js_params,
container_cls='state-field-container',
selector_cls='state-field-selector',
field_cls='state-field',
show_label=False,
selector = None,
states = {},
)
@property
def fields(self):
return [self.selector] + self.states.values()
class DateField(JQueryMixin, ew.TextField):
js_widget_name = 'datepicker'
js_params = JQueryMixin.js_params
defaults=dict(
ew.TextField.defaults,
container_cls = 'ui-date-field',
css_class = 'ui-date-field')
class FieldCluster(ew.CompoundField):
template='genshi:allura.templates.widgets.field_cluster'
class AdminField(ew.InputField):
'''Field with the correct layout/etc for an admin page'''
template='genshi:allura.templates.widgets.admin_field'
defaults=dict(
ew.InputField.defaults,
field=None)
def __init__(self, **kw):
super(AdminField, self).__init__(**kw)
for p in self.field.get_params():
setattr(self, p, getattr(self.field, p))
def resources(self):
for r in self.field.resources():
yield r