Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRogelio Mita <rogeliomita@activitycentral.com>2013-03-28 04:35:08 (GMT)
committer Rogelio Mita <rogeliomita@activitycentral.com>2013-03-29 13:02:39 (GMT)
commit5faf0cbf12f88ea3729fa0f7c82aacc9e35eaed8 (patch)
tree260fc928bc9d6fbd956113e822cf4e44de2d3fe3
parent90ec60f52a57ecb2170f0dfa2206537cb539150e (diff)
Refactoring and cosmetic
-rw-r--r--webapp/polls/models.py312
-rw-r--r--webapp/polls/templates/mustache/field.html32
-rw-r--r--webapp/polls/templates/mustache/group.html12
-rw-r--r--webapp/polls/templates/mustache/option.html10
-rw-r--r--webapp/polls/templates/mustache/option_default.html3
-rw-r--r--webapp/polls/templates/mustache/option_image_thumbnail.html15
-rw-r--r--webapp/polls/templates/mustache/option_image_upload.html5
-rw-r--r--webapp/polls/templates/poll-form.html8
-rw-r--r--webapp/polls/templates/poll-list.html5
-rw-r--r--webapp/polls/templates/poll-structure-form.html19
-rw-r--r--webapp/polls/templates/tags/structure.html16
-rw-r--r--webapp/polls/templatetags/poll_tags.py25
-rw-r--r--webapp/polls/tests.py473
-rw-r--r--webapp/polls/tests/__init__.py0
-rw-r--r--webapp/polls/tests/field_tests.py211
-rw-r--r--webapp/polls/tests/group_tests.py79
-rw-r--r--webapp/polls/tests/option_tests.py155
-rw-r--r--webapp/polls/tests/poll_tests.py136
-rw-r--r--webapp/polls/tests/structure_tests.py219
-rw-r--r--webapp/polls/urls.py2
-rw-r--r--webapp/polls/views.py30
-rw-r--r--webapp/utils/test.py7
-rw-r--r--webapp/webapp/static/js/dynamic_structure.js103
23 files changed, 1134 insertions, 743 deletions
diff --git a/webapp/polls/models.py b/webapp/polls/models.py
index 375af61..19a8d3c 100644
--- a/webapp/polls/models.py
+++ b/webapp/polls/models.py
@@ -4,6 +4,8 @@ import json
import os
import shutil
import re
+import Image
+import base64
from exceptions import *
from bson import ObjectId, DBRef
@@ -38,6 +40,13 @@ WITH_OPTIONS = [
WITH_IMAGES = ["ImageCheckBox", "ImageRadioButton"]
+class ComponentStructure(ObjectId):
+
+ def __init__(self, poll=None, *args, **kwargs):
+ super(ComponentStructure, self).__init__(*args, **kwargs)
+ self.poll = poll
+
+
class AbstracErrorObject(object):
ValidationError = ValidationError
@@ -53,8 +62,8 @@ class Poll(AbstracErrorObject):
OPEN = "Abierta"
CLOSED = "Cerrada"
- def __init__(self, data={}):
- super(Poll, self).__init__()
+ def __init__(self, data={}, *args, **kwargs):
+ super(Poll, self).__init__(*args, **kwargs)
self.id = None
_id = data.get('id', None) or data.get('_id', None)
@@ -66,6 +75,14 @@ class Poll(AbstracErrorObject):
self.name = data.get('name', None)
self.status = data.get('status', Poll.OPEN)
+ @property
+ def structure(self):
+ structure_data = get_db().structures.find_one(
+ {'poll.$id': self.id})
+ structure_data = structure_data if structure_data else {}
+
+ return Structure(data=structure_data, poll=self)
+
@staticmethod
def status_choices():
return (
@@ -140,10 +157,11 @@ class Poll(AbstracErrorObject):
def to_json(self):
structure_data = get_db().structures.find_one(
- {'poll.$id': self.id}, fields={'_id': False, 'poll': False})
+ {'poll.$id': self.id}, fields={'poll': False})
+ structure = Structure(structure_data, poll=self)
_json = json.dumps(
- structure_data,
+ structure.to_python(with_errors=False, img_serialize=True),
sort_keys=True,
indent=4,
separators=(',', ': '),
@@ -153,54 +171,59 @@ class Poll(AbstracErrorObject):
return _json
-class AbastractObject(AbstracErrorObject):
+class AbstractObject(AbstracErrorObject):
@staticmethod
def get_offset_id():
return int(time.time() * 1000)
-class Option(AbastractObject):
+class Option(AbstractObject, ComponentStructure):
+
+ def __init__(self, data={}, *args, **kwargs):
+ super(Option, self).__init__(*args, **kwargs)
- def __init__(self, id, text=None, img=None, img_name=None, weight=None):
- super(Option, self).__init__()
+ self.id = data.get('id', None)
+ self.text = data.get('text', None)
+ self.img = data.get('img', None)
+ self.img_name = data.get('img_name', None)
- self.id = id
- self.text = text
- self.img = img
- self.img_name = img_name
+ weight = data.get('weight', None)
self.weight = int(weight) if weight else weight
if not self.img_name and isinstance(self.img, InMemoryUploadedFile):
fileExtension = os.path.splitext(self.img.name)[1]
self.img_name = '%s%s' % (self.id, fileExtension)
- @staticmethod
- def from_dict(data):
- option = Option(
- id=data.get('id', None),
- text=data.get('text', None),
- img=data.get('img', None),
- img_name=data.get('img_name', None),
- weight=data.get('weight', None)
+ def get_absolute_path(self):
+ return "%s/%s/%s" % (
+ settings.IMAGE_OPTIONS_ROOT, str(self.poll.id), self.img_name
)
- return option
-
def validate(self):
self.dict_errors = {}
self.errors = []
if self.img and isinstance(self.img, InMemoryUploadedFile):
try:
- ImageField().to_python(self.img)
+ img = ImageField().to_python(self.img)
except DjangoValidationError, e:
self.dict_errors.update(
{'img': '%s: %s' % (self.img.name, e.messages[0])})
+ else:
+ width, height = Image.open(img).size
+ if width > 250 or height > 250:
+ msg = u"Se necesita una imagen menor a 250x250."
+ self.dict_errors.update(
+ {'img': '%s: %s' % (self.id, msg)})
+
+ if 'img' in self.dict_errors.keys():
self.img_name = None
self.img = None
+ else:
+ self.img.seek(0)
- if not self.weight:
+ if self.weight is None or self.weight == '':
msg = u"opcion %s: ponderación requerida." % self.id
self.dict_errors.update({'weight': msg})
@@ -208,10 +231,43 @@ class Option(AbastractObject):
if len(self.errors):
raise Option.ValidationError(str(self.errors))
+ def to_python(self, with_errors=False, img_serialize=False):
+
+ data = {'%s' % self.id: {}}
+
+ if self.text:
+ data[self.id].update({'text': self.text})
+
+ if self.img_name:
+ if img_serialize:
+ img_path = self.get_absolute_path()
-class Field(AbastractObject):
+ img_file = open(img_path, 'rb')
+ image_string = base64.b64encode(img_file.read())
+ img_file.close()
- rules = {
+ data[self.id].update({'img': image_string})
+ else:
+ data[self.id].update({'img_name': self.img_name})
+
+ if self.weight is not None and self.weight != '':
+ data[self.id].update({'weight': self.weight})
+
+ return data
+
+
+class Field(AbstractObject, ComponentStructure):
+
+ TextInput = 'TextInput'
+
+ MultipleCheckBox = 'MultipleCheckBox'
+ RadioButton = 'RadioButton'
+ DropDownList = 'DropDownList'
+
+ ImageCheckBox = 'ImageCheckBox'
+ ImageRadioButton = 'ImageRadioButton'
+
+ VALIDATION_RULES = {
'MultipleCheckBox': (
lambda f: f.options and len(f.options) > 0,
"Respuesta con checks (multiple selección): necesita "
@@ -240,45 +296,28 @@ class Field(AbastractObject):
'TextInput': (lambda f: True, ""),
}
- def __init__(self, name, widget_type, key=None):
- super(Field, self).__init__()
+ def __init__(self, data={}, *args, **kwargs):
+ super(Field, self).__init__(*args, **kwargs)
- self.name = name
- self.key = key
+ order = data.get('order', None)
+ self.order = int(order) if order else order
+ self.name = data.get('name', None)
+ self.dependence = data.get('dependence', None)
self.options = []
- self.dependence = None
+ widget_type = data.get('widget_type', None)
if widget_type and widget_type not in dict(WIDGET_TYPES).keys():
raise AttributeError(
- 'valid widget types are TextInput, MultipleCheckBox, \
- RadioButton, DropDownList.'
+ 'valid widget types are %s' % WIDGET_TYPES.keys().join(', ')
)
self.widget_type = widget_type
- @staticmethod
- def from_dict(data):
- name = data.get('name', None)
- key = data.get('key', None)
- widget_type = data.get('widget_type', None)
- dependence = data.get('dependence', None)
-
- field = Field(
- key=key,
- name=name,
- widget_type=widget_type,
- )
-
- if dependence:
- field.add_dependence(dependence)
-
- return field
-
def add_options(self, data):
for id, info in data.iteritems():
opt_data = {'id': id}
opt_data.update(info)
- opt = Option.from_dict(opt_data)
+ opt = Option(opt_data, poll=self.poll)
self.options = self.options if self.options is not None else []
if opt_data.get('text', None) and opt not in self.options:
@@ -288,12 +327,9 @@ class Field(AbastractObject):
if img and opt not in self.options:
self.options.append(opt)
- def add_dependence(self, dependence):
- self.dependence = dependence
-
def validate(self, options=[]):
self.errors = []
- rule, msg = Field.rules.get(self.widget_type)
+ rule, msg = Field.VALIDATION_RULES.get(self.widget_type)
if not rule(self):
self.errors.append(msg)
@@ -301,21 +337,12 @@ class Field(AbastractObject):
for opt in self.options:
# TODO: Refactoring this.
# HORRIBLE path to avoid validation for TextInput options.
- if self.widget_type != "TextInput":
+ if self.widget_type != Field.TextInput:
try:
opt.validate()
except Option.ValidationError:
self.errors += opt.errors
- options_id = [opt.id for opt in options]
-
- # TODO: Test
- # TODO: Comprobacion que exista en el mismo grupo
- # TODO: Que la dependencia no sea de una opcion de este campo
- if self.dependence and self.dependence not in options_id:
- msg = "Dependencia no valida"
- self.errors.append(msg)
-
# TODO: Test
if not self.name:
msg = "Necesita ingresar una pregunta"
@@ -324,20 +351,42 @@ class Field(AbastractObject):
if len(self.errors):
raise Field.ValidationError(str(self.errors))
- def need_options(self):
- return self.widget_type in (
- 'MultipleCheckBox', 'RadioButton', 'DropDownList')
+ def to_python(self, with_errors=False, img_serialize=False):
+ data = {}
+ data.update({
+ 'name': self.name,
+ 'widget_type': self.widget_type,
+ 'options': {}
+ })
+ if self.dependence:
+ data.update({'dependence': self.dependence})
-class Group(AbastractObject):
+ if with_errors:
+ data.update({'errors': self.errors})
- def __init__(self, name, fields=[]):
- super(Group, self).__init__()
- self.name = name
- self.fields = fields
+ options = self.options if self.options else []
+ for option in options:
+ data['options'].update(option.to_python(
+ with_errors=with_errors, img_serialize=img_serialize)
+ )
+
+ return {'%d' % self.order: data}
+
+
+class Group(AbstractObject, ComponentStructure):
+
+ def __init__(self, data={}, *args, **kwargs):
+ super(Group, self).__init__(*args, **kwargs)
+
+ order = data.get('order', None)
+ self.order = int(order) if order else order
+ self.name = data.get('name', None)
+ self.fields = data.get('fields', [])
def add_field(self, field, order):
order = int(order)
+ field.order = order
fields_pre = self.fields[:order]
fields_post = self.fields[order:]
self.fields = fields_pre + [field] + fields_post
@@ -358,8 +407,22 @@ class Group(AbastractObject):
if len(self.errors):
raise Group.ValidationError(str(self.errors))
+ def to_python(self, with_errors=False, img_serialize=False):
+ data = {'name': self.name, 'fields': {}}
+
+ if with_errors:
+ data.update({'errors': self.errors})
-class Structure(AbastractObject):
+ for field_obj in self.fields:
+ field_data = field_obj.to_python(
+ with_errors=with_errors, img_serialize=img_serialize
+ )
+ data['fields'].update(field_data)
+
+ return {'%d' % self.order: data}
+
+
+class Structure(AbstractObject, ComponentStructure):
"""
{
@@ -368,19 +431,22 @@ class Structure(AbastractObject):
'name': 'group name',
'fields': {
'0': {
- 'widget_type': 'MultipleCheckBox',
- 'name': 'sagas',
- 'options': {'2': {'text': 'label or default value'}},
- 'dependence': '1',
- }
+ 'widget_type': ...,
+ 'name': ...,
+ 'options': ...,
+ 'dependence': ...,
+ },
+ '1' ...
}
- }
+ },
+ '1' ...
+ ...
}
}
"""
- def __init__(self, data=None, poll=None):
- super(Structure, self).__init__()
+ def __init__(self, data=None, poll=None, *args, **kwargs):
+ super(Structure, self).__init__(poll, *args, **kwargs)
self.data = data
self.groups = []
self.poll = poll
@@ -394,25 +460,29 @@ class Structure(AbastractObject):
self._poll_id = str(poll_id) if poll_id else self._poll_id
self._poll_id = self.data.get('poll_id', self._poll_id)
- # Getting id
- _id = data.get('id', None) or data.get('_id', None)
- if _id and (isinstance(_id, str) or isinstance(_id, unicode)):
- self.id = ObjectId(_id)
- elif _id and isinstance(_id, ObjectId):
- self.id = _id
-
# Build model Structure obj based in dict data
if self.data:
- # TODO: Revisar la key groups
+ # Getting id
+ _id = data.get('id', None) or data.get('_id', None)
+ if _id and (isinstance(_id, str) or isinstance(_id, unicode)):
+ self.id = ObjectId(_id)
+ elif _id and isinstance(_id, ObjectId):
+ self.id = _id
+
groups_info = data['groups']
for group_order, group_data in groups_info.iteritems():
- group = Group(name=group_data['name'])
+ group = Group({
+ 'order': group_order,
+ 'name': group_data['name']
+ }, poll=self.poll)
+
fields_info = group_data.get('fields', {})
for field_order, field_data in fields_info.iteritems():
- field = Field.from_dict(field_data)
+ field_data.update({'order': field_order})
+ field = Field(field_data, poll=self.poll)
field.add_options(field_data.get('options', {}))
- field.add_dependence(field_data.get('dependence', None))
group.add_field(field, field_order)
+
self.add_group(group, group_order)
# Require: parent poll id !!!
@@ -425,6 +495,7 @@ class Structure(AbastractObject):
def add_group(self, group, order):
order = int(order)
+ group.order = order
groups_pre = self.groups[:order]
groups_post = self.groups[order:]
self.groups = groups_pre + [group] + groups_post
@@ -477,53 +548,24 @@ class Structure(AbastractObject):
return valid
- # TODO: test!, then refactoring, IDEA: to_dict for each class
- def to_dict(self, with_errors=False):
- _dict = dict()
- for group_order, group_obj in enumerate(self.groups):
- group_order = str(group_order)
- _dict[group_order] = {
- 'name': group_obj.name, 'fields': {}
- }
- if with_errors:
- _dict[group_order].update({'errors': group_obj.errors})
-
- for field_order, field_obj in enumerate(group_obj.fields):
- field_order = str(field_order)
- _dict[group_order]['fields'].update({
- '%s' % field_order: {
- 'name': field_obj.name,
- 'widget_type': field_obj.widget_type,
- 'dependence': field_obj.dependence,
- 'options': {}
- }
- })
- if with_errors:
- _dict[group_order]['fields'][field_order].update(
- {'errors': field_obj.errors})
-
- options = field_obj.options if field_obj.options else []
- for option in options:
- _dic_field = _dict[group_order]['fields'][field_order]
-
- # TODO: Check when opt_data = {}
- opt_data = {'text': option.text}
- if option.img_name:
- opt_data = {'img_name': option.img_name}
- if option.weight:
- opt_data.update({'weight': option.weight})
- _dic_field['options'].update(
- {'%s' % option.id: opt_data}
- )
-
- return {'groups': _dict}
+ def to_python(self, with_errors=False, img_serialize=False):
+ data = {'groups': {}}
+
+ for group_obj in self.groups:
+ data['groups'].update(
+ group_obj.to_python(
+ with_errors=with_errors, img_serialize=img_serialize
+ )
+ )
+
+ return data
def save(self):
structure_id = None
self.validate()
- _dict = self.to_dict()
+ _dict = self.to_python()
# Prepare dbref to poll object
if not self.poll:
diff --git a/webapp/polls/templates/mustache/field.html b/webapp/polls/templates/mustache/field.html
index 2c68ac0..3987571 100644
--- a/webapp/polls/templates/mustache/field.html
+++ b/webapp/polls/templates/mustache/field.html
@@ -15,20 +15,30 @@
[[ /visible_errors ]]
<div class="row-fluid">
- <i class="field_sortable_area icon-move"></i>
<button class="WField_remove btn btn-danger">
<i class="icon-remove-sign icon-white"></i>
</button>
- <label>Tipo de pregunta:</label>
+ <label><b>Pregunta</b>:</label>
+ <input
+ class="input-xxlarge"
+ type="text"
+ name="groups.[[ group_order ]].fields.[[ order ]].name"
+ value="[[ name ]]"
+ placeholder="Pregunta..." />
+
+ </div>
+
+ <div class="row-fluid">
+ <label><b>Tipo de pregunta</b>:</label>
<select class="WFieldWidgetType" name="groups.[[ group_order ]].fields.[[ order ]].widget_type" style="width: 300px;">
[[ #WIDGET_TYPES ]]
<option value="[[ key ]]" [[ #selected ]]selected="selected"[[ /selected ]]>[[ value ]]</option>
[[ /WIDGET_TYPES ]]
</select>
- <label>Depende de la opción:</label>
+ <label><b>Depende de la opci&oacute;n</b>:</label>
<input
class="input-medium droppable"
type="text"
@@ -38,21 +48,9 @@
</div>
- <div class="row-fluid">
-
- <label>Pregunta:</label>
- <input
- class="input-xxlarge"
- type="text"
- name="groups.[[ group_order ]].fields.[[ order ]].name"
- value="[[ name ]]"
- placeholder="Pregunta..." />
-
- </div>
-
- <div class="WFieldAddOptionButton_container"></div>
+ <div class="WFieldAddOptionButton_container" style="margin: 5px;"></div>
- <div class="WFieldOptions_container"></div>
+ <div class="WFieldOptions_container well"></div>
</div>
</script> \ No newline at end of file
diff --git a/webapp/polls/templates/mustache/group.html b/webapp/polls/templates/mustache/group.html
index 4f5409d..3ea1cde 100644
--- a/webapp/polls/templates/mustache/group.html
+++ b/webapp/polls/templates/mustache/group.html
@@ -3,7 +3,11 @@
<div class="group row-fluid">
<legend>
- <i class="group_sortable_area icon-move"></i>
+
+ <button class="WGroup_remove btn btn-danger">
+ <i class="icon-remove-sign icon-white"></i>
+ </button>
+
<label>
<h4>Nombre del Grupo:</h4>
</label>
@@ -11,12 +15,8 @@
<input type="text" name="groups.[[ order ]].name" value="[[ name ]]" />
<input type="hidden" name="groups.[[ order ]].order" value="[[ order ]]" class="group_order" />
- <button class="WGroup_remove btn btn-danger">
- <i class="icon-remove-sign icon-white"></i>
- </button>
-
<button class="WGroup_add_field btn btn-success">
- <i class="icon-plus-sign icon-white"></i>Agregar pregunta
+ <i class="icon-plus-sign icon-white"></i>&nbsp;Agregar pregunta
</button>
[[ #visible_errors ]]
diff --git a/webapp/polls/templates/mustache/option.html b/webapp/polls/templates/mustache/option.html
index 3cbf119..0527f05 100644
--- a/webapp/polls/templates/mustache/option.html
+++ b/webapp/polls/templates/mustache/option.html
@@ -1,9 +1,9 @@
<!-- Template: Field Option -->
<script type="text/x-mustache-template" name="field_option">
- <div class="span6 input-append">
- <label>
- Opci&oacute;n (ID: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>)
- </label><br />
+ <div class="span6" style="margin-left: 20px">
+ <label style="padding: 5px;">
+ <b>ID</b>: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>
+ </label>
<input
class="input-large"
type="text"
@@ -17,7 +17,7 @@
value="[[ weight ]]"
placeholder="peso" />
<button class="WFieldOptions_remove btn btn-danger">
- <i class="icon-remove-sign icon-white"></i>
+ <i class="icon-trash icon-white"></i>
</button>
</div>
</script>
diff --git a/webapp/polls/templates/mustache/option_default.html b/webapp/polls/templates/mustache/option_default.html
index eb59807..130acbf 100644
--- a/webapp/polls/templates/mustache/option_default.html
+++ b/webapp/polls/templates/mustache/option_default.html
@@ -7,4 +7,7 @@
name="groups.[[ group_order ]].fields.[[ field_order ]].options.[[ id ]].text"
value="[[ value ]]"
placeholder="(opcional)" />
+ <span>
+ Si ingresa un texto default, estar&aacute; escrito en la respuesta a esta pregunta.
+ </span>
</script> \ No newline at end of file
diff --git a/webapp/polls/templates/mustache/option_image_thumbnail.html b/webapp/polls/templates/mustache/option_image_thumbnail.html
index 90caefa..43244a7 100644
--- a/webapp/polls/templates/mustache/option_image_thumbnail.html
+++ b/webapp/polls/templates/mustache/option_image_thumbnail.html
@@ -1,23 +1,24 @@
<!-- Template: Field Image option thumbnail -->
<script type="text/x-mustache-template" name="field_option_image_thumbnail">
- <div class="pull-left WFieldImageOption_container well well-small" style="margin: 10px;">
+ <div class="span3 WFieldImageOption_container well well-small" style="margin: 10px;">
+ <span class="pull-right">
+ <a href="#" class="WFieldImageOptions_remove_button btn btn-danger">
+ <i class="icon-trash icon-white"></i>
+ </a>
+ </span>
<label>
- Opci&oacute;n (ID: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>)
+ <b>ID</b>: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>
</label><br />
<center>
<input type="hidden" name="groups.[[ group_order ]].fields.[[ field_order ]].options.[[ id ]].img_name" value="[[ img_name ]]" />
<div class="img_container"></div>
+ <b>Peso</b>:
<input
class="input-small"
type="text"
name="groups.[[ group_order ]].fields.[[ field_order ]].options.[[ id ]].weight"
value="[[ weight ]]"
placeholder="peso" />
- <span>
- <a href="#" class="WFieldImageOptions_remove_button btn btn-danger" style="width: 80%; margin-top: 5px;">
- <i class="icon-trash icon-white"></i>
- </a>
- </span>
</center>
</div>
</script> \ No newline at end of file
diff --git a/webapp/polls/templates/mustache/option_image_upload.html b/webapp/polls/templates/mustache/option_image_upload.html
index 89dd0f6..325596d 100644
--- a/webapp/polls/templates/mustache/option_image_upload.html
+++ b/webapp/polls/templates/mustache/option_image_upload.html
@@ -1,9 +1,9 @@
<!-- Template: Field Image option upload -->
<script type="text/x-mustache-template" name="field_option_image_upload">
- <div class="fileupload fileupload-new pull-left well well-small" data-provides="fileupload" style="margin: 10px;">
+ <div class="fileupload fileupload-new span3 well well-small" data-provides="fileupload" style="margin: 10px;">
<label>
- Opci&oacute;n (ID: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>)
+ <b>ID</b>: <span class="draggable"><i class="icon-move"></i>[[ id ]]</span>
</label><br />
<center>
<div class="fileupload-new thumbnail" style="width: 150px; height: 150px;">
@@ -11,6 +11,7 @@
</div>
<div class="fileupload-preview fileupload-exists thumbnail" style="max-width: 150px; max-height: 150px; line-height: 20px;"></div>
<div>
+ <b>Peso</b>:
<input
class="input-small"
type="text"
diff --git a/webapp/polls/templates/poll-form.html b/webapp/polls/templates/poll-form.html
index 9470a87..a182e5a 100644
--- a/webapp/polls/templates/poll-form.html
+++ b/webapp/polls/templates/poll-form.html
@@ -24,7 +24,13 @@
<option value="{{ value }}" {% if status == poll.status %}selected="selected"{% endif %}>{{ status }}</option>
{% endfor %}
</select>
- <span class="help-inline">{{ form.status.errors }}</span>
+ <span class="help-block">
+ <p>Una encuesta "cerrada" no podr&aacute; ser modificada. Una vez "cerrada", solo pordr&aacute; ser "abierta" por un usuario de mas alto privilegio.
+ </p>
+ </span>
+ {% if form.status.errors %}
+ <span class="help-inline">{{ form.status.errors }}</span>
+ {% endif %}
</div>
</div>
{% endif %}
diff --git a/webapp/polls/templates/poll-list.html b/webapp/polls/templates/poll-list.html
index 1e95b1d..bfa0eb3 100644
--- a/webapp/polls/templates/poll-list.html
+++ b/webapp/polls/templates/poll-list.html
@@ -1,6 +1,7 @@
{% extends "base-poll.html" %}
{% block main_container %}
+
<table class="table table-hover table-bordered">
<thead>
<tr>
@@ -11,7 +12,7 @@
</thead>
<tbody>
{% for poll in polls %}
- <tr {% if not poll.is_open %}style="background-color: #f2dede;"{% endif %}>
+ <tr style="background-color: {% if poll.is_open %}#f2dede;{% else %}#e8f4db{% endif %}">
<td>{{ poll.name|capfirst }}</td>
<td>{{ poll.status|capfirst }}</td>
<td>
@@ -25,7 +26,7 @@
</a>
</td>
<td>
- <a class="btn" href="{% url polls:download poll_id=poll.id %}">
+ <a class="btn {% if poll.is_open %}disabled{% endif %}" href="{% url polls:download poll_id=poll.id %}">
<i class="icon-download-alt"></i>&nbsp;Descargar encuesta
</a>
</td>
diff --git a/webapp/polls/templates/poll-structure-form.html b/webapp/polls/templates/poll-structure-form.html
index 6a0a44e..b695395 100644
--- a/webapp/polls/templates/poll-structure-form.html
+++ b/webapp/polls/templates/poll-structure-form.html
@@ -5,9 +5,7 @@
{% block extra_css %}
<style type="text/css">
- body {
- padding-top: 110px;
- }
+ body { padding-top: 40px; }
</style>
<link href="{{ STATIC_URL }}css/bootstrap-fileupload.css" rel="stylesheet" />
@@ -16,12 +14,19 @@
{% block main_container %}
<script src="{{ STATIC_URL }}js/bootstrap-fileupload.js"></script>
- <div style="margin-top: 40px;" class="alert alert-info navbar-fixed-top">Para generar dependencias, arrastré el ID de la opción hacia el campo "Depende de la opción". Las dependencias validas se realizan desde una opción de una pregunta de menor orden hacia una pregunta de mayor orden.</div>
+ <div class="alert alert-info">
+ <ul>
+ <li>
+ Para generar dependencias, arrastre el ID de la opci&oacute;n hacia el campo "Depende de la opci&oacute;n", o bien, escriba el ID indicado. <i class="icon-warning-sign"></i>&nbsp;En esta version no existen criterios sobre las dependecias, tenga cuidado de realizarlas correctamente y no generar inconsistencias (ej: no haga dependiente una pregunta de una opci&oacute;n perteneciente a la misma pregunta.)
+ </li>
+ <li>
+ La opciones con imagenes deber&aacute;n ser de dimensiones menores a 250px de ancho y 250px de alto. Formatos validos: GIF, JPG, PNG.
+ </li>
+ </ul>
+ </div>
<center><h2>{{ poll.name|capfirst }}</h2></center>
- <h3>Estructura</h3>
-
{% if errors %}
<div class="control-group error">
<label class="control-label">
@@ -46,7 +51,7 @@
<div class="ps-form-toolbar btn-toolbar clearfix">
<div class="btn-group">
- <button class="btn btn-primary"><i class="icon-white icon-circle-arrow-right"></i>&nbsp;{% trans 'Generar encuesta' %}</button>
+ <button class="btn btn-primary"><i class="icon-white icon-edit"></i>&nbsp;{% trans 'Guardar' %}</button>
</div>
</div>
diff --git a/webapp/polls/templates/tags/structure.html b/webapp/polls/templates/tags/structure.html
index 18cc622..9b525b8 100644
--- a/webapp/polls/templates/tags/structure.html
+++ b/webapp/polls/templates/tags/structure.html
@@ -2,7 +2,7 @@
<!-- Containers -->
<button id="WGroup_add" class="btn btn-primary">
- <i class="icon-white icon-add"></i>&nbsp;{% trans 'Agregar grupo' %}
+ <i class="icon-plus-sign icon-white"></i>&nbsp;{% trans 'Agregar grupo' %}
</button>
<div id="WGroupContainer"></div>
@@ -24,13 +24,13 @@
<!-- Global variables for dynamic_structure.js -->
<script type="text/javascript">
- var groups = {{ groups }},
- WIDGET_TYPES = {{ WIDGET_TYPES }},
- WITH_OPTIONS = {{ WITH_OPTIONS }},
- WITH_IMAGES = {{ WITH_IMAGES }},
- OFFSET_OPTION_ID = {{ OFFSET_OPTION_ID }},
- IMAGE_OPTIONS_TMP_MEDIA_URL = {{ IMAGE_OPTIONS_TMP_MEDIA_URL }},
- POLL_ID = {{ POLL_ID }};
+ var groups = {{ groups|json }},
+ WIDGET_TYPES = {{ WIDGET_TYPES|json }},
+ WITH_OPTIONS = {{ WITH_OPTIONS|json }},
+ WITH_IMAGES = {{ WITH_IMAGES|json }},
+ OFFSET_OPTION_ID = {{ OFFSET_OPTION_ID|json }},
+ IMAGE_OPTIONS_TMP_MEDIA_URL = {{ IMAGE_OPTIONS_TMP_MEDIA_URL|json }},
+ POLL_ID = {{ POLL_ID|json }};
</script>
diff --git a/webapp/polls/templatetags/poll_tags.py b/webapp/polls/templatetags/poll_tags.py
index 1bf781f..9a8c93a 100644
--- a/webapp/polls/templatetags/poll_tags.py
+++ b/webapp/polls/templatetags/poll_tags.py
@@ -10,25 +10,26 @@ from polls.models import WIDGET_TYPES, WITH_OPTIONS, WITH_IMAGES, Field
register = template.Library()
+@register.filter(name="json")
+def json_filter(obj):
+ return SafeUnicode(json.dumps(obj))
+
+
@register.simple_tag(takes_context=True)
def render_structure(context, structure):
- IMAGE_OPTIONS_TMP_MEDIA_URL = SafeUnicode(json.dumps(
- structure.get_image_options_tmp_media_url()))
- structure = structure.to_dict(with_errors=True)
- groups = SafeUnicode(json.dumps(structure.get("groups", {})))
- widget_types = SafeUnicode(json.dumps(
- [{'key': k, 'value': v} for k, v in WIDGET_TYPES]))
+ structure_data = structure.to_python(with_errors=True)
+ IMAGE_OPTIONS_TMP_MEDIA_URL = structure.get_image_options_tmp_media_url()
return render_to_string(
'tags/structure.html',
{
"STATIC_URL": context['STATIC_URL'],
- "WIDGET_TYPES": widget_types,
- "WITH_OPTIONS": SafeUnicode(json.dumps(WITH_OPTIONS)),
- "WITH_IMAGES": SafeUnicode(json.dumps(WITH_IMAGES)),
- "OFFSET_OPTION_ID": SafeUnicode(json.dumps(Field.get_offset_id())),
+ "WIDGET_TYPES": [{'key': k, 'value': v} for k, v in WIDGET_TYPES],
+ "WITH_OPTIONS": WITH_OPTIONS,
+ "WITH_IMAGES": WITH_IMAGES,
+ "OFFSET_OPTION_ID": Field.get_offset_id(),
"IMAGE_OPTIONS_TMP_MEDIA_URL": IMAGE_OPTIONS_TMP_MEDIA_URL,
- "POLL_ID": SafeUnicode(json.dumps(str(context['poll'].id))),
- "groups": groups
+ "POLL_ID": str(context['poll'].id),
+ "groups": structure_data.get("groups", {})
}
)
diff --git a/webapp/polls/tests.py b/webapp/polls/tests.py
deleted file mode 100644
index 525f9c5..0000000
--- a/webapp/polls/tests.py
+++ /dev/null
@@ -1,473 +0,0 @@
-# -*- encoding: utf-8 -*-
-from bson import ObjectId
-
-from django.test import TestCase
-
-from polls.models import (
- Poll, Field, Group, Structure, Option, WIDGET_TYPES)
-from polls.forms import PollAddForm
-
-from utils.test import MongoTestCase, mock_in_memory_image, mock_text_file
-
-
-class PollTests(MongoTestCase):
-
- def test_poll_init(self):
- name = 'nombre de encuesta'
- data = {'name': name}
-
- poll = Poll(data=data)
- self.assertIsNone(poll.id)
- self.assertEqual(name, poll.name)
-
- id = '513a0634421aa932884daa5c'
- data = {'id': id, 'name': name}
-
- poll = Poll(data=data)
- self.assertEqual(ObjectId(id), poll.id)
- self.assertEqual(name, poll.name)
-
- def test_validate(self):
- data = {}
- poll = Poll(data=data)
-
- self.assertRaises(Poll.ValidationError, poll.validate)
-
- def test_save(self):
-
- name = 'nombre de encuesta'
- data = {'name': name}
-
- poll = Poll(data=data)
- poll.save()
-
- self.assertEqual(1, self.db.polls.count())
-
- def test_unique_name(self):
-
- name = "unique name"
- data = {'name': name}
-
- poll = Poll(data=data)
- poll.save()
-
- poll = Poll(data=data)
-
- self.assertRaisesRegexp(
- Poll.ValidationError,
- "Poll name '%s' already in use." % poll.name,
- poll.validate
- )
-
- data = {'name': "name"}
- poll = Poll(data=data)
-
- fail = True
- try:
- poll.save()
- except Poll.ValidationError:
- fail = False
-
- self.assertTrue(fail)
-
- def test_get(self):
-
- self.assertIsNone(Poll.get(id=None))
-
- name = 'nombre de encuesta'
- data = {'name': name}
-
- poll = Poll(data=data)
- poll_id = poll.save()
-
- poll = Poll.get(id=poll_id)
-
- self.assertIsNotNone(poll)
- self.assertIsNotNone(poll.id)
- self.assertIsInstance(poll_id, ObjectId)
- self.assertEqual(name, poll.name)
- self.assertEqual(Poll.OPEN, poll.status)
-
- def test_status(self):
-
- name = 'nombre de encuesta'
- data = {'name': name}
-
- poll = Poll(data=data)
-
- self.assertEqual(Poll.OPEN, poll.status)
-
- poll_id = poll.save()
-
- self.assertEqual(Poll.OPEN, Poll.get(poll_id).status)
-
- def test_is_open(self):
-
- name = 'nombre de encuesta'
- data = {'name': name}
-
- poll = Poll(data=data)
-
- self.assertTrue(poll.is_open())
-
- poll.status = Poll.CLOSED
-
- self.assertFalse(poll.is_open())
-
-
-class PollFormTests(MongoTestCase):
-
- def test_save(self):
- self.assertEqual(0, self.db.polls.count())
-
- name = 'nombre de encuesta'
- data = {'name': name, 'status': Poll.OPEN}
-
- form = PollAddForm(data=data)
-
- self.assertTrue(form.is_valid())
-
- poll = form.save()
-
- self.assertIsNotNone(poll)
- self.assertIsInstance(poll, Poll)
- self.assertEqual(1, self.db.polls.count())
-
- def test_no_valid_data(self):
- form = PollAddForm()
-
- self.assertFalse(form.is_valid())
-
-
-class FieldsTests(TestCase):
-
- def setUp(self):
- self.field = Field(
- key='0001',
- name='field_0',
- widget_type='TextInput',
- )
-
- def test_basic_field(self):
-
- self.assertEqual('0001', self.field.key)
- self.assertEqual('field_0', self.field.name)
- self.assertEqual('TextInput', self.field.widget_type)
-
- def test_invalid_widget_type(self):
- field_factory = lambda: Field(
- key="0001",
- name='field_0',
- widget_type='bad_widget_type',
- )
-
- self.assertRaises(AttributeError, field_factory)
-
- def test_valid_widget_types(self):
- for widget_type in dict(WIDGET_TYPES).keys():
- field = Field(
- key='0001',
- name='field_0',
- widget_type=widget_type,
- )
- self.assertTrue(field)
-
- def test_add_dependence(self):
- dependence = '414541212'
- self.field.add_dependence(dependence)
-
- self.assertEqual(dependence, self.field.dependence)
-
- def test_from_dict(self):
- dependence = '343523523'
- data = {
- 'widget_type': 'MultipleCheckBox',
- 'name': 'field_0',
- 'dependence': dependence
- }
- field = Field.from_dict(data)
-
- self.assertEqual('field_0', field.name)
- self.assertEqual('MultipleCheckBox', field.widget_type)
- self.assertEqual(dependence, field.dependence)
-
- def test_add_options(self):
- data = {
- 'widget_type': 'MultipleCheckBox',
- 'name': 'field_0',
- }
- field = Field.from_dict(data)
-
- options_data = {
- '1': {'text': None},
- '2': {'text': None},
- '3': {'text': 'test', 'enable': '0001'}
- }
- field.add_options(options_data)
-
- self.assertEqual(1, len(field.options))
-
- def test_add_image_options(self):
- data = {
- 'widget_type': 'ImageCheckBox',
- 'name': 'field_0',
- }
- field = Field.from_dict(data)
-
- img_file = mock_in_memory_image()
-
- options_data = {
- '1': {'img': img_file},
- }
- field.add_options(options_data)
-
- self.assertEqual(1, len(field.options))
-
- def test_validate(self):
-
- self.field.widget_type = "MultipleCheckBox"
-
- self.assertRaises(Field.ValidationError, self.field.validate)
- self.assertEqual(1, len(self.field.errors))
-
- self.field.widget_type = "RadioButton"
-
- self.assertRaises(Field.ValidationError, self.field.validate)
- self.assertEqual(1, len(self.field.errors))
-
- self.field.widget_type = "DropDownList"
-
- self.assertRaises(Field.ValidationError, self.field.validate)
- self.assertEqual(1, len(self.field.errors))
-
-
-class OptionTests(TestCase):
-
- def test_basic_option(self):
- option = Option(id='id', text='text')
-
- self.assertEqual('text', option.text)
- self.assertIsNotNone(option.id)
-
- def test_from_dict(self):
- data = {'id': '1', 'text': 'si'}
- option = Option.from_dict(data)
-
- self.assertEqual('1', option.id)
- self.assertEqual('si', option.text)
-
- def test_image_option(self):
-
- img_name = 'image.jpg'
- img_file = mock_in_memory_image(img_name)
-
- data = {'id': '1', 'img': img_file}
- option = Option.from_dict(data)
-
- self.assertEqual('1', option.id)
- self.assertEqual(img_file, option.img)
-
- def test_validate(self):
- invalid_img_file = mock_text_file()
-
- data = {'id': '1', 'img': invalid_img_file}
- option = Option.from_dict(data)
-
- self.assertRaises(Option.ValidationError, option.validate)
-
- def test_weighting(self):
-
- data = {'id': '1', 'weight': "-100"}
- option = Option.from_dict(data)
-
- self.assertEqual(-100, option.weight)
-
- def test_weight_required(self):
-
- data = {'id': '1'}
- option = Option.from_dict(data)
-
- self.assertRaises(Option.ValidationError, option.validate)
- msg = u"opcion %s: ponderación requerida." % option.id
- self.assertTrue(msg in option.errors)
-
-
-class GroupTests(TestCase):
-
- def setUp(self):
- self.group = Group(name='group_name')
-
- def test_basic_group(self):
- group = Group(name='group_name')
-
- self.assertEqual('group_name', group.name)
- self.assertEqual([], group.fields)
-
- def test_add_field(self):
- len_group = len(self.group.fields)
-
- field_0 = Field(key='0001', name='field_name', widget_type='TextInput')
- self.group.add_field(field_0, 0)
-
- self.assertEqual(len_group + 1, len(self.group.fields))
- self.assertIsInstance(field_0, Field)
-
- field_1 = Field(key='0002', name='field_name', widget_type='TextInput')
- self.group.add_field(field_1, 0)
-
- self.assertEqual(field_0, self.group.fields[1])
- self.assertEqual(field_1, self.group.fields[0])
-
- def test_validate(self):
-
- group = Group(name=None, fields=None)
- self.group.name = None
-
- self.assertRaises(Group.ValidationError, group.validate)
- self.assertEqual(2, len(group.errors))
-
- group = Group(name="", fields=None)
- self.assertRaises(Group.ValidationError, group.validate)
- self.assertEqual(2, len(group.errors))
-
- group = Group(name="name", fields=None)
- self.assertRaises(Group.ValidationError, group.validate)
- self.assertEqual(1, len(group.errors))
-
-
-class StructureTests(MongoTestCase):
-
- def setUp(self):
- poll = Poll(data={'name': 'name'})
- poll_id = poll.save()
-
- self.poll = Poll.get(id=poll_id)
-
- self.data = {
- 'poll_id': 'POLL_ID',
- 'groups': {
- '0': {
- 'name': 'group_0',
- 'fields': {
- '0': {
- 'widget_type': 'TextInput',
- 'name': 'field_0_0'
- }
- }
- }
- }
- }
-
- def test_from_dict(self):
- data = {
- 'groups': {
- '0': {
- 'name': 'group_0',
- 'fields': {
- '0': {
- 'widget_type': 'TextInput',
- 'name': 'field_0_0'
- },
- '1': {
- 'widget_type': 'RadioButton',
- 'name': 'field_0_1'
- }
- },
- },
- '1': {
- 'name': 'group_1',
- 'fields': {
- '0': {
- 'widget_type': 'MultipleCheckBox',
- 'name': 'field_1_0'
- },
- '1': {
- 'widget_type': 'DropDownList',
- 'name': 'field_1_1'
- }
- },
- }
- }
- }
-
- structure = Structure(data=data, poll=self.poll)
-
- group_0 = structure.groups[0]
- self.assertEqual('group_0', group_0.name)
- self.assertEqual(2, len(group_0.fields))
-
- group_1 = structure.groups[1]
- self.assertEqual('group_1', group_1.name)
- self.assertEqual(2, len(group_1.fields))
-
- field_0_0 = group_0.fields[0]
- self.assertEqual('field_0_0', field_0_0.name)
- self.assertEqual('TextInput', field_0_0.widget_type)
- field_0_1 = group_0.fields[1]
- self.assertEqual('field_0_1', field_0_1.name)
- self.assertEqual('RadioButton', field_0_1.widget_type)
- field_1_0 = group_1.fields[0]
- self.assertEqual('field_1_0', field_1_0.name)
- self.assertEqual('MultipleCheckBox', field_1_0.widget_type)
- field_1_1 = group_1.fields[1]
- self.assertEqual('field_1_1', field_1_1.name)
- self.assertEqual('DropDownList', field_1_1.widget_type)
-
- def test_is_valid(self):
- data = {
- 'groups': {
- '0': {
- 'name': 'group_0',
- 'fields': {
- '0': { # has no options for a widget_type that needs
- 'widget_type': 'RadioButton',
- 'name': 'field_0_0'
- },
- }
- },
- '1': {
- 'name': '', # has no name
- 'fields': {} # has no fields
- }
- }
- }
-
- structure = Structure(data=data, poll=self.poll)
-
- self.assertFalse(structure.is_valid())
-
- field_0_0 = structure.groups[0].fields[0]
-
- self.assertEqual(1, len(field_0_0.errors))
-
- group_1 = structure.groups[1]
-
- self.assertEqual(2, len(group_1.errors))
-
- def test_invalid_structure(self):
- data = {}
-
- structure = Structure(data=data, poll=self.poll)
-
- self.assertFalse(structure.is_valid())
-
- self.assertEqual(1, len(structure.errors))
-
- def test_save(self):
-
- structure = Structure(data=self.data)
-
- self.assertRaises(structure.ValidationError, structure.save)
-
- structure = Structure(data=self.data, poll=self.poll)
- structure.save()
-
- self.assertEqual(1, self.db.structures.count())
-
- def test_get(self):
- structure = Structure(data=self.data, poll=self.poll)
- structure_id = structure.save()
-
- structure = Structure.get(id=structure_id)
-
- self.assertEqual(self.poll.id, structure.poll.id)
diff --git a/webapp/polls/tests/__init__.py b/webapp/polls/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webapp/polls/tests/__init__.py
diff --git a/webapp/polls/tests/field_tests.py b/webapp/polls/tests/field_tests.py
new file mode 100644
index 0000000..04e7cd9
--- /dev/null
+++ b/webapp/polls/tests/field_tests.py
@@ -0,0 +1,211 @@
+# -*- encoding: utf-8 -*-
+from polls.models import Poll, Field, WIDGET_TYPES, WITH_OPTIONS, WITH_IMAGES
+
+from utils.test import MongoTestCase, mock_in_memory_image
+
+
+class FieldTests(MongoTestCase):
+
+ def setUp(self):
+ poll = Poll(data={'name': 'name'})
+ poll_id = poll.save()
+
+ self.poll = Poll.get(id=poll_id)
+
+ data = {
+ 'name': "field_0",
+ 'widget_type': Field.TextInput,
+ 'dependence': "414541212",
+ 'order': 0
+ }
+ self.field = Field(data, poll=self.poll)
+
+ def test_field(self):
+ self.assertEqual(0, self.field.order)
+ self.assertEqual('field_0', self.field.name)
+ self.assertEqual(Field.TextInput, self.field.widget_type)
+ self.assertEqual("414541212", self.field.dependence)
+
+ def test_invalid_widget_type(self):
+ field_factory = lambda: Field({
+ 'name': "field_0",
+ 'widget_type': "bad_widget_type",
+ })
+
+ self.assertRaises(AttributeError, field_factory)
+
+ def test_valid_widget_types(self):
+ for widget_type in dict(WIDGET_TYPES).keys():
+
+ field = Field({
+ 'name': 'field_0',
+ 'widget_type': widget_type,
+ })
+ self.assertTrue(field)
+
+ def test_add_options(self):
+ self.field.widget_type = Field.MultipleCheckBox
+
+ options_data = {
+ '1': {'text': None},
+ '2': {'text': None},
+ '3': {'text': 'test', 'enable': '0001'}
+ }
+ self.field.add_options(options_data)
+
+ self.assertEqual(1, len(self.field.options))
+
+ option = self.field.options[0]
+ self.assertEqual(self.poll, option.poll)
+
+ def test_add_image_options(self):
+
+ self.field.widget_type = Field.ImageCheckBox,
+
+ img_file = mock_in_memory_image()
+
+ options_data = {
+ '1': {'img': img_file},
+ }
+ self.field.add_options(options_data)
+
+ self.assertEqual(1, len(self.field.options))
+
+ def test_validate_without_options(self):
+
+ self.field.widget_type = Field.MultipleCheckBox
+
+ self.assertRaises(Field.ValidationError, self.field.validate)
+ self.assertEqual(1, len(self.field.errors))
+
+ self.field.widget_type = Field.RadioButton
+
+ self.assertRaises(Field.ValidationError, self.field.validate)
+ self.assertEqual(1, len(self.field.errors))
+
+ self.field.widget_type = Field.DropDownList
+
+ self.assertRaises(Field.ValidationError, self.field.validate)
+ self.assertEqual(1, len(self.field.errors))
+
+ self.field.widget_type = Field.ImageCheckBox
+
+ self.assertRaises(Field.ValidationError, self.field.validate)
+ self.assertEqual(1, len(self.field.errors))
+
+ self.field.widget_type = Field.ImageRadioButton
+
+ self.assertRaises(Field.ValidationError, self.field.validate)
+ self.assertEqual(1, len(self.field.errors))
+
+ def test_to_python(self):
+
+ # Widget_type = TextInput
+ self.field.widget_type = Field.TextInput
+ self.field.add_options({'1': {'text': "text"}})
+
+ expected = {
+ '0': {
+ 'name': "field_0",
+ 'widget_type': Field.TextInput,
+ 'dependence': "414541212",
+ 'options': {
+ '1': {
+ 'text': "text"
+ }
+ }
+ }
+ }
+
+ self.assertEqual(expected, self.field.to_python())
+
+ # Widget_type = TextInput
+ self.field.widget_type = Field.TextInput
+ self.field.dependence = ""
+ self.field.add_options({'1': {'text': "text"}})
+
+ expected = {
+ '0': {
+ 'name': "field_0",
+ 'widget_type': Field.TextInput,
+ 'options': {
+ '1': {
+ 'text': "text"
+ }
+ }
+ }
+ }
+
+ self.assertEqual(expected, self.field.to_python())
+
+ # Widget_type kind with options
+ order = 0
+ for widget_type in (set(WITH_OPTIONS) - set(WITH_IMAGES)):
+ data = {
+ 'name': "field_0",
+ 'widget_type': widget_type,
+ 'dependence': "414541212",
+ 'order': order
+ }
+ field = Field(data)
+ field.add_options({
+ '1': {'text': "text", 'weight': 100},
+ '2': {'text': "text", 'weight': -100}
+ })
+
+ expected = {
+ '%d' % order: {
+ 'name': "field_0",
+ 'widget_type': widget_type,
+ 'dependence': "414541212",
+ 'options': {
+ '1': {
+ 'text': "text",
+ 'weight': 100
+ },
+ '2': {
+ 'text': "text",
+ 'weight': -100
+ }
+ }
+ }
+ }
+
+ self.assertEqual(expected, field.to_python())
+ order += 1
+
+ # Widget_type kind with options with images
+ order = 0
+ for widget_type in WITH_IMAGES:
+ data = {
+ 'name': "field_0",
+ 'widget_type': widget_type,
+ 'dependence': "414541212",
+ 'order': order
+ }
+ field = Field(data)
+ field.add_options({
+ '1': {'img_name': "text.jpg", 'weight': 100},
+ '2': {'img_name': "text.jpg", 'weight': -100}
+ })
+
+ expected = {
+ '%d' % order: {
+ 'name': "field_0",
+ 'widget_type': widget_type,
+ 'dependence': "414541212",
+ 'options': {
+ '1': {
+ 'img_name': "text.jpg",
+ 'weight': 100
+ },
+ '2': {
+ 'img_name': "text.jpg",
+ 'weight': -100
+ }
+ }
+ }
+ }
+
+ self.assertEqual(expected, field.to_python())
+ order += 1
diff --git a/webapp/polls/tests/group_tests.py b/webapp/polls/tests/group_tests.py
new file mode 100644
index 0000000..794136e
--- /dev/null
+++ b/webapp/polls/tests/group_tests.py
@@ -0,0 +1,79 @@
+# -*- encoding: utf-8 -*-
+from django.test import TestCase
+
+from polls.models import Group, Field
+
+
+class GroupTests(TestCase):
+
+ def setUp(self):
+ data = {'name': "group name", 'order': 0}
+ self.group = Group(data)
+
+ def test_group(self):
+ self.assertEqual('group name', self.group.name)
+ self.assertEqual(0, self.group.order)
+ self.assertEqual([], self.group.fields)
+
+ def test_add_field(self):
+ len_group = len(self.group.fields)
+
+ field_0 = Field({'name': 'field_name', 'widget_type': Field.TextInput})
+ self.group.add_field(field_0, 0)
+
+ self.assertEqual(len_group + 1, len(self.group.fields))
+ self.assertEqual(0, field_0.order)
+ self.assertIsInstance(field_0, Field)
+
+ field_1 = Field({'name': 'field_name', 'widget_type': Field.TextInput})
+ self.group.add_field(field_1, 1)
+ self.assertEqual(1, field_1.order)
+
+ self.assertEqual(field_0, self.group.fields[0])
+ self.assertEqual(field_1, self.group.fields[1])
+
+ def test_validate(self):
+
+ group = Group({'name': None, 'fields': None})
+
+ self.assertRaises(Group.ValidationError, group.validate)
+ self.assertEqual(2, len(group.errors))
+
+ group = Group({'name': "", 'fields': None})
+ self.assertRaises(Group.ValidationError, group.validate)
+ self.assertEqual(2, len(group.errors))
+
+ group = Group({'name': "name", 'fields': None})
+ self.assertRaises(Group.ValidationError, group.validate)
+ self.assertEqual(1, len(group.errors))
+
+ def test_to_python(self):
+
+ expected = {
+ '0': {
+ 'name': "group name",
+ 'fields': {
+ '0': {
+ 'name': "field_0",
+ 'widget_type': Field.TextInput,
+ 'options': {
+ '131212': {
+ 'text': "text"
+ }
+ }
+ }
+ }
+ }
+ }
+
+ field = Field({
+ 'name': "field_0",
+ 'widget_type': Field.TextInput,
+ 'order': 0
+ })
+ field.add_options({'131212': {'text': "text"}})
+
+ group = Group({'name': "group name", 'order': 0})
+ group.add_field(field, field.order)
+
+ self.assertEqual(expected, group.to_python())
diff --git a/webapp/polls/tests/option_tests.py b/webapp/polls/tests/option_tests.py
new file mode 100644
index 0000000..cbfbbb1
--- /dev/null
+++ b/webapp/polls/tests/option_tests.py
@@ -0,0 +1,155 @@
+# -*- encoding: utf-8 -*-
+from django.conf import settings
+
+from polls.models import Poll, Option
+
+from utils.test import MongoTestCase, mock_in_memory_image, mock_text_file
+
+
+class OptionTests(MongoTestCase):
+
+ def setUp(self):
+ poll = Poll(data={'name': 'name'})
+ poll_id = poll.save()
+
+ self.poll = Poll.get(id=poll_id)
+
+ def test_option(self):
+
+ data = {'id': "1"}
+ option = Option(data)
+ self.assertEqual('1', option.id)
+
+ def test_option_text(self):
+
+ data = {'id': "1", 'text': "text"}
+ option = Option(data)
+ self.assertEqual('text', option.text)
+
+ def test_option_text_and_weight(self):
+
+ data = {'id': "1", 'text': "text", 'weight': "100"}
+ option = Option(data)
+ self.assertEqual('text', option.text)
+ self.assertEqual(100, option.weight)
+
+ def test_option_img(self):
+
+ img_file = mock_in_memory_image('image.jpg')
+ data = {'id': "1", 'img': img_file}
+ option = Option(data)
+ self.assertEqual(img_file, option.img)
+ self.assertEqual('%s.jpg' % option.id, option.img_name)
+
+ def test_option_img_and_weight(self):
+
+ img_file = mock_in_memory_image('image.jpg')
+ data = {'id': "1", 'img': img_file, 'weight': "100"}
+ option = Option(data)
+ self.assertEqual(img_file, option.img)
+ self.assertEqual('%s.jpg' % option.id, option.img_name)
+ self.assertEqual(100, option.weight)
+
+ def test_option_validation_weight_required(self):
+
+ data = {'id': '1'}
+ option = Option(data)
+
+ self.assertRaises(Option.ValidationError, option.validate)
+ msg = u"opcion %s: ponderación requerida." % option.id
+ self.assertTrue(msg in option.errors)
+
+ def test_image_option_get_absolute_path(self):
+
+ img_file = mock_in_memory_image(size=(250, 250))
+
+ data = {'id': '1', 'img': img_file}
+ option = Option(data, poll=self.poll)
+
+ expected_path = "%s/%s/%s" % (
+ settings.IMAGE_OPTIONS_ROOT, str(option.poll.id), option.img_name
+ )
+ self.assertEqual(expected_path, option.get_absolute_path())
+
+ def test_image_option_validation_invalid_image_file(self):
+ invalid_img_file = mock_text_file()
+
+ data = {'id': '1', 'img': invalid_img_file}
+ option = Option(data)
+
+ self.assertRaises(Option.ValidationError, option.validate)
+ self.assertIsNone(option.img)
+ self.assertIsNone(option.img_name)
+
+ def test_image_option_validation_invalid_size(self):
+
+ invalid_img_file = mock_in_memory_image(size=(300, 200))
+
+ data = {'id': '1', 'img': invalid_img_file}
+ option = Option(data)
+
+ self.assertRaises(Option.ValidationError, option.validate)
+ msg = u"%s: Se necesita una imagen menor a 250x250." % option.id
+ self.assertTrue(msg in option.errors)
+ self.assertIsNone(option.img)
+ self.assertIsNone(option.img_name)
+
+ invalid_img_file = mock_in_memory_image(size=(200, 300))
+
+ data = {'id': '1', 'img': invalid_img_file}
+ option = Option(data)
+
+ self.assertRaises(Option.ValidationError, option.validate)
+ msg = u"%s: Se necesita una imagen menor a 250x250." % option.id
+ self.assertTrue(msg in option.errors)
+ self.assertIsNone(option.img)
+ self.assertIsNone(option.img_name)
+
+ img_file = mock_in_memory_image(size=(250, 250))
+
+ data = {'id': '1', 'img': img_file}
+ option = Option(data)
+
+ self.assertTrue(len(option.errors) == 0)
+
+ def test_to_python(self):
+
+ img_option_expected = {
+ "1": {
+ "img_name": "1.jpg",
+ "weight": 100
+ }
+ }
+
+ option = Option()
+ option.id = "1"
+ option.img_name = "1.jpg"
+ option.weight = 100
+
+ self.assertEqual(img_option_expected, option.to_python())
+
+ basic_option_expected = {
+ "1": {
+ "text": "some text",
+ "weight": 100
+ }
+ }
+
+ option = Option()
+ option.id = "1"
+ option.text = "some text"
+ option.weight = 100
+
+ self.assertEqual(basic_option_expected, option.to_python())
+
+ default_option_expected = {
+ "1": {
+ "text": "some text",
+ }
+ }
+
+ option = Option()
+ option.id = "1"
+ option.text = "some text"
+
+ self.assertEqual(default_option_expected, option.to_python())
diff --git a/webapp/polls/tests/poll_tests.py b/webapp/polls/tests/poll_tests.py
new file mode 100644
index 0000000..2bf04ad
--- /dev/null
+++ b/webapp/polls/tests/poll_tests.py
@@ -0,0 +1,136 @@
+# -*- encoding: utf-8 -*-
+from bson import ObjectId
+
+from polls.models import Poll
+from polls.forms import PollAddForm
+
+from utils.test import MongoTestCase
+
+
+class PollTests(MongoTestCase):
+
+ def test_poll_init(self):
+ name = 'nombre de encuesta'
+ data = {'name': name}
+
+ poll = Poll(data=data)
+ self.assertIsNone(poll.id)
+ self.assertEqual(name, poll.name)
+
+ id = '513a0634421aa932884daa5c'
+ data = {'id': id, 'name': name}
+
+ poll = Poll(data=data)
+ self.assertEqual(ObjectId(id), poll.id)
+ self.assertEqual(name, poll.name)
+
+ def test_validate(self):
+ data = {}
+ poll = Poll(data=data)
+
+ self.assertRaises(Poll.ValidationError, poll.validate)
+
+ def test_save(self):
+
+ name = 'nombre de encuesta'
+ data = {'name': name}
+
+ poll = Poll(data=data)
+ poll.save()
+
+ self.assertEqual(1, self.db.polls.count())
+
+ def test_unique_name(self):
+
+ name = "unique name"
+ data = {'name': name}
+
+ poll = Poll(data=data)
+ poll.save()
+
+ poll = Poll(data=data)
+
+ self.assertRaisesRegexp(
+ Poll.ValidationError,
+ "Poll name '%s' already in use." % poll.name,
+ poll.validate
+ )
+
+ data = {'name': "name"}
+ poll = Poll(data=data)
+
+ fail = True
+ try:
+ poll.save()
+ except Poll.ValidationError:
+ fail = False
+
+ self.assertTrue(fail)
+
+ def test_get(self):
+
+ self.assertIsNone(Poll.get(id=None))
+
+ name = 'nombre de encuesta'
+ data = {'name': name}
+
+ poll = Poll(data=data)
+ poll_id = poll.save()
+
+ poll = Poll.get(id=poll_id)
+
+ self.assertIsNotNone(poll)
+ self.assertIsNotNone(poll.id)
+ self.assertIsInstance(poll_id, ObjectId)
+ self.assertEqual(name, poll.name)
+ self.assertEqual(Poll.OPEN, poll.status)
+
+ def test_status(self):
+
+ name = 'nombre de encuesta'
+ data = {'name': name}
+
+ poll = Poll(data=data)
+
+ self.assertEqual(Poll.OPEN, poll.status)
+
+ poll_id = poll.save()
+
+ self.assertEqual(Poll.OPEN, Poll.get(poll_id).status)
+
+ def test_is_open(self):
+
+ name = 'nombre de encuesta'
+ data = {'name': name}
+
+ poll = Poll(data=data)
+
+ self.assertTrue(poll.is_open())
+
+ poll.status = Poll.CLOSED
+
+ self.assertFalse(poll.is_open())
+
+
+class PollFormTests(MongoTestCase):
+
+ def test_save(self):
+ self.assertEqual(0, self.db.polls.count())
+
+ name = 'nombre de encuesta'
+ data = {'name': name, 'status': Poll.OPEN}
+
+ form = PollAddForm(data=data)
+
+ self.assertTrue(form.is_valid())
+
+ poll = form.save()
+
+ self.assertIsNotNone(poll)
+ self.assertIsInstance(poll, Poll)
+ self.assertEqual(1, self.db.polls.count())
+
+ def test_no_valid_data(self):
+ form = PollAddForm()
+
+ self.assertFalse(form.is_valid())
diff --git a/webapp/polls/tests/structure_tests.py b/webapp/polls/tests/structure_tests.py
new file mode 100644
index 0000000..0c3ef4d
--- /dev/null
+++ b/webapp/polls/tests/structure_tests.py
@@ -0,0 +1,219 @@
+# -*- encoding: utf-8 -*-
+from polls.models import Poll, Group, Field, Structure
+
+from utils.test import MongoTestCase
+
+
+class StructureTests(MongoTestCase):
+
+ def setUp(self):
+ poll = Poll(data={'name': 'name'})
+ poll_id = poll.save()
+
+ self.poll = Poll.get(id=poll_id)
+
+ self.data = {
+ 'poll_id': 'POLL_ID',
+ 'groups': {
+ '0': {
+ 'name': 'group_0',
+ 'fields': {
+ '0': {
+ 'widget_type': Field.TextInput,
+ 'name': 'field_0_0'
+ }
+ }
+ }
+ }
+ }
+
+ def test_structure(self):
+ data = {
+ 'groups': {
+ '0': {
+ 'name': 'group_0',
+ 'fields': {
+ '0': {
+ 'widget_type': Field.TextInput,
+ 'name': 'field_0_0'
+ },
+ '1': {
+ 'widget_type': Field.RadioButton,
+ 'name': 'field_0_1'
+ }
+ },
+ },
+ '1': {
+ 'name': 'group_1',
+ 'fields': {
+ '0': {
+ 'widget_type': Field.MultipleCheckBox,
+ 'name': 'field_1_0'
+ },
+ '1': {
+ 'widget_type': Field.DropDownList,
+ 'name': 'field_1_1'
+ }
+ },
+ }
+ }
+ }
+
+ structure = Structure(data=data, poll=self.poll)
+ self.assertEqual(self.poll, structure.poll)
+
+ group_0 = structure.groups[0]
+ self.assertEqual(self.poll, group_0.poll)
+ self.assertEqual(0, group_0.order)
+ self.assertEqual('group_0', group_0.name)
+ self.assertEqual(2, len(group_0.fields))
+
+ group_1 = structure.groups[1]
+ self.assertEqual(self.poll, group_1.poll)
+ self.assertEqual(1, group_1.order)
+ self.assertEqual('group_1', group_1.name)
+ self.assertEqual(2, len(group_1.fields))
+
+ field_0_0 = group_0.fields[0]
+ self.assertEqual(self.poll, field_0_0.poll)
+ self.assertEqual(0, field_0_0.order)
+ self.assertEqual('field_0_0', field_0_0.name)
+ self.assertEqual('TextInput', field_0_0.widget_type)
+
+ field_0_1 = group_0.fields[1]
+ self.assertEqual(self.poll, field_0_1.poll)
+ self.assertEqual(1, field_0_1.order)
+ self.assertEqual('field_0_1', field_0_1.name)
+ self.assertEqual('RadioButton', field_0_1.widget_type)
+
+ field_1_0 = group_1.fields[0]
+ self.assertEqual(self.poll, field_1_0.poll)
+ self.assertEqual(0, field_1_0.order)
+ self.assertEqual('field_1_0', field_1_0.name)
+ self.assertEqual('MultipleCheckBox', field_1_0.widget_type)
+
+ field_1_1 = group_1.fields[1]
+ self.assertEqual(self.poll, field_1_1.poll)
+ self.assertEqual(1, field_1_1.order)
+ self.assertEqual('field_1_1', field_1_1.name)
+ self.assertEqual('DropDownList', field_1_1.widget_type)
+
+ def test_is_valid(self):
+ data = {
+ 'groups': {
+ '0': {
+ 'name': 'group_0',
+ 'fields': {
+ '0': { # has no options for a widget_type that needs
+ 'widget_type': 'RadioButton',
+ 'name': 'field_0_0'
+ },
+ }
+ },
+ '1': {
+ 'name': '', # has no name
+ 'fields': {} # has no fields
+ }
+ }
+ }
+
+ structure = Structure(data=data, poll=self.poll)
+
+ self.assertFalse(structure.is_valid())
+
+ field_0_0 = structure.groups[0].fields[0]
+
+ self.assertEqual(1, len(field_0_0.errors))
+
+ group_1 = structure.groups[1]
+
+ self.assertEqual(2, len(group_1.errors))
+
+ def test_invalid_structure(self):
+ data = {}
+
+ structure = Structure(data=data, poll=self.poll)
+
+ self.assertFalse(structure.is_valid())
+
+ self.assertEqual(1, len(structure.errors))
+
+ def test_save(self):
+
+ structure = Structure(data=self.data)
+
+ self.assertRaises(structure.ValidationError, structure.save)
+
+ structure = Structure(data=self.data, poll=self.poll)
+ structure.save()
+
+ self.assertEqual(1, self.db.structures.count())
+
+ def test_get(self):
+ structure = Structure(data=self.data, poll=self.poll)
+ structure_id = structure.save()
+
+ structure = Structure.get(id=structure_id)
+
+ self.assertEqual(self.poll.id, structure.poll.id)
+
+ def test_to_python(self):
+
+ expected = {
+ 'groups': {
+ '0': {
+ 'name': "group name",
+ 'fields': {
+ '0': {
+ 'name': "field_0_0",
+ 'widget_type': Field.TextInput,
+ 'options': {
+ '131212': {
+ 'text': "text"
+ }
+ }
+ }
+ }
+ },
+ '1': {
+ 'name': "group name",
+ 'fields': {
+ '0': {
+ 'name': "field_1_0",
+ 'widget_type': Field.TextInput,
+ 'options': {
+ '131212': {
+ 'text': "text"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ structure = Structure(poll=self.poll)
+
+ field = Field({
+ 'name': "field_0_0",
+ 'widget_type': Field.TextInput,
+ 'order': 0
+ })
+ field.add_options({'131212': {'text': "text"}})
+
+ group = Group({'name': "group name", 'order': 0})
+ group.add_field(field, field.order)
+ structure.add_group(group, group.order)
+
+ field = Field({
+ 'name': "field_1_0",
+ 'widget_type': Field.TextInput,
+ 'order': 0
+ })
+ field.add_options({'131212': {'text': "text"}})
+
+ group = Group({'name': "group name", 'order': 1})
+ group.add_field(field, field.order)
+ structure.add_group(group, group.order)
+
+ self.assertEqual(expected, structure.to_python())
diff --git a/webapp/polls/urls.py b/webapp/polls/urls.py
index b906abe..aff1ae0 100644
--- a/webapp/polls/urls.py
+++ b/webapp/polls/urls.py
@@ -13,8 +13,6 @@ urlpatterns = patterns('',
# Poll structure
url(r'^structure/(?P<poll_id>[0-9A-Fa-f]{24})/$',
StructureFormView.as_view(), name="structure.builder"),
- url(r'^success/(?P<poll_id>[0-9A-Fa-f]{24})/$',
- SucessView.as_view(), name="success"),
url(r'^download/(?P<poll_id>[0-9A-Fa-f]{24})/$',
'polls.views.download_poll', name="download"),
diff --git a/webapp/polls/views.py b/webapp/polls/views.py
index 4f40090..5e14e0c 100644
--- a/webapp/polls/views.py
+++ b/webapp/polls/views.py
@@ -18,7 +18,6 @@ from django.shortcuts import render_to_response
from django.conf import settings
from utils.forms import BadFormValidation
-from utils.mongo_connection import get_db
from utils.data_structure import dict_merge
from polls.models import WIDGET_TYPES, Structure, Poll
@@ -26,7 +25,7 @@ from polls.forms import PollAddForm
__all__ = [
- 'StructureFormView', 'SucessView', 'PollFormView', 'PollListView',
+ 'StructureFormView', 'PollFormView', 'PollListView',
]
@@ -47,9 +46,8 @@ def clean_data(value):
if not isinstance(value, InMemoryUploadedFile):
value = value.strip(' ')
- # TODO: Organizar esto con Flavio.
- #if value == '':
- # value = None
+ if value == '':
+ value = None
if value == 'True' or value in [u'on']:
value = True
if value == 'False':
@@ -132,13 +130,7 @@ class StructureFormView(TemplateView):
def get(self, request, *args, **kwargs):
context = self.get_context_data()
- # TODO: Metodo para obtener la estructura a partir de una encuesta
- structure_data = get_db().structures.find_one(
- {'poll.$id': self.poll.id})
- structure_data = structure_data if structure_data else {}
-
- context.update(
- {'structure': Structure(data=structure_data, poll=self.poll)})
+ context.update({'structure': self.poll.structure})
return self.render_to_response(context)
@@ -195,7 +187,7 @@ class StructureFormView(TemplateView):
return HttpResponseRedirect(
reverse(
- 'polls:success',
+ 'polls:structure.builder',
kwargs={"poll_id": str(self.poll.id)}
)
)
@@ -207,16 +199,6 @@ class StructureFormView(TemplateView):
return self.render_to_response(context)
-class SucessView(TemplateView):
-
- template_name = "poll-success.html"
-
- def post(self, request, *args, **kwargs):
- poll_id = kwargs.get('poll_id', None)
-
- return download_poll(request, poll_id)
-
-
def download_poll(request, poll_id=None):
# Wrong id => 404
@@ -224,6 +206,8 @@ def download_poll(request, poll_id=None):
poll = Poll.get(id=_id)
if not _id or not poll:
raise Http404()
+ elif poll and poll.is_open():
+ raise Http404()
file_name = datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
diff --git a/webapp/utils/test.py b/webapp/utils/test.py
index d9cbfde..98c4209 100644
--- a/webapp/utils/test.py
+++ b/webapp/utils/test.py
@@ -37,9 +37,8 @@ def mock_text_file():
return text_file
-def mock_image_file(format="jpeg"):
+def mock_image_file(format="jpeg", size=(200, 200)):
io = StringIO.StringIO()
- size = (200, 200)
color = (255, 0, 0, 0)
image = Image.new("RGBA", size, color)
image.save(io, format=format.upper())
@@ -47,8 +46,8 @@ def mock_image_file(format="jpeg"):
return io
-def mock_in_memory_image(name='foo.jpg', format="jpeg"):
- io = mock_image_file(format)
+def mock_in_memory_image(name='foo.jpg', format="jpeg", size=(200, 200)):
+ io = mock_image_file(format, size)
content_type = "Image/%s" % format.lower()
image_in_memory = InMemoryUploadedFile(
io, None, name, content_type, io.len, None
diff --git a/webapp/webapp/static/js/dynamic_structure.js b/webapp/webapp/static/js/dynamic_structure.js
index 118a6d4..69f2223 100644
--- a/webapp/webapp/static/js/dynamic_structure.js
+++ b/webapp/webapp/static/js/dynamic_structure.js
@@ -36,12 +36,17 @@ var factoryImageOptionUpload = function(id, value, container, group_order, field
"group_order": group_order,
"field_order": field_order
})
- );
+ ),
+ row_fluid = container.find('.row-fluid');
+
+ if (row_fluid.size() == 0)
+ row_fluid = $('<div class="row-fluid"></div>');
// Draggable option ID to droppable dependence field
option.find(".draggable").draggable({'helper': 'clone'});
- container.append(option);
+ row_fluid.append(option);
+ container.append(row_fluid);
};
var get_opt_thumb = function(poll_id, img_name){
@@ -69,14 +74,21 @@ var factoryImageOptionThumbnail = function(id, value, container, group_order, fi
"group_order": group_order,
"field_order": field_order
})
- );
+ ),
+ row_fluid = container.find('.row-fluid');
+
+ if (row_fluid.size() == 0)
+ row_fluid = $('<div class="row-fluid"></div>');
// Get remove option button and bind with remove option event
option.find('.WFieldImageOptions_remove_button').on('click', function(event) {
event.preventDefault();
- var container_row_fuild = option.parent(".row-fluid");
- option.remove();
+ if(confirm('La opción ' + id + ' va a ser eliminada.')) {
+ var container_row_fuild = option.parent(".row-fluid");
+
+ option.remove();
+ }
});
// Append new img option
@@ -85,13 +97,18 @@ var factoryImageOptionThumbnail = function(id, value, container, group_order, fi
img = '<img src="' + img_src + '" />';
$(option.find(".img_container")).append(thumb);
- $(option.find('img')).popover(
- { title: "ID: " + id, content: img, html: true, trigger: "hover" });
+ $(option.find('img')).popover({
+ title: "<b>ID</b>: " + id + ", <b>Peso</b>: " + value['weight'],
+ content: img,
+ html: true,
+ trigger: "hover"
+ });
// Draggable option ID to droppable dependence field
option.find(".draggable").draggable({'helper': 'clone'});
- container.append(option);
+ row_fluid.append(option);
+ container.append(row_fluid);
};
@@ -110,13 +127,16 @@ var factoryOption = function(id, value, container, group_order, field_order) {
// Get remove option button and bind with remove option event
option.find('.WFieldOptions_remove').on('click', function(event) {
event.preventDefault();
- var container_row_fuild = option.parent(".row-fluid");
- option.remove();
+ if(confirm('La opción ' + id + ' va a ser eliminada.')) {
+ var container_row_fuild = option.parent(".row-fluid");
+
+ option.remove();
- /* Check for remove row of options */
- if (container_row_fuild.contents().length == 0) {
- container_row_fuild.remove();
+ /* Check for remove row of options */
+ if (container_row_fuild.contents().length == 0) {
+ container_row_fuild.remove();
+ }
}
});
@@ -155,22 +175,25 @@ var bindFieldRemoveButton = function(remove_button) {
remove_button.on('click', function(event){
event.preventDefault();
- var field_widget = $('.field').has(remove_button),
- following_siblings = field_widget.nextAll('.field'),
- pattern = /(.fields.)(\d+)/;
+ if(confirm('¿Esta seguro que quiere eliminar esta pregunta?')) {
- // Update order of groups, very important!
- var all_inputs = following_siblings.find(":input:not(:button)");
- _updateFieldInputs(all_inputs, pattern);
+ var field_widget = $('.field').has(remove_button),
+ following_siblings = field_widget.nextAll('.field'),
+ pattern = /(.fields.)(\d+)/;
- field_widget.remove();
+ // Update order of groups, very important!
+ var all_inputs = following_siblings.find(":input:not(:button)");
+ _updateFieldInputs(all_inputs, pattern);
- // Unbind add_option buttons and bind again
- var add_option_buttons = field_widget.find('.WFieldOptions_add_button');
- $.each(add_option_buttons, function(i, add_option_button){
- $(add_option_button).unbind('click');
- bindFieldAddOptionButton(add_option_button);
- });
+ field_widget.remove();
+
+ // Unbind add_option buttons and bind again
+ var add_option_buttons = field_widget.find('.WFieldOptions_add_button');
+ $.each(add_option_buttons, function(i, add_option_button){
+ $(add_option_button).unbind('click');
+ bindFieldAddOptionButton(add_option_button);
+ });
+ }
});
};
@@ -285,7 +308,6 @@ var factoryField = function(order, value) {
bindFieldWidgetTypeSelectBox(widget_types_select_box);
// Adding add_option button if is needed
- // TODO: Mergear este proceso con bindFieldWidgetTypeSelectBox.
buttons_container = field_widget.find('.WFieldAddOptionButton_container');
if (widget_type && $.inArray(widget_type, WITH_OPTIONS) != -1) {
var add_option_button = $(Mustache.render(TEMPLATES['field_add_option_button'], {}));
@@ -372,23 +394,25 @@ var bindGroupRemoveButton = function(remove_button) {
remove_button.on('click', function(event){
event.preventDefault();
- var group_widget = $('.group').has(remove_button),
+ if(confirm('¿Esta seguro que quiere eliminar este grupo?')){
+ var group_widget = $('.group').has(remove_button),
following_siblings = group_widget.nextAll('.group'),
pattern = /(groups.)(\d+)/;
- // Update order of groups, very important!
- var all_inputs = following_siblings.find(":input:not(:button)");
- _updateGroupInputs(all_inputs, pattern);
+ // Update order of groups, very important!
+ var all_inputs = following_siblings.find(":input:not(:button)");
+ _updateGroupInputs(all_inputs, pattern);
- // Remove group
- group_widget.remove();
+ // Remove group
+ group_widget.remove();
- // Unbind add_field buttons and bind again
- var add_field_buttons = $('.WGroup_add_field');
- $.each(add_field_buttons, function(i, add_field_button){
- $(add_field_button).unbind('click');
- bindGroupAddFieldButton(add_field_button);
- });
+ // Unbind add_field buttons and bind again
+ var add_field_buttons = $('.WGroup_add_field');
+ $.each(add_field_buttons, function(i, add_field_button){
+ $(add_field_button).unbind('click');
+ bindGroupAddFieldButton(add_field_button);
+ });
+ }
});
};
@@ -450,5 +474,6 @@ var factoryGroup = function(order, value) {
bindGroupAddFieldButton(add_field_button);
// Show the group widget
+ group.prepend("<hr />");
container.append(group);
}; \ No newline at end of file