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-20 17:26:05 (GMT)
committer Rogelio Mita <rogeliomita@activitycentral.com>2013-03-25 21:51:47 (GMT)
commitd92a0318216818fd65286ccaefdf581327221c83 (patch)
treeb6eac57c6c7aad873694cd1971bdce54070f4d29
parent23ba438d0831e488fb718766fcbff680eb4f6fac (diff)
Adding image option widget for options that need image upload inputs
-rw-r--r--webapp/polls/models.py14
-rw-r--r--webapp/polls/templates/mustache/option_image.html19
-rw-r--r--webapp/polls/templates/poll-structure-form.html4
-rw-r--r--webapp/polls/templates/tags/structure.html2
-rw-r--r--webapp/polls/templatetags/poll_tags.py6
-rwxr-xr-xwebapp/webapp/static/css/bootstrap-fileupload.css132
-rwxr-xr-xwebapp/webapp/static/js/bootstrap-fileupload.js169
-rw-r--r--webapp/webapp/static/js/dynamic_structure.js28
8 files changed, 370 insertions, 4 deletions
diff --git a/webapp/polls/models.py b/webapp/polls/models.py
index 6d049c2..609b38e 100644
--- a/webapp/polls/models.py
+++ b/webapp/polls/models.py
@@ -13,9 +13,23 @@ WIDGET_TYPES = (
('MultipleCheckBox', 'Respuesta con checks (multiple selección)'),
('RadioButton', 'Respuesta con radios (Solo una selección)'),
('DropDownList', 'Respuesta con lista de opciones'),
+ ('ImageCheckBox', 'Respuesta con imagenes tipo checks'),
+ ('ImageRadioButton', 'Respuesta con imagenes tipo radios'),
)
+WITH_OPTIONS = [
+ "MultipleCheckBox",
+ "DropDownList",
+ "RadioButton",
+ "ImageCheckBox",
+ "ImageRadioButton",
+]
+
+
+WITH_IMAGES = ["ImageCheckBox", "ImageRadioButton"]
+
+
class AbstracErrorObject(object):
ValidationError = ValidationError
diff --git a/webapp/polls/templates/mustache/option_image.html b/webapp/polls/templates/mustache/option_image.html
new file mode 100644
index 0000000..b8cb19b
--- /dev/null
+++ b/webapp/polls/templates/mustache/option_image.html
@@ -0,0 +1,19 @@
+<!-- Template: Field -->
+<script type="text/x-mustache-template" name="field_option_image">
+
+ <div class="fileupload fileupload-new" data-provides="fileupload">
+ <div class="fileupload-new thumbnail" style="width: 200px; height: 150px;">
+ <img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&text=no+image" />
+ </div>
+ <div class="fileupload-preview fileupload-exists thumbnail" style="max-width: 200px; max-height: 150px; line-height: 20px;"></div>
+ <div>
+ <span class="btn btn-file">
+ <span class="fileupload-new">Elegir</span>
+ <span class="fileupload-exists">Cambiar</span>
+ <input type="file" name="groups.[[ group_order ]].fields.[[ field_order ]].options.[[ id ]].img" />
+ </span>
+ <a href="#" class="btn fileupload-exists" data-dismiss="fileupload">Quitar</a>
+ </div>
+ </div>
+
+</script> \ No newline at end of file
diff --git a/webapp/polls/templates/poll-structure-form.html b/webapp/polls/templates/poll-structure-form.html
index 149e58d..9303558 100644
--- a/webapp/polls/templates/poll-structure-form.html
+++ b/webapp/polls/templates/poll-structure-form.html
@@ -9,9 +9,13 @@
padding-top: 110px;
}
</style>
+
+ <link href="{{ STATIC_URL }}css/bootstrap-fileupload.css" rel="stylesheet" />
{% endblock %}
{% 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>
<center><h2>{{ poll.name|capfirst }}</h2></center>
diff --git a/webapp/polls/templates/tags/structure.html b/webapp/polls/templates/tags/structure.html
index 327d1f5..427cd81 100644
--- a/webapp/polls/templates/tags/structure.html
+++ b/webapp/polls/templates/tags/structure.html
@@ -17,6 +17,7 @@
{% include "mustache/option_default.html" %}
+{% include "mustache/option_image.html" %}
<!-- Global variables for dynamic_structure.js -->
<script type="text/javascript">
@@ -24,6 +25,7 @@
var groups = {{ groups }},
WIDGET_TYPES = {{ WIDGET_TYPES }},
WITH_OPTIONS = {{ WITH_OPTIONS }},
+ WITH_IMAGES = {{ WITH_IMAGES }},
OFFSET_OPTION_ID = {{ OFFSET_OPTION_ID }};
</script>
diff --git a/webapp/polls/templatetags/poll_tags.py b/webapp/polls/templatetags/poll_tags.py
index 240b95d..bde1962 100644
--- a/webapp/polls/templatetags/poll_tags.py
+++ b/webapp/polls/templatetags/poll_tags.py
@@ -4,7 +4,7 @@ from django import template
from django.utils.safestring import SafeUnicode
from django.template.loader import render_to_string
-from polls.models import WIDGET_TYPES, Field
+from polls.models import WIDGET_TYPES, WITH_OPTIONS, WITH_IMAGES, Field
register = template.Library()
@@ -22,8 +22,8 @@ def render_structure(context, structure):
{
"STATIC_URL": context['STATIC_URL'],
"WIDGET_TYPES": widget_types,
- "WITH_OPTIONS": SafeUnicode(json.dumps(
- ["MultipleCheckBox", "DropDownList", "RadioButton"])),
+ "WITH_OPTIONS": SafeUnicode(json.dumps(WITH_OPTIONS)),
+ "WITH_IMAGES": SafeUnicode(json.dumps(WITH_IMAGES)),
"OFFSET_OPTION_ID": SafeUnicode(json.dumps(Field.get_offset_id())),
"groups": groups
}
diff --git a/webapp/webapp/static/css/bootstrap-fileupload.css b/webapp/webapp/static/css/bootstrap-fileupload.css
new file mode 100755
index 0000000..eec90a7
--- /dev/null
+++ b/webapp/webapp/static/css/bootstrap-fileupload.css
@@ -0,0 +1,132 @@
+/*!
+ * Bootstrap v2.3.1-j6
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat, extended by @ArnoldDaniels.
+ */
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.clearfix:after {
+ clear: both;
+}
+.hide-text {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.btn-file {
+ overflow: hidden;
+ position: relative;
+ vertical-align: middle;
+}
+.btn-file > input {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 0;
+ opacity: 0;
+ filter: alpha(opacity=0);
+ transform: translate(-300px, 0) scale(4);
+ font-size: 23px;
+ direction: ltr;
+ cursor: pointer;
+}
+.fileupload {
+ margin-bottom: 9px;
+}
+.fileupload .uneditable-input {
+ display: inline-block;
+ margin-bottom: 0px;
+ vertical-align: middle;
+ cursor: text;
+}
+.fileupload .thumbnail {
+ overflow: hidden;
+ display: inline-block;
+ margin-bottom: 5px;
+ vertical-align: middle;
+ text-align: center;
+}
+.fileupload .thumbnail > img {
+ display: inline-block;
+ vertical-align: middle;
+ max-height: 100%;
+}
+.fileupload .btn {
+ vertical-align: middle;
+}
+.fileupload-exists .fileupload-new,
+.fileupload-new .fileupload-exists {
+ display: none;
+}
+.fileupload-inline .fileupload-controls {
+ display: inline;
+}
+.fileupload-new .input-append .btn-file {
+ -webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+.thumbnail-borderless .thumbnail {
+ border: none;
+ padding: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+.fileupload-new.thumbnail-borderless .thumbnail {
+ border: 1px solid #ddd;
+}
+.control-group.warning .fileupload .uneditable-input {
+ color: #a47e3c;
+ border-color: #a47e3c;
+}
+.control-group.warning .fileupload .fileupload-preview {
+ color: #a47e3c;
+}
+.control-group.warning .fileupload .thumbnail {
+ border-color: #a47e3c;
+}
+.control-group.error .fileupload .uneditable-input {
+ color: #b94a48;
+ border-color: #b94a48;
+}
+.control-group.error .fileupload .fileupload-preview {
+ color: #b94a48;
+}
+.control-group.error .fileupload .thumbnail {
+ border-color: #b94a48;
+}
+.control-group.success .fileupload .uneditable-input {
+ color: #468847;
+ border-color: #468847;
+}
+.control-group.success .fileupload .fileupload-preview {
+ color: #468847;
+}
+.control-group.success .fileupload .thumbnail {
+ border-color: #468847;
+}
diff --git a/webapp/webapp/static/js/bootstrap-fileupload.js b/webapp/webapp/static/js/bootstrap-fileupload.js
new file mode 100755
index 0000000..97a6da5
--- /dev/null
+++ b/webapp/webapp/static/js/bootstrap-fileupload.js
@@ -0,0 +1,169 @@
+/* ===========================================================
+ * bootstrap-fileupload.js j2
+ * http://jasny.github.com/bootstrap/javascript.html#fileupload
+ * ===========================================================
+ * Copyright 2012 Jasny BV, Netherlands.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+!function ($) {
+
+ "use strict"; // jshint ;_
+
+ /* FILEUPLOAD PUBLIC CLASS DEFINITION
+ * ================================= */
+
+ var Fileupload = function (element, options) {
+ this.$element = $(element)
+ this.type = this.$element.data('uploadtype') || (this.$element.find('.thumbnail').length > 0 ? "image" : "file")
+
+ this.$input = this.$element.find(':file')
+ if (this.$input.length === 0) return
+
+ this.name = this.$input.attr('name') || options.name
+
+ this.$hidden = this.$element.find('input[type=hidden][name="'+this.name+'"]')
+ if (this.$hidden.length === 0) {
+ this.$hidden = $('<input type="hidden" />')
+ this.$element.prepend(this.$hidden)
+ }
+
+ this.$preview = this.$element.find('.fileupload-preview')
+ var height = this.$preview.css('height')
+ if (this.$preview.css('display') != 'inline' && height != '0px' && height != 'none') this.$preview.css('line-height', height)
+
+ this.original = {
+ 'exists': this.$element.hasClass('fileupload-exists'),
+ 'preview': this.$preview.html(),
+ 'hiddenVal': this.$hidden.val()
+ }
+
+ this.$remove = this.$element.find('[data-dismiss="fileupload"]')
+
+ this.$element.find('[data-trigger="fileupload"]').on('click.fileupload', $.proxy(this.trigger, this))
+
+ this.listen()
+ }
+
+ Fileupload.prototype = {
+
+ listen: function() {
+ this.$input.on('change.fileupload', $.proxy(this.change, this))
+ $(this.$input[0].form).on('reset.fileupload', $.proxy(this.reset, this))
+ if (this.$remove) this.$remove.on('click.fileupload', $.proxy(this.clear, this))
+ },
+
+ change: function(e, invoked) {
+ if (invoked === 'clear') return
+
+ var file = e.target.files !== undefined ? e.target.files[0] : (e.target.value ? { name: e.target.value.replace(/^.+\\/, '') } : null)
+
+ if (!file) {
+ this.clear()
+ return
+ }
+
+ this.$hidden.val('')
+ this.$hidden.attr('name', '')
+ this.$input.attr('name', this.name)
+
+ if (this.type === "image" && this.$preview.length > 0 && (typeof file.type !== "undefined" ? file.type.match('image.*') : file.name.match(/\.(gif|png|jpe?g)$/i)) && typeof FileReader !== "undefined") {
+ var reader = new FileReader()
+ var preview = this.$preview
+ var element = this.$element
+
+ reader.onload = function(e) {
+ preview.html('<img src="' + e.target.result + '" ' + (preview.css('max-height') != 'none' ? 'style="max-height: ' + preview.css('max-height') + ';"' : '') + ' />')
+ element.addClass('fileupload-exists').removeClass('fileupload-new')
+ }
+
+ reader.readAsDataURL(file)
+ } else {
+ this.$preview.text(file.name)
+ this.$element.addClass('fileupload-exists').removeClass('fileupload-new')
+ }
+ },
+
+ clear: function(e) {
+ this.$hidden.val('')
+ this.$hidden.attr('name', this.name)
+ this.$input.attr('name', '')
+
+ //ie8+ doesn't support changing the value of input with type=file so clone instead
+ if (navigator.userAgent.match(/msie/i)){
+ var inputClone = this.$input.clone(true);
+ this.$input.after(inputClone);
+ this.$input.remove();
+ this.$input = inputClone;
+ }else{
+ this.$input.val('')
+ }
+
+ this.$preview.html('')
+ this.$element.addClass('fileupload-new').removeClass('fileupload-exists')
+
+ if (e) {
+ this.$input.trigger('change', [ 'clear' ])
+ e.preventDefault()
+ }
+ },
+
+ reset: function(e) {
+ this.clear()
+
+ this.$hidden.val(this.original.hiddenVal)
+ this.$preview.html(this.original.preview)
+
+ if (this.original.exists) this.$element.addClass('fileupload-exists').removeClass('fileupload-new')
+ else this.$element.addClass('fileupload-new').removeClass('fileupload-exists')
+ },
+
+ trigger: function(e) {
+ this.$input.trigger('click')
+ e.preventDefault()
+ }
+ }
+
+
+ /* FILEUPLOAD PLUGIN DEFINITION
+ * =========================== */
+
+ $.fn.fileupload = function (options) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('fileupload')
+ if (!data) $this.data('fileupload', (data = new Fileupload(this, options)))
+ if (typeof options == 'string') data[options]()
+ })
+ }
+
+ $.fn.fileupload.Constructor = Fileupload
+
+
+ /* FILEUPLOAD DATA-API
+ * ================== */
+
+ $(document).on('click.fileupload.data-api', '[data-provides="fileupload"]', function (e) {
+ var $this = $(this)
+ if ($this.data('fileupload')) return
+ $this.fileupload($this.data())
+
+ var $target = $(e.target).closest('[data-dismiss="fileupload"],[data-trigger="fileupload"]');
+ if ($target.length > 0) {
+ $target.trigger('click.fileupload')
+ e.preventDefault()
+ }
+ })
+
+}(window.jQuery);
diff --git a/webapp/webapp/static/js/dynamic_structure.js b/webapp/webapp/static/js/dynamic_structure.js
index 24edebb..9bc87af 100644
--- a/webapp/webapp/static/js/dynamic_structure.js
+++ b/webapp/webapp/static/js/dynamic_structure.js
@@ -26,6 +26,24 @@ var factoryOptionDefault = function(group_order, field_widget, id, default_value
container.append(row_fluid);
};
+
+var factoryImageOption = function(id, value, container, group_order, field_order) {
+
+ var option = $(
+ Mustache.render(TEMPLATES['field_option_image'], {
+ "id": id,
+ "group_order": group_order,
+ "field_order": field_order
+ })
+ );
+
+ // Append new option
+ row_fluid = $('<div class="row-fluid"></div>');
+ row_fluid.append(option);
+ container.append(row_fluid);
+};
+
+
var factoryOption = function(id, value, container, group_order, field_order) {
var option = $(
@@ -119,7 +137,15 @@ var bindFieldAddOptionButton = function(add_option_button) {
options_container = field_widget.find('.WFieldOptions_container');
OFFSET_OPTION_ID++;
empty_option_widget = {'name': ''};
- factoryOption(OFFSET_OPTION_ID, empty_option_widget, options_container, group_order, field_order );
+
+ // Get current selected widget type for current field
+ var current_widget_type = field_widget.find(".WFieldWidgetType").attr('value');
+
+ if ($.inArray(current_widget_type, WITH_IMAGES) == -1){
+ factoryOption(OFFSET_OPTION_ID, empty_option_widget, options_container, group_order, field_order );
+ } else {
+ factoryImageOption(OFFSET_OPTION_ID, empty_option_widget, options_container, group_order, field_order );
+ }
});
}