Agenda
authorCyril Robert <Cyril Robert cyrilrbt@gmail.com>
Mon, 14 Jun 2010 19:19:10 +0000 (15:19 -0400)
committerCyril Robert <Cyril Robert cyrilrbt@gmail.com>
Mon, 14 Jun 2010 19:19:10 +0000 (15:19 -0400)
72 files changed:
auf_savoirs_en_partage_django/backend_config.py [new file with mode: 0644]
auf_savoirs_en_partage_django/media/css/global.css
auf_savoirs_en_partage_django/media/css/jquery/jquery.timepicker.css [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jquery/jquery.timepicker.js [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/00changelog.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branch [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branchheads.cache [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/dirstate [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/hgrc [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/requires [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00changelog.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00manifest.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_j_s_o_n.php.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_l_i_c_e_n_s_e.txt.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/addressbookschema.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/behaviour.js.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionlarge.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionnormal.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionschema.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electiontiny.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/example.php.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/index.html.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/json.js.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonedit.js.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonwidget.css.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/openschema.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/prototype.html.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-large.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-tiny.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampleschema.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/schemaschema.json.i [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/fncache [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/undo [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/tags.cache [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.branch [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.dirstate [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/JSON.php [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/LICENSE.txt [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/addressbookschema.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/electionlarge.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/electionnormal.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/electionschema.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/electiontiny.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/example.php [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/index.html [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/json.js [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/jsonedit.js [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/jsonwidget.css [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/openschema.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/prototype.html [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/jsonwidget/schemaschema.json [new file with mode: 0644]
auf_savoirs_en_partage_django/media/js/test.html [new file with mode: 0644]
auf_savoirs_en_partage_django/savoirs/__init__.py
auf_savoirs_en_partage_django/savoirs/admin.py
auf_savoirs_en_partage_django/savoirs/forms.py
auf_savoirs_en_partage_django/savoirs/lib/__init__.py [new file with mode: 0644]
auf_savoirs_en_partage_django/savoirs/lib/calendrier.py [new file with mode: 0644]
auf_savoirs_en_partage_django/savoirs/lib/recherche.py [new file with mode: 0644]
auf_savoirs_en_partage_django/savoirs/models.py
auf_savoirs_en_partage_django/savoirs/recherche.py [deleted file]
auf_savoirs_en_partage_django/savoirs/views.py
auf_savoirs_en_partage_django/settings.py
auf_savoirs_en_partage_django/templates/container_base.html
auf_savoirs_en_partage_django/templates/savoirs/evenement.html [new file with mode: 0644]
auf_savoirs_en_partage_django/templates/savoirs/evenement_ajout.html [new file with mode: 0644]
auf_savoirs_en_partage_django/templates/savoirs/evenement_confirmation.html [new file with mode: 0644]
auf_savoirs_en_partage_django/templates/savoirs/evenement_moderation.html [new file with mode: 0644]
auf_savoirs_en_partage_django/templates/savoirs/index.html
auf_savoirs_en_partage_django/templates/savoirs/informations.html
auf_savoirs_en_partage_django/urls.py
buildout.cfg

diff --git a/auf_savoirs_en_partage_django/backend_config.py b/auf_savoirs_en_partage_django/backend_config.py
new file mode 100644 (file)
index 0000000..e69de29
index 56d3e5e..32e1ee4 100644 (file)
@@ -80,13 +80,14 @@ div.boite-recherche p a:hover { color:#97012c; text-decoration:none;}
 
 #contenu img.top, .resultats img.top { height:10px; position:relative; top:-10px; left:0;}
 #contenu img.bottom, .resultats img.bottom{ height:10px; position:relative; bottom:-10px; left:0;}
-#contenu a.liste-complete { font-size: 1.2em; float:right; margin-right:2em; text-decoration:none; font-weight: bold;}
-#contenu a:hover.liste-complete { text-decoration:underline;}
 #contenu .demi-gauche { width:361px; margin-left:12px; background-color:#f5f5f5; float:left;}
 #contenu .demi-gauche img.top { height:9px; position:relative; top:-9px;}
 #contenu .demi-gauche img.bottom { height:9px;  position:relative; bottom:-9px;}
 #contenu .demi-droite { width:358px; margin-top:8px; margin-right:12px;float:right;}
 
+#calendar-links { padding: 0 25px; }
+#calendar-links p { margin: 0px; }
+
 ul.liste-de-l-accueil { padding:0 2.5em 0 0;}
 ul.liste-de-l-accueil li { margin:1em 0; padding-bottom:1.1em;border-bottom:2px solid #d5d5d5;}
 ul.liste-de-l-accueil a:hover { text-decoration:underline;}
@@ -147,3 +148,13 @@ ul.liste-de-l-accueil .le-resume a { display:inline;}
 #edit-form tr { border-top: 1px black solid; }
 #edit-form tr:first-child { border-top: none; }
 
+.form td { vertical-align: top; }
+.form th { font-weight: bold; }
+.form td:first-child { width: 150px; text-align: left; }
+.form table { width: 100%; }
+.form input[type=text], .form textarea, .form select { width: 80%; }
+.form textarea { height: 100px; }
+.form p { margin-bottom: 2px; }
+.form tr:first-child { border-top: none; }
+
+.odd { background: #f0f0f0; }
diff --git a/auf_savoirs_en_partage_django/media/css/jquery/jquery.timepicker.css b/auf_savoirs_en_partage_django/media/css/jquery/jquery.timepicker.css
new file mode 100644 (file)
index 0000000..9804c0c
--- /dev/null
@@ -0,0 +1,115 @@
+@CHARSET "UTF-8";
+
+ /*demo page css*/
+
+
+            .demoHeaders {
+                margin-top: 2em;
+            }
+
+            #dialog_link {
+                padding: .4em 1em .4em 20px;
+                text-decoration: none;
+                position: relative;
+            }
+
+            #dialog_link span.ui-icon {
+                margin: 0 5px 0 0;
+                position: absolute;
+                left: .2em;
+                top: 50%;
+                margin-top: -8px;
+            }
+
+            ul#icons {
+                margin: 0;
+                padding: 0;
+            }
+
+            ul#icons li {
+                margin: 2px;
+                position: relative;
+                padding: 4px 0;
+                cursor: pointer;
+                float: left;
+                list-style: none;
+            }
+
+            ul#icons span.ui-icon {
+                float: left;
+                margin: 0 4px;
+            }
+
+            
+               .selHrs, .selMins {
+                       width:2.5em;
+               }
+               .selHrs {
+                       margin-left:5px;
+               }
+               .dayPeriod {
+                       display:inline-block;
+                       width:20px;
+               }
+               .slider {
+                       height:120px; 
+                       float:left; 
+                       margin:10px
+               }
+               
+               #tpSelectedTime {
+                       margin-bottom:0;
+                       border-bottom:1px solid #aaa;
+                       padding:5px;
+                       color:#000;
+                       background:#fff;
+                       text-transform:none;
+                       
+               }
+               #tpSelectedTime span {
+                       fon-weight:bold;
+               }
+               #datepicker {
+                       
+               }
+               #pickerplug {
+                       overflow:hidden;
+                       position:absolute;
+                       top:200px;
+                       left:300px; 
+                                       padding:0;
+                                       margin:0;
+                       z-index:500;    
+               }
+               #pickerplug li {
+                       display:block;
+                       float:left;
+               }
+               #timepicker {
+                       border:1px solid #aaa;                          
+                       background:#fff;
+               }
+               #timepicker ul {
+                       overflow:hidden;
+                       padding:5px;
+               }
+               #timepicker ul li {
+                       position:relative;
+                       display:block;
+                       float:left;
+                       width:50px;
+                                               
+               }
+               #timepicker ul li h4 {
+                       width:100%;
+                       background:transparent;
+                       color:#000;
+                               text-align:center;                                              
+               }
+               #timepicker ul li .slider {
+                       position:relative;
+                       left:10px;
+                       
+               /*      background:#FBF9EE url(images/ui-bg_glass_55_fbf9ee_1x400.png) repeat-x scroll 50% 50%;
+                               border:1px solid #FCEFA1;*/
+               }
diff --git a/auf_savoirs_en_partage_django/media/js/jquery/jquery.timepicker.js b/auf_savoirs_en_partage_django/media/js/jquery/jquery.timepicker.js
new file mode 100644 (file)
index 0000000..0534404
--- /dev/null
@@ -0,0 +1,311 @@
+// änderungen / 090521:
+// OK beim einlesen im american mode zeit umrechnen
+// OK datum einlesen
+// OK beim ändern des input feldes widget anpassen / neu einlesen
+// OK >> wenn keine stunde/minute angegeben ist 00 angeben
+// OK sprache datepicker
+// OK sprache durch parameter reingeben
+// OK mehrere felder bedienen
+// OK datepicker als klickbar machen
+
+/** fixes / 090521:
+       - convert widget time to am/pm if american mode is on
+       - show correct date from input
+       - on change at input field modify widget
+       - if there is no hour/minute given in input, show 00
+       - start datepicker in given language
+       - new parameter for language
+       - able to work on many fields
+       - write date from datepicker
+*/
+jQuery.fn.datetime = function() {
+
+       var userLang            = arguments[0]['userLang'] || 'en';
+       var b24Hour                     = !(arguments[0]['americanMode'] || false);     
+       var markerClass         = 'hasDateTime';
+
+                               
+       return this.each(function(){
+                        
+                               var datepicker_def      = {
+                                                       changeMonth: true,
+                                                       changeYear: true,
+                                                       dateFormat: 'yy-mm-dd',
+                                                       showButtonPanel: true, 
+                                                       onSelect: writeDate                                             
+                               };                      
+               
+                               var lang = {};
+
+                               lang['en'] = {
+                                                               time:   'Time',
+                                                               hour:   'Hour',
+                                                               minute: 'Minute',
+                                                               close:  'Close'                 
+                                                       };
+
+        lang['fr'] = {
+                                                               time:   'Heure',
+                                                               hour:   'Heure',
+                                                               minute: 'Minute',
+                                                               close:  'Fermer'                        
+                                                       };
+                                                       
+                               lang['de'] = {
+                                                               time:   'Zeit',
+                                                               hour:   'Stunde',
+                                                               minute: 'Minute',
+                                                               close:  'Schließen'                    
+                                                       };                              
+                               
+                               $(this).data('sets',datepicker_def);
+                               $(this).data('userLang',userLang);
+                               $(this).data('b24Hour',b24Hour);
+                               
+                               function renderPickerPlug(b24Hour_,lang_) {
+                                       var loadedLang = lang[lang_] || lang['en'];
+                                       
+                                       if (!$('#pickerplug').length) {
+                                       
+                                               var htmlins = '<ul id="pickerplug">';
+                                               htmlins += '<li>';
+                                               htmlins += '<div id="datepicker"></div>';
+                                               htmlins += '</li>';
+                                               htmlins += '<li>';
+                                               htmlins += '<div id="timepicker">';
+                                               htmlins += '<h3 id="tpSelectedTime">';
+                                               htmlins += '    <span id="text_time"></span>';
+                                               htmlins += '    <span class="selHrs" >00</span>';
+                                               htmlins += '    <span class="delim" >:</span>';
+                                               htmlins += '    <span class="selMins">00</span>';
+                                               htmlins += '    <span class="dayPeriod">am</span>';
+                                               htmlins += '</h3>';                     
+                                               htmlins += '<ul id="sliderContainer">'; 
+                                               htmlins += '    <li>';
+                                               htmlins += '        <h4 id="text_hour"></h4>';
+                                               htmlins += '        <div id="hourSlider" class="slider"></div>';
+                                               htmlins += '    </li>';
+                                               htmlins += '    <li>';
+                                               htmlins += '        <h4 id="text_minute"></h4>';                                
+                                               htmlins += '        <div id="minuteSlider" class="slider"></div>';
+                                               htmlins += '    </li>';
+                                               htmlins += '</ul>';
+                                               htmlins += '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" id="text_close"></button><p>&nbsp;</p>';                               
+                                               htmlins += '</div>';
+                                               htmlins += '</li>';                             
+                                               htmlins += '</ul>';
+                                               $('body').append(htmlins);      
+                                               
+                                               $('#datepicker').datepicker();
+                                               $(document).mousedown(closePickPlug);                   
+                                               $('#pickerplug .ui-datepicker-close').click(closePickPlug);                                                     
+
+        // Slider
+                                               $('#hourSlider').slider({
+                                                       orientation: "vertical",   
+                                                       range: 'min',                 
+                                                       min: 0,
+                                                       max: 23,
+                                                       step: 1,
+                                                       slide: function(event, ui) {
+                                                               writeDate(writeTime(ui.value,'hour'),'time');
+                                                               
+                                                       },
+                                                       change: function(event, ui) {
+                                                               $('#tpSelectedTime .selHrs').effect('highlight', 1000);
+                                                       }
+                                               });
+                                               // Slider
+                                               $('#minuteSlider').slider({
+                                                       orientation: "vertical",      
+                                                       range: 'min',                                  
+                                                       min: 0,
+                                                       max: 55,
+                                                       step: 5,
+                                                       slide: function(event, ui) {                   
+                                                               writeDate(writeTime(ui.value,'minute'),'time');                                           
+                                                       },
+                                                       change: function(event, ui) {
+                                                               $('#tpSelectedTime .selMins').effect('highlight', 1000);
+                                                       }
+                                               });
+                                       
+               //Inline editor bind
+                                               $('#tpSelectedTime .selHrs').keyup(function(e){
+                                                       if((e.which <= 57 && e.which >= 48) && ($(this).text() >=1 && $(this).text() <=12 ) ){
+                                                       //console.log("Which: "+e.which);
+                                                  $('#hourSlider').slider('value', parseInt($(this).text()));
+                                                       //console.log("Val: "+parseInt($(this).val()))
+                                                       }else{
+                                                               $(this).val($(this).text().slice(0, -1));
+                                                       }
+                                                       //if($(this).val() < 1){
+                                                       //    $(this).val(1);
+                                                       //}
+                                               });
+                                               
+               //Inline editor bind
+                                               $('#tpSelectedTime .selMins').keyup(function(e){
+                                                       if((e.which <= 57 && e.which >= 48) && ($(this).text() >=0 && $(this).text() <=59 ) ){
+                                                       //console.log("Which: "+e.which);
+                                                  $('#minuteSlider').slider('value', parseInt($(this).text()));
+                                                       //console.log("Val: "+parseInt($(this).val()))
+                                                       }else{
+                                                               $(this).text($(this).text().slice(0, -1));
+                                                       }
+                                                       //if($(this).val() < 1){
+                                                       //    $(this).val(1);
+                                                       //}
+                                               });                                     
+                                       }
+
+                                       $('.dayPeriod').toggle(!b24Hour);
+                                       $('#text_time').text(loadedLang['time']);
+                                       $('#text_hour').text(loadedLang['hour']);
+                                       $('#text_minute').text(loadedLang['minute']);
+                                       $('#text_close').text(loadedLang['close']);
+                                       
+                                       $('#pickerplug').data('userLang',lang_);
+                                       $('#pickerplug').data('b24Hour',b24Hour_);      
+                               }
+                               
+                               $(this).bind('focus',function(){ 
+                                       
+                                       var top         = $(this).offset().top+$(this).outerHeight(); 
+                                       var left        = $(this).offset().left;
+                                       
+                                       if ($(this).data('userLang')    != $('#pickerplug').data('userLang') || 
+                                               $(this).data('b24Hour')         != $('#pickerplug').data('userLang') ) {
+                                               renderPickerPlug($(this).data('b24Hour'),$(this).data('userLang'));
+                                       }
+                                       
+                                       $('#pickerplug').css({
+                                                                               left: left+'px',
+                                                                               top: top+'px'
+                                                                               }).css('display', 'block');                                             
+                                       
+                                       if ($(this).data('userLang')!='en' && lang[$(this).data('userLang')]) {
+                                               $('#datepicker').datepicker('option', $.extend({},
+                                                                                               $.datepicker.regional[$(this).data('userLang')]));      
+                                               $('#datepicker').datepicker('option', $.extend($(this).data('sets')));                                                                                                  
+                                       } else {
+                                               $('#datepicker').datepicker('option', $.extend({},
+                                                                                               $.datepicker.regional['']));    
+                                               $('#datepicker').datepicker('option', $.extend($(this).data('sets')));                                                                                          
+                                       }                                       
+
+                                       parseTime(this);
+                                       
+                                       if ($('#pickerplug').css('display') == 'none') {                                                                                        
+                                               $('#pickerplug').css('display', 'block');
+                                       }
+                                       
+                                       $(this).bind('keyup',parseTime);
+                                       //$(this).bind('slider',writeTime);
+
+                                       $(this).addClass(markerClass);
+
+                                       $('#pickerplug').data('inputfield',this);
+                               });
+
+                               function parseTime (obj) {
+
+                                       var time = ($(obj).val() || $(this).val()).split(" ");
+                                       
+                                       if (time.length < 2) {
+                                               time = ['00-00-00','00:00:00'];
+                                       }
+                                               
+                                       $('#pickerplug').data('lastdate',time[0]);      //lastdate = time[0];
+                                       $('#pickerplug').data('lasttime',time[1]);  //lasttime = time[1];                                       
+                                       time = time[1].split(":");                                      
+                                       
+                                       if (time.length < 2) {
+                                               time = ['00','00','00'];
+                                       }
+                                       
+                                       var hour        = time[0] || '00';
+                                       var minute      = time[1] || '00';
+                               
+                                       writeTime(hour,'hour');
+                                       writeTime(minute,'minute');
+
+                                       $('#hourSlider').slider('option', 'value', hour);
+                                       $('#minuteSlider').slider('option', 'value', minute);   
+                                                                               
+                                       $('#datepicker').datepicker(
+                                                                                       'setDate', 
+                                                                                       $.datepicker.parseDate(
+                                                                                                       datepicker_def['dateFormat'], 
+                                                                                                       $('#pickerplug').data('lastdate')
+                                                                                               ));
+                               }
+                               
+                               function writeTime(fragment,type) {
+                                       var time = '';
+                                       
+                                       switch (type) {
+                                               case 'hour':
+                               var hours = parseInt(fragment,10);
+                                                               
+                               if (!$('#pickerplug').data('b24Hour') && hours > 11) {                                  
+                                       hours -= 12;
+                                       $('.dayPeriod').text('pm');
+                                       
+                               } else if (!$('#pickerplug').data('b24Hour')) {
+                                       $('.dayPeriod').text('am');
+                               } 
+                               
+                               if (hours < 10) {
+                                       hours = '0'.concat(hours);
+                               }
+                               if (fragment < 10) {
+                                       fragment = '0'.concat(parseInt(fragment));
+                               }
+                               
+                               $('#tpSelectedTime .selHrs').text(hours);
+                               
+                               time = fragment+':'+$('#tpSelectedTime .selMins').text();                                               
+                                                       break;
+                                               case 'minute':
+                               minutes = ((fragment < 10) ? '0' :'') + parseInt(fragment,10);
+                               $('#tpSelectedTime .selMins').text(minutes);
+                          
+                               time = $('#hourSlider').slider('option', 'value')+':'+minutes;                                                  
+                                                       break;
+                                       }
+                                       return time;
+                               }                               
+                               
+                               function writeDate (text,type) {
+
+                                       switch (type) {
+                                               case 'time':
+                                                       $('#pickerplug').data('lasttime',text+':00');                                           
+                                                       break;  
+                                               default:
+                                                       $('#pickerplug').data('lastdate',text);                                                                                         
+                                       }
+                                       
+                                       $($('#pickerplug').data('inputfield')).val(
+                                                               $('#pickerplug').data('lastdate')+' '+$('#pickerplug').data('lasttime')
+                                       );
+                               }
+                               
+                               function closePickPlug (event) {
+
+                                       if (($(event.target).parents('#pickerplug').length ||
+                                               $(event.target).hasClass(markerClass)) &&
+                                               !$(event.target).hasClass('ui-datepicker-close')) {                                     
+                                               return;
+                                       }
+                                       
+                                       $('#pickerplug').css('display', 'none');                
+                                       $(this).unbind('click',closePickPlug);
+                                       $(this).unbind('keyup',parseTime);
+                                       $(this).removeClass(markerClass);
+                               }
+                                                               
+            });
+            
+           }
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/00changelog.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/00changelog.i
new file mode 100644 (file)
index 0000000..d3a8311
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/00changelog.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branch b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branch
new file mode 100644 (file)
index 0000000..4ad96d5
--- /dev/null
@@ -0,0 +1 @@
+default
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branchheads.cache b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/branchheads.cache
new file mode 100644 (file)
index 0000000..d4365e1
--- /dev/null
@@ -0,0 +1,2 @@
+50112f350013df437ab0db387cb4644e8e901446 66
+50112f350013df437ab0db387cb4644e8e901446 default
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/dirstate b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/dirstate
new file mode 100644 (file)
index 0000000..b46f27a
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/dirstate differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/hgrc b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/hgrc
new file mode 100644 (file)
index 0000000..cc59ab8
--- /dev/null
@@ -0,0 +1,2 @@
+[paths]
+default = http://bitbucket.org/robla/jsonwidget-javascript/
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/requires b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/requires
new file mode 100644 (file)
index 0000000..5175383
--- /dev/null
@@ -0,0 +1,3 @@
+revlogv1
+store
+fncache
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00changelog.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00changelog.i
new file mode 100644 (file)
index 0000000..be30465
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00changelog.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00manifest.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00manifest.i
new file mode 100644 (file)
index 0000000..5541229
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/00manifest.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_j_s_o_n.php.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_j_s_o_n.php.i
new file mode 100644 (file)
index 0000000..ad1d64f
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_j_s_o_n.php.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_l_i_c_e_n_s_e.txt.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_l_i_c_e_n_s_e.txt.i
new file mode 100644 (file)
index 0000000..a68ffeb
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/_l_i_c_e_n_s_e.txt.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/addressbookschema.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/addressbookschema.json.i
new file mode 100644 (file)
index 0000000..370fa7a
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/addressbookschema.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/behaviour.js.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/behaviour.js.i
new file mode 100644 (file)
index 0000000..f2afcd4
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/behaviour.js.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionlarge.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionlarge.json.i
new file mode 100644 (file)
index 0000000..8a59a2e
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionlarge.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionnormal.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionnormal.json.i
new file mode 100644 (file)
index 0000000..4482c32
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionnormal.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionschema.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionschema.json.i
new file mode 100644 (file)
index 0000000..30fe30b
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electionschema.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electiontiny.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electiontiny.json.i
new file mode 100644 (file)
index 0000000..93a4d17
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/electiontiny.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/example.php.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/example.php.i
new file mode 100644 (file)
index 0000000..d36f10c
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/example.php.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/index.html.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/index.html.i
new file mode 100644 (file)
index 0000000..a7df238
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/index.html.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/json.js.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/json.js.i
new file mode 100644 (file)
index 0000000..971eaf3
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/json.js.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonedit.js.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonedit.js.i
new file mode 100644 (file)
index 0000000..2982352
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonedit.js.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonwidget.css.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonwidget.css.i
new file mode 100644 (file)
index 0000000..3964cc8
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/jsonwidget.css.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/openschema.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/openschema.json.i
new file mode 100644 (file)
index 0000000..8289d33
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/openschema.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/prototype.html.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/prototype.html.i
new file mode 100644 (file)
index 0000000..e4edffe
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/prototype.html.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-large.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-large.json.i
new file mode 100644 (file)
index 0000000..9c0d0dd
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-large.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-tiny.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-tiny.json.i
new file mode 100644 (file)
index 0000000..79ba368
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata-tiny.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata.json.i
new file mode 100644 (file)
index 0000000..31ad5ba
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampledata.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampleschema.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampleschema.json.i
new file mode 100644 (file)
index 0000000..2d90a60
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/sampleschema.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/schemaschema.json.i b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/schemaschema.json.i
new file mode 100644 (file)
index 0000000..9090d38
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/data/schemaschema.json.i differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/fncache b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/fncache
new file mode 100644 (file)
index 0000000..6773d05
--- /dev/null
@@ -0,0 +1,20 @@
+data/JSON.php.i
+data/LICENSE.txt.i
+data/addressbookschema.json.i
+data/behaviour.js.i
+data/electionlarge.json.i
+data/electionnormal.json.i
+data/electionschema.json.i
+data/electiontiny.json.i
+data/example.php.i
+data/index.html.i
+data/json.js.i
+data/jsonedit.js.i
+data/jsonwidget.css.i
+data/openschema.json.i
+data/prototype.html.i
+data/sampledata-large.json.i
+data/sampledata-tiny.json.i
+data/sampledata.json.i
+data/sampleschema.json.i
+data/schemaschema.json.i
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/undo b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/undo
new file mode 100644 (file)
index 0000000..42baa1a
Binary files /dev/null and b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/store/undo differ
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/tags.cache b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/tags.cache
new file mode 100644 (file)
index 0000000..4fd59ca
--- /dev/null
@@ -0,0 +1,2 @@
+66 50112f350013df437ab0db387cb4644e8e901446
+
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.branch b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.branch
new file mode 100644 (file)
index 0000000..331d858
--- /dev/null
@@ -0,0 +1 @@
+default
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.dirstate b/auf_savoirs_en_partage_django/media/js/jsonwidget/.hg/undo.dirstate
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/JSON.php b/auf_savoirs_en_partage_django/media/js/jsonwidget/JSON.php
new file mode 100644 (file)
index 0000000..92faca4
--- /dev/null
@@ -0,0 +1,664 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/** 
+ * Converts to and from JSON format.
+ * 
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in  Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ * 
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met: Redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * 
+ * @category   
+ * @package     Services_JSON
+ * @author      Michal Migurski <mike-json@teczno.com>
+ * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright   2005 Michal Migurski
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ */
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_SLICE',   1);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_STR',  2);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_ARR',  4);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_OBJ',  8);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_CMT', 16);
+
+/**
+ * Behavior switch for JSON::decode()
+ */
+define('JSON_LOOSE_TYPE', 10);
+
+/**
+ * Behavior switch for JSON::decode()
+ */
+define('JSON_STRICT_TYPE', 11);
+
+/** 
+ * Converts to and from JSON format.
+ *
+ * @category   
+ * @package    JSON
+ * @author     Michal Migurski <mike-json@teczno.com>
+ * @author     Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author     Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright  2005 Michal Migurski
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ */
+class Services_JSON
+{
+   /**
+    * constructs a new JSON instance
+    *
+    * @param    int     $use    object behavior: when encoding or decoding,
+    *                           be loose or strict about object/array usage
+    *
+    *                           possible values:
+    *                              JSON_STRICT_TYPE - strict typing, default
+    *                                                 "{...}" syntax creates objects in decode.
+    *                               JSON_LOOSE_TYPE - loose typing
+    *                                                 "{...}" syntax creates associative arrays in decode.
+    */
+    function Services_JSON($use=JSON_STRICT_TYPE)
+    {
+        $this->use = $use;
+    }
+
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   string  JSON string representation of input var
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+            
+            case 'NULL':
+                return 'null';
+            
+            case 'integer':
+                return (int) $var;
+                
+            case 'double':
+            case 'float':
+                return (float) $var;
+                
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+                    
+                    $ord_var_c = ord($var{$c});
+                    
+                    switch (true) {
+                        case $ord_var_c == 0x08:
+                            $ascii .= '\b';
+                            break;
+                        case $ord_var_c == 0x09:
+                            $ascii .= '\t';
+                            break;
+                        case $ord_var_c == 0x0A:
+                            $ascii .= '\n';
+                            break;
+                        case $ord_var_c == 0x0C:
+                            $ascii .= '\f';
+                            break;
+                        case $ord_var_c == 0x0D:
+                            $ascii .= '\r';
+                            break;
+
+                        case $ord_var_c == 0x22:
+                        case $ord_var_c == 0x2F:
+                        case $ord_var_c == 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+                            
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+                        
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c+1}));
+                            $c+=1;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}));
+                            $c+=2;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}));
+                            $c+=3;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}),
+                                         ord($var{$c+4}));
+                            $c+=4;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}),
+                                         ord($var{$c+4}),
+                                         ord($var{$c+5}));
+                            $c+=5;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+                
+                return '"'.$ascii.'"';
+                
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                * 
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+                
+                // treat as a JSON object  
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    return '{' .
+                           join(',', array_map(array($this, 'name_value'),
+                                               array_keys($var),
+                                               array_values($var)))
+                           . '}';
+                }
+
+                // treat it like a regular array
+                return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']';
+                
+            case 'object':
+                $vars = get_object_vars($var);
+                return '{' .
+                       join(',', array_map(array($this, 'name_value'),
+                                           array_keys($vars),
+                                           array_values($vars)))
+                       . '}';
+
+            default:
+                return '';
+        }
+    }
+    
+   /**
+    * encodes an arbitrary variable into JSON format, alias for encode()
+    * @see JSON::encode()
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   string  JSON string representation of input var
+    * @access   public
+    */
+    function enc($var)
+    {
+        return $this->encode($var);
+    }
+    
+   /** function name_value
+    * array-walking function for use in generating JSON-formatted name-value pairs
+    *
+    * @param    string  $name   name of key to use
+    * @param    mixed   $value  reference to an array element to be encoded
+    *
+    * @return   string  JSON-formatted name-value pair, like '"name":value'
+    * @access   private
+    */
+    function name_value($name, $value)
+    {
+        return $this->encode(strval($name)) . ':' . $this->encode($value);
+    }        
+
+   /**
+    * reduce a string by removing leading and trailing comments and whitespace
+    *
+    * @param    $str    string      string value to strip of comments and whitespace
+    *
+    * @return   string  string value stripped of comments and whitespace
+    * @access   private
+    */
+    function reduce_string($str)
+    {
+        $str = preg_replace(array(
+        
+                // eliminate single line comments in '// ...' form
+                '#^\s*//(.+)$#m',
+    
+                // eliminate multi-line comments in '/* ... */' form, at start of string
+                '#^\s*/\*(.+)\*/#Us',
+    
+                // eliminate multi-line comments in '/* ... */' form, at end of string
+                '#/\*(.+)\*/\s*$#Us'
+    
+            ), '', $str);
+        
+        // eliminate extraneous space
+        return trim($str);
+    }
+
+   /**
+    * decodes a JSON string into appropriate variable
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    * @access   public
+    */
+    function decode($str)
+    {
+        $str = $this->reduce_string($str);
+    
+        switch (strtolower($str)) {
+            case 'true':
+                return true;
+
+            case 'false':
+                return false;
+            
+            case 'null':
+                return null;
+            
+            default:
+                if (is_numeric($str)) {
+                    // Lookie-loo, it's a number
+
+                    // This would work on its own, but I'm trying to be
+                    // good about returning integers where appropriate:
+                    // return (float)$str;
+
+                    // Return float or int, as appropriate
+                    return ((float)$str == (integer)$str)
+                        ? (integer)$str
+                        : (float)$str;
+                    
+                } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+                    // STRINGS RETURNED IN UTF-8 FORMAT
+                    $delim = substr($str, 0, 1);
+                    $chrs = substr($str, 1, -1);
+                    $utf8 = '';
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c < $strlen_chrs; ++$c) {
+                    
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                        $ord_chrs_c = ord($chrs{$c});
+                        
+                        switch (true) {
+                            case $substr_chrs_c_2 == '\b':
+                                $utf8 .= chr(0x08);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\t':
+                                $utf8 .= chr(0x09);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\n':
+                                $utf8 .= chr(0x0A);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\f':
+                                $utf8 .= chr(0x0C);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\r':
+                                $utf8 .= chr(0x0D);
+                                ++$c;
+                                break;
+
+                            case $substr_chrs_c_2 == '\\"':
+                            case $substr_chrs_c_2 == '\\\'':
+                            case $substr_chrs_c_2 == '\\\\':
+                            case $substr_chrs_c_2 == '\\/':
+                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+                                    $utf8 .= $chrs{++$c};
+                                }
+                                break;
+                                
+                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+                                // single, escaped unicode character
+                                $utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
+                                       . chr(hexdec(substr($chrs, ($c+4), 2)));
+                                $utf8 .= mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+                                $c+=5;
+                                break;
+        
+                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+                                $utf8 .= $chrs{$c};
+                                break;
+        
+                            case ($ord_chrs_c & 0xE0) == 0xC0:
+                                // characters U-00000080 - U-000007FF, mask 110XXXXX
+                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 2);
+                                ++$c;
+                                break;
+    
+                            case ($ord_chrs_c & 0xF0) == 0xE0:
+                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 3);
+                                $c += 2;
+                                break;
+    
+                            case ($ord_chrs_c & 0xF8) == 0xF0:
+                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 4);
+                                $c += 3;
+                                break;
+    
+                            case ($ord_chrs_c & 0xFC) == 0xF8:
+                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 5);
+                                $c += 4;
+                                break;
+    
+                            case ($ord_chrs_c & 0xFE) == 0xFC:
+                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 6);
+                                $c += 5;
+                                break;
+
+                        }
+
+                    }
+                    
+                    return $utf8;
+                
+                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+                    // array, or object notation
+
+                    if ($str{0} == '[') {
+                        $stk = array(JSON_IN_ARR);
+                        $arr = array();
+                    } else {
+                        if ($this->use == JSON_LOOSE_TYPE) {
+                            $stk = array(JSON_IN_OBJ);
+                            $obj = array();
+                        } else {
+                            $stk = array(JSON_IN_OBJ);
+                            $obj = new stdClass();
+                        }
+                    }
+                    
+                    array_push($stk, array('what'  => JSON_SLICE,
+                                           'where' => 0,
+                                           'delim' => false));
+
+                    $chrs = substr($str, 1, -1);
+                    $chrs = $this->reduce_string($chrs);
+                    
+                    if ($chrs == '') {
+                        if (reset($stk) == JSON_IN_ARR) {
+                            return $arr;
+
+                        } else {
+                            return $obj;
+
+                        }
+                    }
+
+                    //print("\nparsing {$chrs}\n");
+                    
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
+                    
+                        $top = end($stk);
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                    
+                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == JSON_SLICE))) {
+                            // found a comma that is not inside a string, array, etc.,
+                            // OR we've reached the end of the character list
+                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
+                            array_push($stk, array('what' => JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                            if (reset($stk) == JSON_IN_ARR) {
+                                // we are in an array, so just push an element onto the stack
+                                array_push($arr, $this->decode($slice));
+
+                            } elseif (reset($stk) == JSON_IN_OBJ) {
+                                // we are in an object, so figure
+                                // out the property name and set an
+                                // element in an associative array,
+                                // for now
+                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // "name":value pair
+                                    $key = $this->decode($parts[1]);
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // name:value pair, where name is unquoted
+                                    $key = $parts[1];
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                }
+
+                            }
+
+                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != JSON_IN_STR)) {
+                            // found a quote, and we are not inside a string
+                            array_push($stk, array('what' => JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+                            //print("Found start of string at {$c}\n");
+
+                        } elseif (($chrs{$c} == $top['delim']) &&
+                                 ($top['what'] == JSON_IN_STR) &&
+                                 (($chrs{$c - 1} != "\\") ||
+                                 ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) {
+                            // found a quote, we're in a string, and it's not escaped
+                            array_pop($stk);
+                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '[') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a left-bracket, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_ARR, 'where' => $c, 'delim' => false));
+                            //print("Found start of array at {$c}\n");
+
+                        } elseif (($chrs{$c} == ']') && ($top['what'] == JSON_IN_ARR)) {
+                            // found a right-bracket, and we're in an array
+                            array_pop($stk);
+                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '{') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a left-brace, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+                            //print("Found start of object at {$c}\n");
+
+                        } elseif (($chrs{$c} == '}') && ($top['what'] == JSON_IN_OBJ)) {
+                            // found a right-brace, and we're in an object
+                            array_pop($stk);
+                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($substr_chrs_c_2 == '/*') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a comment start, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_CMT, 'where' => $c, 'delim' => false));
+                            $c++;
+                            //print("Found start of comment at {$c}\n");
+
+                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == JSON_IN_CMT)) {
+                            // found a comment end, and we're in one now
+                            array_pop($stk);
+                            $c++;
+                            
+                            for ($i = $top['where']; $i <= $c; ++$i)
+                                $chrs = substr_replace($chrs, ' ', $i, 1);
+                            
+                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        }
+                    
+                    }
+                    
+                    if (reset($stk) == JSON_IN_ARR) {
+                        return $arr;
+
+                    } elseif (reset($stk) == JSON_IN_OBJ) {
+                        return $obj;
+
+                    }
+                
+                }
+        }
+    }
+    
+   /**
+    * decodes a JSON string into appropriate variable; alias for decode()
+    * @see JSON::decode()
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    */
+    function dec($var)
+    {
+        return $this->decode($var);
+    }
+    
+}
+    
+?>
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/LICENSE.txt b/auf_savoirs_en_partage_django/media/js/jsonwidget/LICENSE.txt
new file mode 100644 (file)
index 0000000..39993f6
--- /dev/null
@@ -0,0 +1,30 @@
+Copyright (c) 2005, Rob Lanphier
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither my name nor the names of my contributors may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/addressbookschema.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/addressbookschema.json
new file mode 100644 (file)
index 0000000..a672b11
--- /dev/null
@@ -0,0 +1,60 @@
+{
+  "type":"seq",
+  "sequence":
+  [
+    {
+      "type":"map",
+      "mapping":
+      {
+        "Name":
+        {
+          "type":"str",
+          "required":true
+        },
+        "Email":
+        {
+          "type":"str",
+          "required":true
+        },
+        "Address":
+        {
+          "type":"str",
+          "required":true
+        },
+        "Phone":
+        {
+          "type":"seq",
+          "required":true,
+          "sequence":
+          [
+            {
+              "type":"map",
+              "mapping":
+              {
+                "workhomeother":
+                {
+                  "type":"str",
+                  "required":true,
+                  "enum":
+                  [
+                    "Work",
+                    "Home",
+                    "Mobile",
+                    "Fax",
+                    "Other"
+                  ],
+                  "title":"Work/Home/Other"
+                },
+                "Number":
+                {
+                  "type":"str",
+                  "required":true
+                }
+              }
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/electionlarge.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/electionlarge.json
new file mode 100644 (file)
index 0000000..4a4835c
--- /dev/null
@@ -0,0 +1,230 @@
+{
+  "version": "0.1",
+  "description": "Actual results of the 2003 Debian Project Leader elections.  See http:\/\/www.debian.org\/vote\/2003\/vote_0001 .  The Debian Project uses the [[Wikipedia:Schulze method|Schulze method]], but [[Wikipedia:Instant runoff voting|Instant runoff voting]] results are also provided for comparison purposes.  A [http:\/\/electorama.com\/modules.php?op=modload&name=News&file=article&sid=32 detailed discussion of these results] is also available, written long ago before this program was released.   See talk page for discussion about conversion of ranked ballots to range ballots.  An approval voting tally is also provided, which assumes all candidates better than NOTA are approved, and all candidates equal to or below are not approved.  The approval result is admittedly dubious, since its not obvious the voters would have actually voted that way.",
+  "display_parameters": true,
+  "display_results": true,
+  "display_ballots": true,
+  "election_methods": [
+      {
+        "type": "schulze-wv-mod"
+      },
+      {
+        "type": "instant-runoff"
+      },
+      {
+        "type": "approval"
+      }
+    ],
+  "allow_voting": false,
+  "ballot_type": null,
+  "max_rating": 5,
+  "min_rating": -5,
+  "count_subpage_ballots": false,
+  "count_inline_ballots": true,
+  "candidates": {
+      "Zadka": {
+          "display_name" : "Moshe Zadka"
+        },
+      "Garbee": {
+          "display_name" : "Bdale Garbee"
+        },
+      "Robinson": {
+          "display_name" : "Branden Robinson"
+        },
+      "Michlmayr": {
+          "display_name" : "Michael Michlmayr"
+        },
+      "NOTA": {
+          "display_name" : "None Of The Above"
+        }
+    },
+  "inline_ballot_type": "range-array",
+  "inline_ballots": [
+{"qty":1, "vote": {"NOTA":0}},
+{"qty":2, "vote": {"Michlmayr":5}},
+{"qty":1, "vote": {"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Robinson":5}},
+{"qty":3, "vote": {"Robinson":5,"NOTA":0}},
+{"qty":1, "vote": {"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Robinson":4,"Michlmayr":5}},
+{"qty":2, "vote": {"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Robinson":3,"Michlmayr":5}},
+{"qty":3, "vote": {"Garbee":5}},
+{"qty":1, "vote": {"Garbee":5,"NOTA":0}},
+{"qty":2, "vote": {"Garbee":5,"Michlmayr":4}},
+{"qty":5, "vote": {"Garbee":5,"Michlmayr":4,"NOTA":0}},
+{"qty":9, "vote": {"Garbee":5,"Robinson":4}},
+{"qty":2, "vote": {"Garbee":5,"Robinson":4,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":5,"Robinson":4,"Michlmayr":4}},
+{"qty":3, "vote": {"Garbee":5,"Robinson":4,"Michlmayr":3}},
+{"qty":3, "vote": {"Garbee":5,"Robinson":4,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":5,"Robinson":3}},
+{"qty":4, "vote": {"Garbee":5,"Robinson":3,"Michlmayr":4}},
+{"qty":1, "vote": {"Garbee":5,"Robinson":2,"Michlmayr":3,"NOTA":0}},
+{"qty":3, "vote": {"Garbee":4,"Michlmayr":5}},
+{"qty":7, "vote": {"Garbee":4,"Michlmayr":5,"NOTA":0}},
+{"qty":4, "vote": {"Garbee":4,"Robinson":5}},
+{"qty":7, "vote": {"Garbee":4,"Robinson":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":4,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Garbee":4,"Robinson":5,"Michlmayr":3}},
+{"qty":3, "vote": {"Garbee":4,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":2, "vote": {"Garbee":4,"Robinson":4,"Michlmayr":5}},
+{"qty":3, "vote": {"Garbee":4,"Robinson":3,"Michlmayr":5}},
+{"qty":1, "vote": {"Garbee":4,"Robinson":0,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Garbee":4,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":4,"Robinson":2,"Michlmayr":5}},
+{"qty":1, "vote": {"Garbee":-1,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":3,"Robinson":5}},
+{"qty":3, "vote": {"Garbee":3,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":3,"Robinson":5,"Michlmayr":2}},
+{"qty":3, "vote": {"Garbee":3,"Robinson":4,"Michlmayr":5}},
+{"qty":4, "vote": {"Garbee":3,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":3,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Garbee":2,"Robinson":5,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":5,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":4,"Robinson":3,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":4,"Robinson":3,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Robinson":4,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Robinson":3,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Robinson":3,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":3,"Robinson":2,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":5,"Garbee":2,"Robinson":3,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Robinson":5}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":5,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":5,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":4,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":4,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":0,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":3,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":5,"Robinson":2,"Michlmayr":3}},
+{"qty":3, "vote": {"Zadka":4,"Garbee":5,"Robinson":-1,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":4,"Robinson":5,"Michlmayr":4}},
+{"qty":2, "vote": {"Zadka":4,"Garbee":4,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":3,"Robinson":5,"Michlmayr":2}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":3,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":3,"Robinson":2,"Michlmayr":5}},
+{"qty":2, "vote": {"Zadka":4,"Garbee":3,"Robinson":2,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":-2,"Robinson":-3,"Michlmayr":-4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":3,"Robinson":-1,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":4,"Garbee":-1,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Robinson":4,"Michlmayr":5}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":3}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":5,"Robinson":4,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":5,"Robinson":2,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":5,"Robinson":2,"Michlmayr":4}},
+{"qty":4, "vote": {"Zadka":3,"Garbee":5,"Robinson":2,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-2,"Michlmayr":-1,"NOTA":0}},
+{"qty":6, "vote": {"Zadka":3,"Garbee":5,"Robinson":-1,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-3,"Michlmayr":-1,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-3,"Michlmayr":-2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Michlmayr":5}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":4,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":3}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":4, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":2}},
+{"qty":5, "vote": {"Zadka":3,"Garbee":4,"Robinson":5,"Michlmayr":2,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":4,"Michlmayr":5}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":4,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":4,"Robinson":0,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":4,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":2,"Michlmayr":5}},
+{"qty":5, "vote": {"Zadka":3,"Garbee":4,"Robinson":2,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":4,"Robinson":-1,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":3,"Robinson":5,"Michlmayr":3}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":-1,"Robinson":5,"Michlmayr":-1,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":3,"Garbee":2,"Robinson":5,"Michlmayr":4}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":2,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":3,"Garbee":2,"Robinson":4,"Michlmayr":5}},
+{"qty":3, "vote": {"Zadka":3,"Garbee":2,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-1,"Garbee":5,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":2,"Garbee":5,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":2,"Garbee":5,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":5, "vote": {"Zadka":2,"Garbee":5,"Robinson":4,"Michlmayr":3}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":4,"Michlmayr":0,"NOTA":0}},
+{"qty":11, "vote": {"Zadka":2,"Garbee":5,"Robinson":4,"Michlmayr":3,"NOTA":0}},
+{"qty":9, "vote": {"Zadka":2,"Garbee":5,"Robinson":3,"Michlmayr":4}},
+{"qty":8, "vote": {"Zadka":2,"Garbee":5,"Robinson":3,"Michlmayr":4,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-1,"Michlmayr":4,"NOTA":0}},
+{"qty":6, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-2,"Michlmayr":4,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":2,"Garbee":4,"Robinson":5,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":2,"Garbee":4,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":10, "vote": {"Zadka":2,"Garbee":4,"Robinson":5,"Michlmayr":3}},
+{"qty":15, "vote": {"Zadka":2,"Garbee":4,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":-2,"NOTA":0}},
+{"qty":9, "vote": {"Zadka":2,"Garbee":4,"Robinson":3,"Michlmayr":5}},
+{"qty":8, "vote": {"Zadka":2,"Garbee":4,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-1,"Garbee":4,"Robinson":-2,"Michlmayr":5,"NOTA":0}},
+{"qty":6, "vote": {"Zadka":2,"Garbee":3,"Robinson":5,"Michlmayr":4}},
+{"qty":15, "vote": {"Zadka":2,"Garbee":3,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":4, "vote": {"Zadka":2,"Garbee":3,"Robinson":4,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":3,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":9, "vote": {"Zadka":2,"Garbee":3,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":2,"Garbee":3,"Robinson":3,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":-2,"Garbee":-1,"Robinson":-3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":-1,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-2,"Garbee":-2,"Robinson":5,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":-1,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":-1,"Garbee":-2,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":7, "vote": {"Zadka":-1,"Garbee":5,"Robinson":4,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":5,"Robinson":4,"Michlmayr":3,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":-2,"Garbee":5,"Robinson":4,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":5,"Robinson":4,"Michlmayr":0,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":5,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":10, "vote": {"Zadka":-1,"Garbee":5,"Robinson":3,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":3,"Michlmayr":0,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":3,"Michlmayr":-1,"NOTA":0}},
+{"qty":4, "vote": {"Zadka":-2,"Garbee":5,"Robinson":-1,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-3,"Garbee":5,"Robinson":-2,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":5,"Robinson":2,"Michlmayr":3,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":5,"Robinson":-1,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":5,"Robinson":0,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":1,"Garbee":4,"Robinson":5,"Michlmayr":5}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":8, "vote": {"Zadka":-1,"Garbee":4,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-2,"Garbee":4,"Robinson":5,"Michlmayr":-1,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-2,"Garbee":4,"Robinson":5,"Michlmayr":-2,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-1,"Garbee":4,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":1,"Garbee":4,"Robinson":4,"Michlmayr":3}},
+{"qty":12, "vote": {"Zadka":-1,"Garbee":4,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":6, "vote": {"Zadka":-2,"Garbee":4,"Robinson":-1,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":3,"Robinson":5,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":1,"Garbee":3,"Robinson":5,"Michlmayr":4}},
+{"qty":1, "vote": {"Zadka":-4,"Garbee":-2,"Robinson":0,"Michlmayr":-1,"NOTA":0}},
+{"qty":26, "vote": {"Zadka":-1,"Garbee":3,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":3,"Robinson":5,"Michlmayr":3,"NOTA":0}},
+{"qty":13, "vote": {"Zadka":-1,"Garbee":3,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":-1,"Garbee":3,"Robinson":3,"Michlmayr":5,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":-2,"Garbee":-1,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":3, "vote": {"Zadka":-3,"Garbee":-2,"Robinson":5,"Michlmayr":-1,"NOTA":0}},
+{"qty":2, "vote": {"Zadka":-2,"Garbee":-1,"Robinson":4,"Michlmayr":5,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":0,"Garbee":0,"Robinson":5,"Michlmayr":4,"NOTA":0}},
+{"qty":1, "vote": {"Zadka":1,"Garbee":1,"Robinson":2,"Michlmayr":5}}
+  ]
+}
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/electionnormal.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/electionnormal.json
new file mode 100644 (file)
index 0000000..ad7774c
--- /dev/null
@@ -0,0 +1,108 @@
+{
+  "version": "0.1",
+  "description": "This is a simplified version of the 2000 election.",
+  "display_parameters": true,
+  "display_results": true,
+  "display_ballots": true,
+  "election_methods": [
+      {
+        "type": "smith"
+      },
+      {
+        "type": "minmax-wv"
+      },
+      {
+        "type": "minmax-margins"
+      },
+      {
+        "type": "schulze-wv"
+      },
+      {
+        "type": "schulze-margins"
+      },
+      {
+        "type": "schulze-wv-mod"
+      },
+      {
+        "type": "approval"
+      },
+      {
+        "type": "range"
+      },
+      {
+        "type": "instant-runoff"
+      },
+      {
+        "type": "plurality"
+      },
+      {
+        "type": "copeland"
+      },
+      {
+        "type": "dmc"
+      }
+    ],
+  "allow_voting": true,
+  "ballot_type": null,
+  "max_rating": 5,
+  "count_subpage_ballots": true,
+  "count_inline_ballots": true,
+  "candidates": {
+      "Bush": {
+          "display_name": "George Bush",
+          "sort_key": "Bush",
+          "party": "Republican",
+          "candidate_url": "http://en.wikipedia.org/wiki/George_W._Bush",
+          "party_url": "http://en.wikipedia.org/wiki/United_States_Republican_Party"
+        },
+      "Gore": {
+          "display_name": "Al Gore",
+          "sort_key": "Gore",
+          "party": "Democrat",
+          "candidate_url": "http://en.wikipedia.org/wiki/Al_Gore",
+          "party_url": "http://en.wikipedia.org/wiki/United_States_Democratic_Party"
+        },
+      "Nader": {
+          "display_name": "Ralph Nader",
+          "sort_key": "Nader",
+          "party": "Reform , (Independent)",
+          "candidate_url": "http://en.wikipedia.org/wiki/Ralph_Nader",
+          "party_url": "http://en.wikipedia.org/wiki/Ralph_Nader"
+        }
+    },
+  "inline_ballot_type": "range-array",
+  "inline_ballots": [
+      {
+        "qty": 24,
+        "vote": {
+            "Bush": "0",
+            "Gore": "5",
+            "Nader": "-1"
+          }
+      },
+      {
+        "qty": 24,
+        "vote": {
+            "Bush": "-1",
+            "Gore": "5",
+            "Nader": "0"
+          }
+      },
+      {
+        "qty": 49,
+        "vote": {
+            "Bush": "5",
+            "Gore": "0",
+            "Nader": "-1"
+          }
+      },
+      {
+        "qty": 3,
+        "vote": {
+            "Bush": "0",
+            "Gore": "2",
+            "Nader": "5"
+          }
+      }
+    ]
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/electionschema.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/electionschema.json
new file mode 100644 (file)
index 0000000..57d3d7f
--- /dev/null
@@ -0,0 +1,308 @@
+{
+  "title":"Election configuration file",
+  "type":"map",
+  "desc":"An election configuration is a mapping with a series of parameters, as defined below:",
+  "mapping":
+  {
+    "version":
+    {
+      "title":"Version",
+      "type":"str",
+      "enum":
+      [
+        "0.1"
+      ],
+      "desc":"Version of the election configuration format being used.",
+      "required":true,
+      "desc_enum":
+      {
+        "0.1":"Format version number for all versions of Electowidget as of this writing (October, 2005)"
+      }
+    },
+    "allow_voting":
+    {
+      "title":"Allow voting?",
+      "type":"bool",
+      "desc":"'true' if a link should be displayed to allow logged-in users to edit their vote."
+    },
+    "ballot_type":
+    {
+      "title":"Ballot type",
+      "type":"str",
+      "enum":
+      [
+        "barscale",
+        "radioarray",
+        "singlecheckbox",
+        "singleradio",
+        "stars"
+      ],
+      "desc":"Controls the appearance and behavior of the voting user interface.",
+      "desc_enum":
+      {
+        "barscale":"Bar chart with adjustable bars.  Requires JavaScript for optimal use, though essential functionality is accessible without JavaScript by entering a rating in the provided text entry field.  Specify minimum and maximum ratings using <code>min_rating</code> and <code>max_rating</code> parameters, and control the size of the sliding scale using <code>barscale_tickpx</code>",
+        "radioarray":"Series of descrete ratings selectable by simple radio button control.  Specify minimum and maximum ratings using <code>min_rating</code> and <code>max_rating</code> parameters, and set the labels for each rating using <code>radioarray_labels</code>.",
+        "singlecheckbox":"Allow users to check (set rating to 1) or uncheck (set rating to 0) for each candidate.  Ignores <code>min_rating</code> and <code>max_rating</code> parameters.  Useful for conducting a pure Approval election.",
+        "singleradio":"Allow users to select (set rating to 1) a single candidate, deselecting all other candidates (setting ratings to 0).  Ignores <code>min_rating</code> and <code>max_rating</code> parameters.  Useful for conducting a traditional plurality election.",
+        "stars":"Graphical bar chart with stars representing the ratings.  Requires JavaScript for optimal use, though essential functionality is accessible without JavaScript by selecting a rating from the provided drop-down selection box.  Specify maximum rating using <code>max_rating</code> parameter.   Ignores <code>min_rating</code> parameter."
+      }
+    },
+    "barscale_tickpx":
+    {
+      "title":"Barscale pixels per tickmark",
+      "type":"number",
+      "desc":"Used when <code>ballot_type</code> is set to 'barscale' to specify the number of pixels per rating.  For example, if min_rating is set to 0, and max_rating is set to 10, setting barscale_tickpx to 2 will cause adjustable portion of the barscale to be 20 pixels wide."
+    },
+    "candidates":
+    {
+      "title":"Candidates",
+      "type":"map",
+      "desc":"Key/value List of candidates in the election.  The key portion is an internal identifier for the candidate used by the program which sometimes shows up in the user interface (though this will hopefully be rare).  Set the key to something readable, but short.",
+      "user_key":"(candidate key)",
+      "mapping":
+      {
+        "(candidate key)":
+        {
+          "title":"Candidate key",
+          "type":"map",
+          "user_key":"(other fields)",
+          "mapping":
+          {
+            "candidate_url":
+            {
+              "title":"Candidate URL",
+              "type":"str",
+              "desc":"URL to a page describing the candidate"
+            },
+            "display_name":
+            {
+              "title":"Display name",
+              "type":"str",
+              "desc":"Name of the candidate as you would like it displayed in the ballots and results."
+            },
+            "(other fields)":
+            {
+              "title":"Other fields",
+              "type":"str",
+              "desc":"Other fields may be defined by adding field definitions to the <code>features</code> mapping."
+            }
+          }
+        }
+      }
+    },
+    "count_subpage_ballots":
+    {
+      "title":"Count subpage ballots?",
+      "type":"bool",
+      "desc":"If <code>true</code>, count ballots cast by logged in users."
+    },
+    "count_inline_ballots":
+    {
+      "title":"Count inline ballots?",
+      "type":"bool",
+      "desc":"If <code>true</code>, count ballots encoded inline in the election config file."
+    },
+    "description":
+    {
+      "title":"Description",
+      "type":"str",
+      "desc":"Description of the election, which appears at the top of the initial election entry page."
+    },
+    "display_ballots":
+    {
+      "title":"Display ballots?",
+      "type":"bool",
+      "desc":"Show the ballots."
+    },
+    "display_parameters":
+    {
+      "title":"Display parameters?",
+      "type":"bool",
+      "desc":"If <code>true</code>, display the parameters for this election on the initial election entry page.  At the time of this writing, this is woefully incomplete, but will at least return the list of candidates."
+    },
+    "display_results":
+    {
+      "title":"Display results?",
+      "type":"bool",
+      "desc":"If <code>true</code>, calculate and display the results of the election with ballots currently on hand."
+    },
+    "election_methods":
+    {
+      "title":"Election methods",
+      "type":"seq",
+      "desc":"List of election methods to use in tallying the results.  Each item of the list is a mapping which has parameters specific to that particular method.",
+      "sequence":
+      [
+        {
+          "desc":"Key/value list of parameters for this particular method.",
+          "id":"election_method",
+          "title":"Method definition",
+          "type":"map",
+          "mapping":
+          {
+            "type":
+            {
+              "title":"Method type",
+              "type":"str",
+              "enum":
+              [
+                "approval",
+                "chain",
+                "copeland",
+                "dmc",
+                "instant-runoff",
+                "minmax-margins",
+                "minmax-wv",
+                "plurality",
+                "range",
+                "schulze-margins",
+                "schulze-wv",
+                "schulze-wv-mod",
+                "smith"
+              ],
+              "desc":"The election tallying method.  <code>schulze-wv</code> is recommended by the author of this software.",
+              "desc_enum":
+              {
+                "approval":"[[Wikipedia:Approval voting|Approval voting]]",
+                "chain":"Chain multiple methods using this election type.  For example, one can define a chain such that the Smith method is used, and Minmax(wv) settles any ties should there be multiple Smith method winners.  Use the 'methods' parameter described below to provide an ordered list of methods.",
+                "copeland":"[[Wikipedia:Copeland method|Copeland method]]",
+                "dmc":"[[Definite Majority Choice]] method.  This particular implementation implements it as Minmax(Total Approval) as an implementation convenience. ",
+                "instant-runoff":"[[Wikipedia:Instant runoff voting|Instant runoff voting]]",
+                "minmax-margins":"[[Minmax]](wv) - use 'margins' to measure victory strength.",
+                "minmax-wv":"[[Minmax]](wv) - use 'winning votes' to measure victory strength.",
+                "plurality":"[[Plurality]]",
+                "range":"[[Wikipedia:Range Voting|Range Voting]]",
+                "schulze-margins":"[[Wikipedia:Schulze method|Schulze method]] - use 'margins' to measure victory strength.",
+                "schulze-wv":"[[Wikipedia:Schulze method|Schulze method]] - use 'winning votes' to measure victory strength.",
+                "schulze-wv-mod":"[[Schulze method]] - use 'winning votes' to measure victory strength, and use 'margins' to resolve ties.",
+                "smith":"Choses the member(s) of the [[Smith set]]"
+              },
+              "required":"true"
+            },
+            "methods":
+            {
+              "title":"Chained methods",
+              "type":"seq",
+              "desc":"Used in conjunction with the <code>chain</code> method.  This defines an ordered sequence of methods to use in calculating the winner.",
+              "sequence":
+              [
+                {
+                  "type":"idref",
+                  "idref":"election_method"
+                }
+              ]
+            }
+          }
+        }
+      ]
+    },
+    "features":
+    {
+      "title":"Features",
+      "type":"map",
+      "desc":"List of important features/characteristics useful in comparing candidates.  'Political party' is an example of a candidate characteristic important while voting.  These features will be listed in a separate column from the candidates' names, and will be sortable.",
+      "user_key":"(feature identifier)",
+      "mapping":
+      {
+        "(feature identifier)":
+        {
+          "title":"Feature definition",
+          "type":"map",
+          "desc":"Parameters for a particular feature.",
+          "mapping":
+          {
+            "display_name":
+            {
+              "title":"display name",
+              "type":"str",
+              "desc":"The label for use in the column header."
+            },
+            "url_field":
+            {
+              "title":"url field",
+              "type":"str",
+              "desc":"A field identifier for an optional URL associated with a particular feature.  The identifier defined here can be used in the (candidate key) mapping defined above."
+            }
+          }
+        }
+      }
+    },
+    "inline_ballot_type":
+    {
+      "title":"Inline ballot type",
+      "type":"str",
+      "enum":
+      [
+        "range-array"
+      ],
+      "desc":"Type of ballots embedded inline"
+    },
+    "inline_ballots":
+    {
+      "title":"Inline ballots",
+      "type":"seq",
+      "desc":"Used to provide a set of ballots inline, rather than relying on an external source.",
+      "sequence":
+      [
+        {
+          "type":"map",
+          "title":"Batch of ballots",
+          "mapping":
+          {
+            "qty":
+            {
+              "title":"Quantity",
+              "type":"number",
+              "desc":"Number of votes",
+              "required":true
+            },
+            "vote":
+            {
+              "title":"vote",
+              "type":"map",
+              "desc":"set of ratings",
+              "user_key":"(candidate key)",
+              "mapping":
+              {
+                "(candidate key)":
+                {
+                  "title":"(candidate key)",
+                  "type":"number",
+                  "desc":"Rating for the specific candidate"
+                }
+              }
+            }
+          }
+        }
+      ]
+    },
+    "max_rating":
+    {
+      "title":"Maximum rating",
+      "desc":"Maximum rating that voters may assign to a candidate.  Not respected by all ballot types.",
+      "type":"number"
+    },
+    "min_rating":
+    {
+      "title":"Mininum rating",
+      "desc":"Maximum rating that voters may assign to a candidate.  Not respected by all ballot types.",
+      "type":"number"
+    },
+    "radioarray_labels":
+    {
+      "title":"radioarray labels",
+      "type":"map",
+      "desc":"Set of labels to use when the <code>'radioarray'</code> value for <code>ballot_type</code> is chosen.",
+      "user_key":"(rating value)",
+      "mapping":
+      {
+        "(rating value)":
+        {
+          "title":"Label for rating value",
+          "type":"str",
+          "desc":"label associated with this particular numerical rating."
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/electiontiny.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/electiontiny.json
new file mode 100644 (file)
index 0000000..0ea3fa2
--- /dev/null
@@ -0,0 +1,25 @@
+{
+  "candidates":
+  {
+    "Zadka":
+    {
+      "display_name":"Moshe Zadka"
+    },
+    "Garbee":
+    {
+      "display_name":"Bdale Garbee"
+    },
+    "Robinson":
+    {
+      "display_name":"Branden Robinson"
+    },
+    "Michlmayr":
+    {
+      "display_name":"Michael Michlmayr"
+    },
+    "NOTA":
+    {
+      "display_name":"None Of The Above"
+    }
+  }
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/example.php b/auf_savoirs_en_partage_django/media/js/jsonwidget/example.php
new file mode 100644 (file)
index 0000000..e1617d1
--- /dev/null
@@ -0,0 +1,237 @@
+<!-- Copyright (c) 2005 Rob Lanphier.
+See http://robla.net/2005/jsonwidget/LICENSE for license (BSD style)
+-->
+
+<?php
+
+$jsonfile = 'electiondata.json';
+$schemafile = 'electionschema.json';
+$schemaschemafile = 'schemaschema.json';
+switch($_GET['user']) {
+ case "advanced":
+     $enableschemaedit = true;
+     $debuglevel = 1;
+     break;
+ case "debug":
+     $enableschemaedit = true;
+     $debuglevel = 2;
+     break;
+}
+switch($_GET['sample']) {
+ case "large":
+     $schemafile = 'electionschema.json';
+     $jsonfile = 'electionlarge.json';
+     break;
+    
+ case "tiny":
+     $jsonfile = 'electiontiny.json';
+     break;
+     
+ case "blank":
+     $jsonfile = null;
+     break;
+
+ case "byexample":
+     $jsonfile = null;
+     $schemafile = 'openschema.json';
+     $byexample = true;
+     $enableschemaedit = true;
+     break;
+ case "schemaedit":
+     $jsonfile = null;
+     $schemafile = 'schemaschema.json';
+     break;
+ case "schemaschema":
+     $jsonfile = 'schemaschema.json';
+     $schemafile = 'schemaschema.json';
+     break;
+ case "electoschema":
+     $jsonfile = 'electionschema.json';
+     $schemafile = 'schemaschema.json';
+     break;
+ case "addressbookschema":
+     $jsonfile = 'addressbookschema.json';
+     $schemafile = 'schemaschema.json';
+     break;
+ case "openschema":
+     $jsonfile = null;
+     $schemafile = 'openschema.json';
+     break;
+ case "blankaddr":
+     $jsonfile = null;
+     $schemafile = 'addressbookschema.json';
+     break;
+ case "normal":
+ default:
+     $jsonfile = 'electionnormal.json';
+     break;
+}
+
+
+
+?>
+
+<html>
+<head>
+<title>JSON widget prototype</title>
+
+
+<script src="json.js"></script> 
+<script src="jsonedit.js"></script> 
+
+<link rel="stylesheet" type="text/css" href="jsonwidget.css" />
+
+<script type="text/javascript" language="javascript">
+
+function sample_init() {
+    var je=new jsonwidget.editor();
+
+    //default values for ids are in script, but can be overridden.
+    //For example, to set the formdiv id to something other than
+    //"je_formdiv", add the following line:
+    //je.htmlids.formdiv = "myveryownformdiv";
+    
+    <?php if($debuglevel > 1) { ?>
+    je.debuglevel = <?php print $debuglevel.';';
+    } ?>
+
+    <?php if($enableschemaedit) { ?>
+    je.views = ['form','source','schemaform','schemasource'];
+    je.schemaEditInit();
+    <?php } ?>
+
+    <?php if($byexample) { ?>
+    je.byExampleInit();
+    <?php } ?>
+
+
+    je.setView('form');
+}
+
+</script>
+
+</head>
+<?php
+if($_POST['jsonsubmit'] != 'true') {
+    $onload = ' onload="sample_init();"';
+}
+?>
+
+<body<?php print $onload?>>
+
+<?php
+if($_POST['jsonsubmit'] != 'true') {
+    //this encapsulates most of this page
+?>
+<div id="je_warningdiv">
+</div>
+
+<div>
+<span id="je_formbutton" style="cursor: pointer">[Edit w/Form]</span>
+<span id="je_sourcebutton" style="cursor: pointer">[Edit Source]</span>
+<?php if($enableschemaedit) { ?>
+<span id="je_schemaformbutton" style="cursor: pointer">[Edit Schema w/Form]</span>
+<span id="je_schemasourcebutton" style="cursor: pointer">[Edit Schema Source]</span>
+<?php } ?>
+</div>
+
+
+<div id="je_formdiv" style="text-background: white">
+</div>
+
+<div>
+
+<div id="je_schemaformdiv" style="text-background: white">
+</div>
+
+<textarea id="je_schematextarea" style="display: none" rows="30" cols="80">
+<?php 
+if($schemafile != null) {
+    readfile($schemafile);
+}
+?>
+</textarea>
+
+<form method='POST' id="je_sourcetextform">
+<textarea id="je_sourcetextarea" rows="30" cols="80" name="sourcearea">
+<?php 
+if($jsonfile != null) {
+    readfile($jsonfile);
+}
+?>
+</textarea>
+<p>
+<input type="hidden" name="jsonsubmit" value="true"/>
+      <input type="submit" value="Submit JSON"/> - WARNING: submitting your form data ends your editing session.  This merely illustrates what your data looks like on the server side.
+</p>
+</form>
+
+</div>
+
+<?php if($enableschemaedit) { ?>
+<textarea id="je_schemaschematextarea" style="display: none" rows="30" cols="80" name="sourcearea">
+<?php 
+if($schemaschemafile != null) {
+    readfile($schemaschemafile);
+}
+?>
+</textarea>
+<?php } ?>
+
+
+<div>
+
+<form submit="example.php" method="GET">
+<fieldset><legend>Demo options</legend>
+JSON sample: 
+<select name="sample" type="text">
+<option value="normal">Election - typical</option>
+<option value="byexample">Create a schema by example</option>
+<option value="openschema">Freeform JSON</option>
+<option value="blankaddr">Address book - blank</option>
+<option value="blank">Election - blank</option>
+<option value="tiny">Election - minimal</option>
+<option value="large">Election - large(ish) data set</option>
+<option value="schemaedit">Edit a new schema</option>
+<option value="electoschema">Edit the election configuration schema</option>
+<option value="addressbookschema">Edit the address book schema</option>
+<option value="schemaschema">Edit the schema for schemas</option>
+</select>
+<br/>
+User type: 
+<select name="user" type="text">
+<option>normal</option>
+<option default>advanced</option>
+<option>debug</option>
+</select>
+<br/>
+<input value="Change demo" type="submit">
+</fieldset>
+</form>
+
+</div>
+<textarea style="display: none;" id="rawhtml" rows="30" cols="80">
+</textarea>
+
+<?php 
+}
+else {
+    //this means $_POST['jsonsubmit'] == 'true'
+    require_once('JSON.php');
+    $rawjson = $_POST['sourcearea'];
+    
+    $json = new Services_JSON(JSON_LOOSE_TYPE);
+    $jsondata = $json->decode(stripslashes($rawjson));
+
+    print "Data structure as parsed and output by PHP's print_r:<br>";
+    print '<textarea  rows="30" cols="80">';
+    print_r($jsondata);
+    print "</textarea>";
+}
+?>
+
+</body>
+</html>
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/index.html b/auf_savoirs_en_partage_django/media/js/jsonwidget/index.html
new file mode 100644 (file)
index 0000000..67900cd
--- /dev/null
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
+  <title>JSONwidget</title>
+</head>
+<body>
+<h2>JSONwidget</h2>
+<h3>An automatic form generator/editor for JSON in Javascript</h3>
+<h3>News:</h3>
+<ul>
+  <li><span style="font-weight: bold;">2005-12-01</span> &nbsp;-
+&nbsp;JSONwidget 0.1.0 release. &nbsp;Current version has only been
+tested with Firefox 1.0.7. &nbsp;Known to be very buggy in IE and
+Opera, if it works at all. &nbsp;(Heck, it's pretty buggy in Firefox,
+still).<br>
+  </li>
+</ul>
+<h3>About</h3>
+JSONwidget is a Javascript library implementing a basic HTML form
+interface for editing arbitrary JSON files. &nbsp;Application designers
+using this library have the option of providing a schema, limiting the
+input to a subset of valid JSON compatible with whatever application is
+actually consuming the JSON, or using a provided permissive schema that
+allows any valid JSON. &nbsp;The form is dynamically generated using
+nothing more than a schema and a JSON file as input.<br>
+<br>
+The library is licensed under a <a href="LICENSE">BSD-style license</a>, making the licensing very flexible for many different applications.<br>
+<h3>Demos</h3>
+<ul>
+  <li><a href="example.php">Election Configuration Editor</a> - this was the original application I wrote this for (to be integrated into <a href="http://electorama.com/electowidget">Electowidget</a>). &nbsp;It allows for flexible editing of a rather complex configuration file. &nbsp;See also <a href="example.php?sample=normal&amp;user=advanced">the view with schema editing enabled</a>.</li>
+  <li><a href="example.php?sample=openschema&amp;user=normal">Freeform JSON editor</a> - any valid JSON file (sans comments) can be modified</li>
+  <li><a href="example.php?sample=byexample&amp;user=normal">Create schema by example</a> - a freeform JSON editor with the ability to generate a schema from the source</li>
+</ul>
+Other demos are available via selection box at the bottom of the&nbsp;examples above.<br>
+<br>
+<h3>Acknowledgements</h3>
+This assembles a lot of code and ideas from other sources. &nbsp;<br>
+<ul>
+  <li>json.js - a modified, outdated version of <a href="http://json.org">Douglas Crockford's library</a>
+, which allows for nicely formated JSON. &nbsp;My apologies to Mr.
+Crockford for the butchered, forked version - I plan to work on a
+cleaner patch for later submission.</li>
+  <li>Schema language inspired by and mostly compatible with the JSON version of <a href="http://www.kuwata-lab.com/kwalify/">Kwalify</a> by&nbsp;Makoto Kuwata.</li>
+  <li>JSON.php by Michal Migurski and others. &nbsp;This is provided as originally distributed.</li>
+  <li>I'm certain there are others.</li>
+</ul>
+<h3>Download</h3>
+A tarball with everything used to create this demo is below:<br>
+<ul>
+  <li><a href="downloads/JSONwidget_0.1.0.tar.gz">JSONwidget 0.1.0</a></li>
+</ul>
+<hr style="width: 100%; height: 2px;"><span style="font-style: italic;">Copyright (c) 2005</span>&nbsp;<a style="font-style: italic;" href="http://robla.net">Rob Lanphier</a>
+</body>
+</html>
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/json.js b/auf_savoirs_en_partage_django/media/js/jsonwidget/json.js
new file mode 100644 (file)
index 0000000..370a650
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+Modified "pretty printing" JSON.js
+
+Copyright (c) 2005 JSON.org
+Pretty printing modifications Copyright (c) 2005 Rob Lanphier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+var JSON = {
+    org: 'http://www.JSON.org',
+    copyright: '(c)2005 JSON.org',
+    license: 'http://www.crockford.com/JSON/license.html',
+
+    indent_level: 0,
+    str_repeat: function (str, rep) {
+        var retval='';
+        for(var i=0;i<rep;i++) 
+        {
+            retval+=str;
+        };
+        return retval;
+    },
+    stringify: function (arg) {
+        var c, i, l, s = '', v;
+
+        switch (typeof arg) {
+        case 'object':
+            var out_indent = this.str_repeat("  ", this.indent_level);
+            this.indent_level++;
+            var indent = this.str_repeat("  ", this.indent_level);
+
+            if (arg) {
+                if (arg instanceof Array) {
+                    for (i = 0; i < arg.length; ++i) {
+                        if(typeof arg[i] == 'object') {
+                            v = this.stringify(arg[i]);
+                        }
+                        else {
+                            v = indent + this.stringify(arg[i]);
+                        }
+                        if (s) {
+                            s += ',\n';
+                        }
+                        s += v;
+                    }
+                    this.indent_level--;
+                    return out_indent+'[\n' + s + "\n" + out_indent+']';
+                } else if (typeof arg.toString != 'undefined') {
+                    for (i in arg) {
+                        v = arg[i];
+                        if (typeof v != 'undefined' && typeof v != 'function') {
+                            v = this.stringify(v);
+                            if (s) {
+                                s += ',\n';
+                            }
+                            if(typeof arg[i] == 'object') {
+                                s += indent + this.stringify(i) + ':\n' + v;
+                            }
+                            else {
+                                s += indent + this.stringify(i) + ':' + v;
+                            }
+                        }
+                    }
+                    this.indent_level--;
+                    return out_indent+'{\n' + s + '\n'+out_indent+'}';
+                }
+            }
+            this.indent_level--;
+            return 'null';
+        case 'number':
+            return isFinite(arg) ? String(arg) : 'null';
+        case 'string':
+            l = arg.length;
+            s = '"';
+            for (i = 0; i < l; i += 1) {
+                c = arg.charAt(i);
+                if (c >= ' ') {
+                    if (c == '\\' || c == '"') {
+                        s += '\\';
+                    }
+                    s += c;
+                } else {
+                    switch (c) {
+                        case '\b':
+                            s += '\\b';
+                            break;
+                        case '\f':
+                            s += '\\f';
+                            break;
+                        case '\n':
+                            s += '\\n';
+                            break;
+                        case '\r':
+                            s += '\\r';
+                            break;
+                        case '\t':
+                            s += '\\t';
+                            break;
+                        default:
+                            c = c.charCodeAt();
+                            s += '\\u00' + Math.floor(c / 16).toString(16) +
+                                (c % 16).toString(16);
+                    }
+                }
+            }
+            return s + '"';
+        case 'boolean':
+            return String(arg);
+        default:
+            return 'null';
+        }
+    },
+    parse: function (text) {
+        var at = 0;
+        var ch = ' ';
+
+        function error(m) {
+            throw {
+                name: 'JSONError',
+                message: m,
+                at: at - 1,
+                text: text
+            };
+        }
+
+        function next() {
+            ch = text.charAt(at);
+            at += 1;
+            return ch;
+        }
+
+        function white() {
+            while (ch !== '' && ch <= ' ') {
+                next();
+            }
+        }
+
+        function str() {
+            var i, s = '', t, u;
+
+            if (ch == '"') {
+outer:          while (next()) {
+                    if (ch == '"') {
+                        next();
+                        return s;
+                    } else if (ch == '\\') {
+                        switch (next()) {
+                        case 'b':
+                            s += '\b';
+                            break;
+                        case 'f':
+                            s += '\f';
+                            break;
+                        case 'n':
+                            s += '\n';
+                            break;
+                        case 'r':
+                            s += '\r';
+                            break;
+                        case 't':
+                            s += '\t';
+                            break;
+                        case 'u':
+                            u = 0;
+                            for (i = 0; i < 4; i += 1) {
+                                t = parseInt(next(), 16);
+                                if (!isFinite(t)) {
+                                    break outer;
+                                }
+                                u = u * 16 + t;
+                            }
+                            s += String.fromCharCode(u);
+                            break;
+                        default:
+                            s += ch;
+                        }
+                    } else {
+                        s += ch;
+                    }
+                }
+            }
+            error("Bad string");
+        }
+
+        function arr() {
+            var a = [];
+
+            if (ch == '[') {
+                next();
+                white();
+                if (ch == ']') {
+                    next();
+                    return a;
+                }
+                while (ch) {
+                    a.push(val());
+                    white();
+                    if (ch == ']') {
+                        next();
+                        return a;
+                    } else if (ch != ',') {
+                        break;
+                    }
+                    next();
+                    white();
+                }
+            }
+            error("Bad array");
+        }
+
+        function obj() {
+            var k, o = {};
+
+            if (ch == '{') {
+                next();
+                white();
+                if (ch == '}') {
+                    next();
+                    return o;
+                }
+                while (ch) {
+                    k = str();
+                    white();
+                    if (ch != ':') {
+                        break;
+                    }
+                    next();
+                    o[k] = val();
+                    white();
+                    if (ch == '}') {
+                        next();
+                        return o;
+                    } else if (ch != ',') {
+                        break;
+                    }
+                    next();
+                    white();
+                }
+            }
+            error("Bad object");
+        }
+
+        function num() {
+            var n = '', v;
+            if (ch == '-') {
+                n = '-';
+                next();
+            }
+            while (ch >= '0' && ch <= '9') {
+                n += ch;
+                next();
+            }
+            if (ch == '.') {
+                n += '.';
+                while (next() && ch >= '0' && ch <= '9') {
+                    n += ch;
+                }
+            }
+            if (ch == 'e' || ch == 'E') {
+                n += 'e';
+                next();
+                if (ch == '-' || ch == '+') {
+                    n += ch;
+                    next();
+                }
+                while (ch >= '0' && ch <= '9') {
+                    n += ch;
+                    next();
+                }
+            }
+            v = +n;
+            if (!isFinite(v)) {
+                error("Bad number");
+            } else {
+                return v;
+            }
+        }
+
+        function word() {
+            switch (ch) {
+                case 't':
+                    if (next() == 'r' && next() == 'u' && next() == 'e') {
+                        next();
+                        return true;
+                    }
+                    break;
+                case 'f':
+                    if (next() == 'a' && next() == 'l' && next() == 's' &&
+                            next() == 'e') {
+                        next();
+                        return false;
+                    }
+                    break;
+                case 'n':
+                    if (next() == 'u' && next() == 'l' && next() == 'l') {
+                        next();
+                        return null;
+                    }
+                    break;
+            }
+            error("Syntax error");
+        }
+
+        function val() {
+            white();
+            switch (ch) {
+                case '{':
+                    return obj();
+                case '[':
+                    return arr();
+                case '"':
+                    return str();
+                case '-':
+                    return num();
+                default:
+                    return ch >= '0' && ch <= '9' ? num() : word();
+            }
+        }
+
+        return val();
+    }
+};
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/jsonedit.js b/auf_savoirs_en_partage_django/media/js/jsonwidget/jsonedit.js
new file mode 100644 (file)
index 0000000..52efb4d
--- /dev/null
@@ -0,0 +1,1381 @@
+// Copyright (c) 2005 Rob Lanphier.
+// See http://robla.net/2005/jsonwidget/LICENSE for license (BSD style)
+
+var language = 'fr';
+var intl = {
+    'fr': {'help': 'aide',
+        'no': 'non',
+        'yes': 'oui',
+        'del': 'suppr',
+        'hide': 'masquer',
+        'show': 'afficher',
+        'delete': 'supprimer',
+        'Root node': 'Racine',
+        'Add property': 'Ajouter un attribut',
+        'Add ': 'Ajouter un ',
+        ' to ': ' a ',
+    },
+};
+function _(s) {
+    rc = s
+    if (typeof(intl[language])!='undefined' && intl[language][s]) {
+        rc = intl[language][s];
+    }
+    return rc;
+}
+
+var jsonwidget = function() {}
+
+jsonwidget.stringToId = function (str) {
+    // performs the easiest transformation to safe id, but is lossy
+    if((typeof str)=='number') {
+        return str.toString();
+    }
+    else if ((typeof str)=='string') {
+        return str.replace(/[^a-z0-9\-_:\.]/gi, "");
+    }
+    else error();
+}
+
+jsonwidget.getTitleFromNode = function (schemanode, nodeindex) {
+    if(undefined != schemanode.title) {
+        return schemanode.title;
+    }
+    else {
+        return nodeindex;
+    }
+}
+
+jsonwidget.getNewValueForType = function(thistype) {
+    switch(thistype) {
+    case 'map':
+        var newvalue = new Object();
+        break;
+        
+    case 'seq':
+        var newvalue = new Array();
+        break;
+
+    case 'number':
+    case 'int':
+        var newvalue = 0;
+        break;
+
+    case 'str':
+    case 'text':
+        var newvalue = "";
+        break;
+
+    case 'bool':
+        var newvalue = false;
+        break;
+    default:
+        var newvalue = null;
+        break;
+    }
+    return newvalue;
+}
+
+
+jsonwidget.getType = function (foo) {
+    if(foo==null) {
+        return undefined;
+    }
+
+    switch(typeof foo) {
+        case "object":
+        if(foo.constructor == Array) {
+            return "seq";
+        }
+        else {
+            return "map";
+        }
+        break;
+        
+        case "number":
+        return "number";
+        break;
+        
+        case "boolean":
+        return "bool";
+        break;
+        
+        case "string":
+        return "str";
+        break;
+        
+        default:
+        return undefined;
+        break;
+    }
+}
+
+jsonwidget.getSchemaArray = function (parent) {
+    var schema = new Object();
+
+    schema.type = jsonwidget.getType(parent);
+    
+    switch (schema.type) {
+    case 'map':
+        schema.mapping = new Object();
+        for (var name in parent) {
+            schema.mapping[name]= jsonwidget.getSchemaArray(parent[name]);
+        }
+        break;
+    case 'seq':
+        schema.sequence = new Array();
+        schema.sequence[0] = jsonwidget.getSchemaArray(parent[0]);
+        break;
+    }
+    return schema;
+}
+
+jsonwidget.treeRef = function (node, parent, nodeindex, nodename) {
+    this.node = node;
+    this.parent = parent;
+    this.nodeindex = nodeindex;
+    this.nodename = nodename;
+}
+
+//
+// jsonTreeRef object
+//
+// not yet bothering to make this a subclass of treeRef
+jsonwidget.jsonTreeRef = function (node, parent, nodeindex, nodename, schemaref) {
+    this.node = node;
+    this.parent = parent;
+    this.nodeindex = nodeindex;
+    this.nodename = nodename;
+    this.schemaref = schemaref;
+
+    this.init = jsonwidget.jsonTreeRef.init;
+    this.isUserKey = jsonwidget.jsonTreeRef.isUserKey;
+    this.renamePropname = jsonwidget.jsonTreeRef.renamePropname;
+    this.getType = jsonwidget.jsonTreeRef.getType;
+    this.getTitle = jsonwidget.jsonTreeRef.getTitle;    
+    this.getFullIndex = jsonwidget.jsonTreeRef.getFullIndex;    
+    this.attachSchema = jsonwidget.jsonTreeRef.attachSchema;
+
+    this.init();
+}
+
+
+jsonwidget.jsonTreeRef.init = function () {
+    this.fullindex = this.getFullIndex();
+    this.attachSchema();
+}
+
+jsonwidget.jsonTreeRef.attachSchema = function () {
+    if(this.schemaref.node.type == 'any') {
+        if(this.getType()=='map') {
+            this.schemaref.node.mapping = { 
+                "extension": {
+                    "title":"extension field", 
+                    "type":"any"
+                }
+            };
+            this.schemaref.node.user_key = "extension";
+        }
+        else if(this.getType()=='seq') {
+            this.schemaref.node.sequence = [ 
+                    {
+                        "title":"extension field", 
+                        "type":"any"
+                    }
+            ];
+            this.schemaref.node.user_key = "extension";
+        }
+    }
+}
+
+jsonwidget.jsonTreeRef.getTitle = function () {
+    if(undefined != this.nodename) {
+        return this.nodename;
+    }
+    else {
+        return jsonwidget.getTitleFromNode(this.node, this.nodeindex);
+    }
+}
+
+jsonwidget.jsonTreeRef.isUserKey = function () {
+    return this.userkeyflag;
+}
+
+jsonwidget.jsonTreeRef.renamePropname = function (newindex) {
+    var oldindex = this.nodeindex;
+    this.parent.node[newindex] = this.node;
+    
+    this.nodeindex = newindex;
+    this.nodename = newindex;
+    this.fullindex = this.getFullIndex();
+
+    delete this.parent.node[oldindex];
+}
+
+jsonwidget.jsonTreeRef.getType = function () {
+    var nodetype = this.schemaref.node.type;
+    if(nodetype == 'any') {
+        if(this.node == undefined) {
+            return undefined;
+        }
+        else {
+            return jsonwidget.getType(this.node);
+        }
+    }
+    else {
+        return nodetype;
+    }
+}
+
+jsonwidget.jsonTreeRef.getFullIndex = function () {
+    if(this.parent==undefined) {
+        return "json_root";
+    }
+    else {
+        return this.parent.getFullIndex() + "." + jsonwidget.stringToId(this.nodeindex);
+    }
+}
+
+
+//
+// schemaIndex object
+//
+
+jsonwidget.schemaIndex = function (schema) {
+    this.root = schema;
+    this.idtable = {};
+    this.debugwindow = document.getElementById("je_warningdiv");
+
+    if(!this.root) {
+        return null;
+    }
+    this.indexSubtree = jsonwidget.schemaIndex.indexSubtree;
+    this.newRef = jsonwidget.schemaIndex.newRef;
+
+    this.indexSubtree(this.root);
+}
+
+jsonwidget.schemaIndex.indexSubtree = function (schemanode) {
+    var nodetype = schemanode.type;
+    
+    switch(nodetype) {
+    case 'map':
+        for(var i in schemanode.mapping) {
+            this.indexSubtree(schemanode.mapping[i]);
+        }
+        break;
+    case 'seq':
+        for(var i in schemanode.sequence) {
+            this.indexSubtree(schemanode.sequence[i]);
+        }
+        break;
+    }
+
+    if(undefined != schemanode.id) {
+        this.idtable[schemanode.id] = schemanode;
+    }
+}
+
+jsonwidget.schemaIndex.newRef = function (node, parent, nodeindex, nodename) {
+    if(node.type == 'idref') {
+        node =  this.idtable[node.idref];
+    }
+    return new jsonwidget.treeRef(node, parent, nodeindex, nodename);
+}
+
+
+//
+// editor object
+//
+
+jsonwidget.editor = function () {
+    this.buffer = new Array();
+    this.bufferTree = document.createElement("div");
+    this.bufferCurrent = this.bufferTree;
+        
+    this.jsonLookupById = new Array();
+    this.bgcolor = "#f0f0ff";
+
+    //override if you want to use different ids
+    this.htmlids = {
+        "warningdiv": "je_warningdiv",
+        "formdiv": "je_formdiv",
+        "schemaformdiv": "je_schemaformdiv",
+        "sourcetextarea": "je_sourcetextarea",
+        "schematextarea": "je_schematextarea",
+        "schemaschematextarea": "je_schemaschematextarea",
+        "byexamplebutton": "je_byexamplebutton",
+        "sourcetextform": "je_sourcetextform"
+    }
+    this.debuglevel=0;
+
+    this.views = ['form','source'];
+    this.formview = 'form';
+
+       this.showByExampleButton = false;
+
+    this.htmlbuttons = {
+        form: "je_formbutton",
+        source: "je_sourcebutton",
+        schemasource: "je_schemasourcebutton",
+        schemaform: "je_schemaformbutton"
+    }
+    
+    this.classname = {
+        fgbutton: "je_foreground",
+        bgbutton: "je_background"
+    }
+
+    this.formdiv = document.getElementById(this.htmlids.formdiv);
+
+    this.showForm = jsonwidget.editor.showForm;
+    this.clearForm = jsonwidget.editor.clearForm;
+    this.attachHandlers = jsonwidget.editor.attachHandlers;
+    this.setNode = jsonwidget.editor.setNode;
+    this.updateNode = jsonwidget.editor.updateNode;
+    this.deleteNode = jsonwidget.editor.deleteNode;
+    this.getArrayInputAttrs = jsonwidget.editor.getArrayInputAttrs;
+    this.getHelpButton = jsonwidget.editor.getHelpButton;
+    this.getShowButton = jsonwidget.editor.getShowButton;
+    this.getAddToSeqButton = jsonwidget.editor.getAddToSeqButton;
+    this.getHideButton = jsonwidget.editor.getHideButton;
+    this.getDeleteButton = jsonwidget.editor.getDeleteButton;
+    this.addPropToMapping = jsonwidget.editor.addPropToMapping;
+    this.getAddButton = jsonwidget.editor.getAddButton;
+    this.attachArrayInput = jsonwidget.editor.attachArrayInput;
+    this.showPropnameInput = jsonwidget.editor.showPropnameInput;
+    this.getPropnameSpan = jsonwidget.editor.getPropnameSpan;
+    this.attachSimplePropertyInput = jsonwidget.editor.attachSimplePropertyInput;
+    this.getStringInput = jsonwidget.editor.getStringInput;
+    this.getBoolInput = jsonwidget.editor.getBoolInput;
+    this.getNumberInput = jsonwidget.editor.getNumberInput;
+    this.getTypeSelectInput = jsonwidget.editor.getTypeSelectInput;
+    this.attachNodeInput = jsonwidget.editor.attachNodeInput;
+    this.getSetViewFunction = jsonwidget.editor.getSetViewFunction;
+    this.setView = jsonwidget.editor.setView;
+    this.getStatusLightDelay = jsonwidget.editor.getStatusLightDelay;
+    this.setStatusLight = jsonwidget.editor.setStatusLight;
+    this.clearStatusLight = jsonwidget.editor.clearStatusLight;
+    this.toggleToFormActual = jsonwidget.editor.toggleToFormActual;
+    this.updateJSON = jsonwidget.editor.updateJSON;
+    this.error = jsonwidget.editor.error;
+    this.debugOut = jsonwidget.editor.debugOut;
+    this.warningOut = jsonwidget.editor.warningOut;
+    this.clearWarnings = jsonwidget.editor.clearWarnings;
+    this.contextHelp = jsonwidget.editor.contextHelp;
+    this.confirmDelete = jsonwidget.editor.confirmDelete;
+    this.getSchema = jsonwidget.editor.getSchema;
+    this.schemaEditInit = jsonwidget.editor.schemaEditInit;
+    this.byExampleInit = jsonwidget.editor.byExampleInit;
+    this.createSchemaFromExample = jsonwidget.editor.createSchemaFromExample;
+    this.attachByExampleText = jsonwidget.editor.attachByExampleText;
+    this.setFormOnSubmit = jsonwidget.editor.setFormOnSubmit;
+}
+
+jsonwidget.editor.schemaEditInit = function () {
+    this.schemaedit = new jsonwidget.editor();
+    var je = this;
+    this.schemaedit.setView = function (viewtoset) {
+        je.setView(viewtoset);
+    }
+    this.schemaedit.setStatusLight = function (statustext) {
+        je.setStatusLight(statustext);
+    }
+    this.schemaedit.clearStatusLight = function () {
+        je.clearStatusLight();
+    }
+    this.schemaedit.getStatusLightDelay = function (jsonref) {
+        return je.getStatusLightDelay(jsonref);
+    }
+    this.schemaedit.formview = 'schemaform';
+    this.schemaedit.htmlids.formdiv = this.htmlids.schemaformdiv;
+    this.schemaedit.htmlids.sourcetextarea = this.htmlids.schematextarea;
+    this.schemaedit.htmlids.schematextarea = this.htmlids.schemaschematextarea;
+}
+
+jsonwidget.editor.byExampleInit = function () {
+       this.showByExampleButton = true;
+}
+
+jsonwidget.editor.createSchemaFromExample = function () {
+    this.updateJSON();
+    if(this.jsondata == null) {
+        alert("I can't generate a very interesting schema from a blank document.  Try adding a little something to your JSON first");
+    }
+    else {
+        this.schemaedit.jsondata = jsonwidget.getSchemaArray(this.jsondata);
+        this.showByExampleButton = false;
+        this.schemaedit.updateJSON();
+        this.setView(this.formview);
+    }
+}
+
+jsonwidget.editor.attachByExampleText = function () {
+    var examplebutton = document.createElement('span');
+    var je = this;
+    examplebutton.id = this.htmlids.byexamplebutton;
+    examplebutton.style.cursor = "pointer";
+    examplebutton.appendChild(document.createTextNode("[Create schema by example]"));
+    examplebutton.onclick = function () {
+        je.createSchemaFromExample();
+    }
+
+    this.formdiv.appendChild(examplebutton);
+    this.formdiv.appendChild(document.createTextNode(" - clicking this button will generate a schema based on the current JSON file, and load it into the schema area.  It will also lock the current document into its current structure."));
+}
+
+jsonwidget.editor.showForm = function (formnode) {
+    this.formdiv.appendChild(formnode);
+    formnode.style.background = "#ffffff";
+    this.formdiv.style.display="inline";
+}
+
+jsonwidget.editor.clearForm = function () {
+    var parent = this.formdiv.parentNode;
+    var nextsibling = this.formdiv.nextSibling;
+    parent.removeChild(this.formdiv);
+    this.formdiv.innerHTML = "";
+    parent.insertBefore(this.formdiv, nextsibling);
+}
+
+jsonwidget.editor.attachHandlers = function () {
+    var jsoneditobj = this;
+    //document.body.style.background = jsoneditobj.bgcolor;
+    this.formdiv.onchange = function (event) {
+        if(event.target.className == "jeclass") {
+            var jsonnode = jsoneditobj.jsonLookupById[event.target.id.substr(8)];
+            var nodetype = jsonnode.getType();
+
+            if(nodetype == undefined) {
+                var value=jsonwidget.getNewValueForType(event.target.value);
+                jsonnode.node = value;
+                jsoneditobj.updateNode(jsonnode);
+            }
+            else {
+                if(nodetype == 'str' || nodetype == 'text') {
+                    var value = event.target.value;
+                }
+                else if(nodetype == 'number' || nodetype == 'int') {
+                    var value = parseInt(event.target.value);
+                }
+                else if(nodetype == 'bool') {
+                    var value = event.target.checked;
+                }
+                        
+                jsonnode.node = value;
+                if(jsonnode.parent != undefined) {
+                    jsonnode.parent.node[jsonnode.nodeindex] = value;
+                }
+                else {
+                    jsoneditobj.jsondata = value;
+                }
+            }
+        }
+    }
+
+    this.formdiv.onclick = function (event) {
+        var target = window.event ? window.event.srcElement : event.target;
+        if(target.className == "rmx") {
+            var jsonnode = jsoneditobj.jsonLookupById[target.id.substr(9)];
+            jsonwidget.editor.confirmDelete(jsoneditobj, jsonnode, target);
+        }
+        if(target.className == "je_hide") {
+            var nodeid = target.id.substr("hide".length+1);
+            document.getElementById("contents."+nodeid).style.display="none";
+            document.getElementById("hide."+nodeid).style.display="none";
+            document.getElementById("show."+nodeid).style.display="inline";
+        }
+        if(target.className == "je_show") {
+            var nodeid = target.id.substr("show".length+1);
+            document.getElementById("contents."+nodeid).style.display="inline";
+            document.getElementById("hide."+nodeid).style.display="inline";
+            document.getElementById("show."+nodeid).style.display="none";
+        }
+        if(target.className == "je_help") {
+            var jsonnode = jsoneditobj.jsonLookupById[target.id.substr("help".length+1)];
+            jsonwidget.editor.contextHelp(event, jsonnode);
+        }
+    }
+}
+
+jsonwidget.editor.setNode = function (jsonnode, value) {
+    if(jsonnode.parent != undefined) {
+        jsonnode.parent.node[jsonnode.nodeindex] = value;
+    }
+    else {
+        this.jsondata = value;
+    }
+}
+
+jsonwidget.editor.updateNode = function (jsonnode) {
+    var value = jsonnode.node;
+    if(jsonnode.parent != undefined) {
+        jsonnode.parent.node[jsonnode.nodeindex] = value;
+        jsonnode.attachSchema();
+
+        var rownode = document.createElement("tr");
+        jsonnode.domparent.parentNode.replaceChild(rownode, jsonnode.domparent);
+        jsonnode.domparent = rownode;
+
+        var je = this;
+        this.setStatusLight("working...");
+        setTimeout(function () {je.attachNodeInput(jsonnode);je.clearStatusLight();},this.getStatusLightDelay(jsonnode));
+    }
+    else {
+        this.jsondata = value;
+        this.updateJSON();
+        this.setView(this.formview);
+    }
+}
+
+jsonwidget.editor.deleteNode = function (jsonindex) {
+    var jsonnode = this.jsonLookupById[jsonindex];
+    var parent = jsonnode.parent;
+    jsonnode.domparent.parentNode.removeChild(jsonnode.domparent);
+    if(parent != undefined) {
+        if (parent.node instanceof Array) {
+            parent.node.splice(jsonnode.nodeindex,1);
+        }
+        else {
+            delete parent.node[jsonnode.nodeindex];
+        }
+        delete this.jsonLookupById[jsonindex];
+        this.updateNode(parent);
+    }
+    else {
+        this.jsondata = null;
+        delete this.jsonLookupById[jsonindex];
+        this.updateJSON();
+        this.setView(this.formview);
+    }
+}
+
+
+
+
+
+jsonwidget.editor.getArrayInputAttrs = function (jsonref) {
+    var jsoni;
+    var schemai;
+
+    var contentsid='contents.'+jsonref.fullindex;
+    var jsoneditobj = this;
+
+    var retval = document.createElement("table");
+
+    retval.id=contentsid;
+
+    var tbody = document.createElement("tbody");
+
+    for(var i in jsonref.node) {
+        var rownode = document.createElement("tr");
+        if(jsonref.getType()=='map') {
+            var nodename = i;
+            if(jsonref.schemaref.node.mapping[i]==undefined) {
+                if(jsonref.schemaref.node.user_key==undefined) {
+                    this.warningOut("warning: unrecognized key: "+i+"<br/>");
+                    continue;
+                }
+                else {
+                    var userkeyflag = true;
+                    var j = jsonref.schemaref.node.user_key;
+                    schemai = this.schemaindex.newRef(jsonref.schemaref.node.mapping[j], jsonref.schemaref, j, j);
+                }
+            }
+            else {
+                var userkeyflag = false;
+                nodename = jsonwidget.getTitleFromNode(jsonref.schemaref.node.mapping[i], i);
+                schemai = this.schemaindex.newRef(jsonref.schemaref.node.mapping[i], jsonref.schemaref, i, i);
+
+            }
+            jsoni = new jsonwidget.jsonTreeRef(jsonref.node[i], jsonref, i, nodename, schemai);
+        }
+        else if (jsonref.getType()=='seq') {
+            schemai = this.schemaindex.newRef(jsonref.schemaref.node.sequence[0], jsonref.schemaref, 0, i);
+            jsoni = new jsonwidget.jsonTreeRef(jsonref.node[i], jsonref, i, i, schemai);
+        }
+        jsoni.userkeyflag = userkeyflag;
+        jsoni.domparent = rownode;
+        this.jsonLookupById[jsoni.fullindex]=jsoni;
+        this.attachNodeInput(jsoni);
+        tbody.appendChild(rownode);
+    }
+    if(jsonref.getType()=='map') {
+        var schemap = jsonref.schemaref.node.mapping;
+        for(var i in schemap) {
+            //this.debugOut(1, schemap[i].required);
+
+            if(jsonref.node[i]==undefined && schemap[i].required == true) {
+                var rownode = document.createElement("tr");
+                jsoni = this.addPropToMapping(jsonref, i);
+                jsoni.domparent = rownode;
+                this.attachNodeInput(jsoni);
+                tbody.appendChild(rownode);
+            }
+        }
+    }
+
+    retval.appendChild(tbody);
+    return retval;
+}
+
+
+jsonwidget.editor.getHelpButton = function (jsonref) {
+    var helpid='help.'+jsonref.fullindex;
+    var retval = document.createElement("span");
+
+    retval.className="je_help";
+    retval.setAttribute("title", "help");
+    retval.id=helpid;
+    //retval.appendChild(document.createTextNode("["+_('help')+"]"));
+    return retval;
+}
+
+jsonwidget.editor.getHideButton = function (jsonref) {
+    var hideid='hide.'+jsonref.fullindex;
+    var retval = document.createElement("span");
+
+    retval.className="je_hide";
+    retval.setAttribute("title", "hide");
+    retval.id=hideid;
+    retval.appendChild(document.createTextNode("["+_("hide")+"]"));
+    return retval;
+}
+
+jsonwidget.editor.getShowButton = function (jsonref) {
+    var showid='show.'+jsonref.fullindex;
+    var retval = document.createElement("span");
+
+    retval.className="je_show";
+    retval.setAttribute("title", "show");
+    retval.id=showid;
+    retval.appendChild(document.createTextNode("["+_("show")+"]"));
+    retval.style.display = "none";
+    return retval;
+}              
+
+jsonwidget.editor.getDeleteButton = function (jsonref) {
+    var retval = document.createElement("span");
+    var rmid='rmbutton.'+jsonref.fullindex;
+
+    if(!jsonref.schemaref.node.required) {
+        retval.className="rmx";
+        retval.setAttribute("title", "delete");
+    }
+    else {
+        retval.className="je_disabled";
+        retval.setAttribute("title", "required attribute - deletion not allowed");
+    }
+    retval.id=rmid;
+    retval.appendChild(document.createTextNode("["+_("del")+"]"));
+    return retval;
+}            
+        
+
+jsonwidget.editor.addPropToMapping = function (jsonref, prop) {
+    var newname = prop;
+    var newindex = prop;
+    var schemap = jsonref.schemaref.node.mapping;
+
+    if(prop == jsonref.schemaref.node.user_key) {
+        newindexbase = jsonwidget.stringToId(prop);
+        for(var i=1;true;i++) {
+            newindex = newindexbase + "_" + i;
+            if(jsonref.node[newindex] == undefined) {
+                var nodenum = i;
+                newname = newindex;
+                break;
+            }
+        }
+    }
+    else {
+        newname = jsonwidget.getTitleFromNode(schemap[prop], prop);
+    }
+
+    var newschema = this.schemaindex.newRef(schemap[prop], jsonref.schemaref, prop, prop);
+    var newvalue = jsonwidget.getNewValueForType(newschema.node.type);
+    var newjson = new jsonwidget.jsonTreeRef(newvalue, jsonref, newindex, newname, newschema);
+    if (jsonref.node instanceof Array) {
+        jsonref.node.push(newvalue);
+    }
+    else {
+        jsonref.node[newindex]=newvalue;
+    }
+    this.jsonLookupById[newjson.fullindex]=newjson;
+    return newjson;
+}
+
+jsonwidget.editor.getAddButton = function (jsonref, prop) {
+    var schemap = jsonref.schemaref.node.mapping;
+    var je = this;
+    var addlink = document.createElement("a");
+    addlink.style.textDecoration = "underline";
+    addlink.style.cursor = "pointer";
+    addlink.onclick = function () {
+        je.addPropToMapping(jsonref, prop);
+        je.updateNode(jsonref);
+    }
+    addlink.appendChild(document.createTextNode(jsonwidget.getTitleFromNode(schemap[prop], prop)));
+    return addlink;
+}
+
+jsonwidget.editor.getAddToSeqButton = function (jsonref) {
+    var childschema = jsonref.schemaref.node.sequence[0];
+    var je = this;
+    var addlink = document.createElement("a");
+    var itemname = jsonwidget.getTitleFromNode(childschema, "item");
+    addlink.style.textDecoration = "underline";
+    addlink.style.cursor = "pointer";
+    addlink.onclick = function () {
+        var newname = 0;
+        var newindex = 0;
+        var newschema = je.schemaindex.newRef(childschema, jsonref.schemaref, 0, newindex);
+        var newvalue=jsonwidget.getNewValueForType(newschema.node.type);
+
+        var newjson = new jsonwidget.jsonTreeRef(newvalue, jsonref, newindex, newindex, newschema);
+        if (jsonref.node instanceof Array) {
+            jsonref.node.push(newvalue);
+        }
+        else {
+            jsonref.node[newindex]=newvalue;
+        }
+        je.jsonLookupById[newjson.fullindex]=newjson;
+        je.updateNode(jsonref);
+    }
+    var nodename = jsonref.getTitle();
+
+    addlink.appendChild(document.createTextNode(_("Add ")+ itemname + _(" to ") + nodename ));
+    return addlink;
+}
+
+jsonwidget.editor.attachArrayInput = function (jsonref) {
+    var retval = document.createElement("fieldset");
+    var localnode = document.createElement("legend");
+
+    if(jsonref.isUserKey()) {
+        localnode.appendChild(this.getPropnameSpan(jsonref));
+    }
+    else {
+        localnode.appendChild(document.createTextNode(jsonref.nodename));
+    }
+
+    retval.appendChild(localnode);
+
+    localnode = document.createElement("div");
+    localnode.className="je_topcontrols";
+    localnode.appendChild(this.getHelpButton(jsonref));
+    localnode.appendChild(this.getHideButton(jsonref));
+    localnode.appendChild(this.getShowButton(jsonref));
+    localnode.appendChild(this.getDeleteButton(jsonref));
+    retval.appendChild(localnode);
+
+    retval.appendChild(this.getArrayInputAttrs(jsonref));
+
+    if(jsonref.getType()=='map') {
+        var schemap = jsonref.schemaref.node.mapping;
+        var numprops = 0;
+        for(var i in schemap) {
+            if ((jsonref.node[i]==undefined || i == jsonref.schemaref.node.user_key)
+                && (schemap[i]['hidden'] != true)){
+                numprops++;
+                if(numprops == 1) {
+                    retval.appendChild(document.createTextNode(_("Add property")+": "));
+                }
+                else {
+                    retval.appendChild(document.createTextNode(", "));
+                }
+                retval.appendChild(this.getAddButton(jsonref,i));
+            }
+        }
+    }
+    if(jsonref.getType()=='seq') {
+        retval.appendChild(this.getAddToSeqButton(jsonref));
+    }            
+    //wrap it all in a td
+    if(jsonref.domparent.tagName == 'TR') {
+        localnode = retval;
+        retval = document.createElement("td");
+        retval.setAttribute("colspan", 3);
+        retval.appendChild(localnode);
+    }
+    jsonref.domparent.appendChild(retval);
+}
+
+jsonwidget.editor.showPropnameInput = function (jsonref,htmlnode) {
+    var nameinput = document.createElement("input");
+    var nameinputid = 'nameinputid.'+jsonref.fullindex;
+    nameinput.className = "jeclass";
+    nameinput.className="je_userkey";
+    nameinput.id=nameinputid;
+    nameinput.size=20;
+    nameinput.type="text";
+    nameinput.setAttribute("value", jsonref.nodename);
+
+    var je = this;
+    var parent = htmlnode.parentNode;
+    var putback = function () {
+        jsonref.renamePropname(this.value);
+        parent.replaceChild(je.getPropnameSpan(jsonref),nameinput);
+        je.updateNode(jsonref);
+        je.jsonLookupById[jsonref.fullindex]=jsonref;
+        je.updateJSON();
+    }
+
+    nameinput.onblur = putback;
+    nameinput.onchange = putback;
+    parent.replaceChild(nameinput, htmlnode);
+    nameinput.focus();
+}
+
+jsonwidget.editor.getPropnameSpan = function (jsonref) {
+    var nameinput = document.createElement("span");
+    nameinput.appendChild(document.createTextNode(jsonref.nodename));
+    var nameinputid = 'nameinputid.'+jsonref.fullindex;
+    nameinput.className="je_userkey";
+    nameinput.id=nameinputid;
+    var je = this;
+    nameinput.onclick = function (event) {
+        je.showPropnameInput(jsonref,this);
+    }
+    return nameinput;
+}
+
+jsonwidget.editor.attachSimplePropertyInput = function (jsonref) {
+    var valuetype = jsonref.getType();
+
+    switch (valuetype) {
+    case 'str':
+    case 'text':
+        var inputelement = this.getStringInput(jsonref);
+        break;
+                
+    case 'bool':
+        var inputelement = this.getBoolInput(jsonref);
+        break;
+
+    case 'number':
+    case 'int':
+        var inputelement = this.getNumberInput(jsonref);
+        break;
+                
+    case 'any':
+    case undefined:
+        var inputelement = this.getTypeSelectInput(jsonref);
+        break;
+
+    default:
+        this.warningOut("unknown type: " + valuetype);
+        var inputelement = this.getTypeSelectInput(jsonref);
+        break;
+    }
+
+
+    if(jsonref.domparent.tagName == 'TR') {
+        var parent = jsonref.domparent;
+        var namenode = document.createElement("td");
+        if(jsonref.isUserKey()) {
+            namenode.appendChild(this.getPropnameSpan(jsonref));
+        }
+        else {
+            namenode.appendChild(document.createTextNode(jsonref.nodename));
+        }
+        var valuenode = document.createElement("td");
+        var controlnode = document.createElement("td");
+    }
+    else {
+        var parent = document.createElement("fieldset");
+        var localnode = document.createElement("legend");
+        localnode.appendChild(document.createTextNode(jsonref.nodename));
+        parent.appendChild(localnode);
+        jsonref.domparent.appendChild(parent);
+
+        var namenode = document.createElement("span");
+        if(jsonref.getType() == undefined ) {
+            namenode.appendChild(document.createTextNode("value type: "));
+        }
+        else {
+            namenode.appendChild(document.createTextNode("value: "));
+        }
+        var valuenode = document.createElement("span");
+        var controlnode = document.createElement("span");
+        controlnode.appendChild(document.createTextNode(" "));
+    }
+
+    valuenode.appendChild(inputelement);
+
+    var controldiv = document.createElement("span");
+    controldiv.className="je_topcontrols";
+    controldiv.appendChild(this.getHelpButton(jsonref));
+    controldiv.appendChild(this.getDeleteButton(jsonref));
+
+    controlnode.appendChild(controldiv);
+
+    parent.appendChild(namenode);
+    parent.appendChild(valuenode);
+    parent.appendChild(controlnode);
+}
+
+jsonwidget.editor.getStringInput = function (jsonref) {
+    var control = '';
+    var curvalue = jsonref.node;
+    var jsoneditobj = this;
+    var inputid = 'inputid.'+jsonref.fullindex;
+
+    if(jsonref.schemaref.node['type']=='text') {
+        var inputelement = document.createElement("textarea");
+        inputelement.className = "jeclass";
+        inputelement.id=inputid;
+        inputelement.cols=50;
+        inputelement.setAttribute("value", curvalue);
+    } else if(jsonref.schemaref.node['enum']==undefined) {
+        //switching to DOM creation in hopes of preventing injection problems
+        var inputelement = document.createElement("input");
+        inputelement.className = "jeclass";
+        inputelement.id=inputid;
+        inputelement.size=50;
+        inputelement.type="text";
+        inputelement.setAttribute("value", curvalue);
+    } else {
+        var inputelement = document.createElement("select");
+        var validvalue = false;
+        inputelement.className = "jeclass";
+        inputelement.id=inputid;
+        for(var i in jsonref.schemaref.node['enum']) {
+            var option = document.createElement("option");
+            option.appendChild(document.createTextNode(jsonref.schemaref.node['enum'][i]));
+            if(jsonref.schemaref.node['enum'][i]==curvalue) {
+                option.selected = true;
+                validvalue = true;
+            }
+            inputelement.appendChild(option);
+        }
+        if(!validvalue) {
+            this.setNode(jsonref, jsonref.schemaref.node['enum'][0]);
+        }
+    }
+    return inputelement;
+}
+
+jsonwidget.editor.getTypeSelectInput = function (jsonref) {
+    var control = '';
+    var curvalue = jsonref.node;
+    var jsoneditobj = this;
+    var inputid = 'inputid.'+jsonref.fullindex;
+    var types = ['any','str','text','int','number','bool','seq','map'];
+
+    var inputelement = document.createElement("select");
+    inputelement.className = "jeclass";
+    inputelement.id=inputid;
+    for(var i in types) {
+        var option = document.createElement("option");
+        option.appendChild(document.createTextNode(types[i]));
+        inputelement.appendChild(option);
+    }
+    return inputelement;
+}
+
+
+jsonwidget.editor.getBoolInput = function getBoolInput(jsonref) {
+    var jsoneditobj = this;
+    var inputid = 'inputid.'+jsonref.fullindex;
+
+    var control = '<input class="jeclass" id="'+inputid+'" type="checkbox"';
+
+    var inputelement = document.createElement("input");
+    inputelement.id=inputid;
+    inputelement.className = "jeclass";
+    inputelement.type="checkbox";
+
+    if(jsonref.node) {
+        inputelement.setAttribute("checked", "true");
+    }
+    return inputelement;
+}
+
+jsonwidget.editor.getNumberInput = function getNumberInput(jsonref) {
+    var jsoneditobj = this;
+    var inputid = 'inputid.'+jsonref.fullindex;
+
+    if(jsonref.node == null) {
+        jsonref.node = '';
+    }
+    var inputelement = document.createElement("input");
+    inputelement.className = "jeclass";
+    inputelement.id=inputid;
+    inputelement.size=5;
+    inputelement.type="text";
+    inputelement.setAttribute("value", jsonref.node);
+    inputelement.setAttribute("align", "right");
+
+    return inputelement;
+}
+
+jsonwidget.editor.attachNodeInput = function attachNodeInput(jsonref) {
+    var nodetype = jsonref.getType();
+    var startTime=new Date().getTime();
+    var endTime;
+
+    if(jsonref.schemaref == undefined) {
+        this.warningOut("Unrecognized index: "+jsonref.toSource()+"<br/>\n");
+        //try uncommenting to see if anything breaks...if so, add this
+        //return;
+    }
+
+    if(jsonref.node == undefined) {
+        jsonref.node = jsonwidget.getNewValueForType(nodetype);
+    }
+
+    switch(nodetype) {
+        case 'map':
+        case 'seq':
+        this.attachArrayInput(jsonref);
+        break;
+
+        default:
+        this.attachSimplePropertyInput(jsonref);
+        break;
+    }
+    endTime=new Date().getTime();
+    jsonref.rendertime = endTime - startTime;
+}
+
+jsonwidget.editor.getSetViewFunction = function (viewname) {
+    var je = this;
+    return function () {
+        je.setView(viewname);
+    }
+}
+
+jsonwidget.editor.setView = function setView (viewtoset) {
+    this.setStatusLight("working...");
+    for(var i in this.views) {
+        var currentbutton = document.getElementById(this.htmlbuttons[this.views[i]]);
+        if(viewtoset == this.views[i]) {
+            currentbutton.className = this.classname.fgbutton;
+            currentbutton.onclick = null;
+        }
+        else {
+            switch (this.views[i]) {
+            case 'form':
+                this.formdiv.style.display="none";
+                break;
+            case 'source':
+                document.getElementById(this.htmlids.sourcetextarea).style.display="none";
+                break;
+            case 'schemasource':
+                document.getElementById(this.htmlids.schematextarea).style.display="none";
+                break;
+            case 'schemaform':
+                this.schemaedit.formdiv.style.display="none";
+                break;
+            }
+            currentbutton.onclick = this.getSetViewFunction(this.views[i]);
+            currentbutton.className = this.classname.bgbutton;
+        }
+    }
+
+    switch (this.currentView) {
+    case 'form':
+        this.updateJSON();
+        break;
+    case 'schemaform':
+        this.schemaedit.updateJSON();
+        break;
+    }
+
+    var je = this;
+
+    switch (viewtoset) {
+    case "source":
+        setTimeout(function () {
+            je.updateJSON();
+            document.getElementById(je.htmlids.sourcetextarea).style.display="inline";
+            je.clearStatusLight();
+        },this.getStatusLightDelay(null));
+        break;
+            
+    case "form":
+        setTimeout(function () {je.toggleToFormActual()},this.getStatusLightDelay(this.rootjson));
+        break;
+
+    case "schemasource":
+        setTimeout(function () {
+            je.updateJSON();
+            document.getElementById(je.htmlids.schematextarea).style.display="inline";
+            je.clearStatusLight();
+        },this.schemaedit.getStatusLightDelay(null));
+        break;
+    case "schemaform":
+        setTimeout(function () {je.schemaedit.toggleToFormActual()},this.getStatusLightDelay(this.schemaedit.rootjson));
+        break;
+    }
+    this.currentView = viewtoset;
+}
+
+
+jsonwidget.editor.getStatusLightDelay = function (jsonref) {
+    if(jsonref != null && jsonref != undefined && jsonref.rendertime != undefined) {
+        var timeout = jsonref.rendertime / 20;
+    }
+    else {
+        if(document.getElementById(this.htmlids.sourcetextarea).value.length>5000) {
+            var timeout = 400;
+        }
+        else {
+            var timeout = 40;
+        }
+    }
+    return timeout;
+}
+
+jsonwidget.editor.setStatusLight = function (statustext) {
+/*    if(this.statusLight == undefined) {
+        this.statusLight = document.createElement("div");
+        this.statusLight.id = "statusLight";
+        this.statusLight.style.position = "fixed";
+        this.statusLight.style.top = "0";
+        this.statusLight.style.right = "0";
+        this.statusLight.style.background = "red";
+        this.statusLight.style.color = "white";
+        this.statusLight.innerHTML=statustext;
+        this.statusLight = document.body.insertBefore(this.statusLight, document.body.firstChild);
+    }
+    else {
+        this.statusLight.innerHTML=statustext;
+        this.statusLight.style.visibility = "visible";
+    }*/
+}
+
+jsonwidget.editor.clearStatusLight = function () {
+    //this.statusLight.style.visibility = "hidden";
+}
+
+jsonwidget.editor.toggleToFormActual = function () {
+    var endTime;
+    var startTime=new Date().getTime();
+
+    this.debugwindow = document.getElementById(this.htmlids.warningdiv);
+    this.warningwindow = document.getElementById(this.htmlids.warningdiv);
+    this.clearWarnings();
+
+    //need to move this
+    this.setFormOnSubmit();
+
+    var startTime=new Date().getTime();
+    var endTime;
+    var jsonarea = document.getElementById(this.htmlids.sourcetextarea);
+
+    endTime=new Date().getTime();
+    this.debugOut(1, '#1a Elapsed time: '+((endTime-startTime)/1000));
+
+    var schema = this.getSchema();
+    this.schemaindex = new jsonwidget.schemaIndex(schema);
+
+    endTime=new Date().getTime();
+    this.debugOut(1, '#1b Elapsed time: '+((endTime-startTime)/1000));
+
+    if(!schema) {
+        return null;
+    }
+
+    try {
+        this.jsondata = JSON.parse(jsonarea.value);
+    }
+    catch (error) {
+        var errorstring = '';
+        if(/^\s*$/.test(jsonarea.value)) {
+               this.jsondata = jsonwidget.getNewValueForType(schema.type);
+        }
+        else {
+            if(error.at<40) {
+                errorstring += error.text.substr(0,error.at);
+            }
+            else {
+                errorstring += error.text.substr(error.at-40,40);
+            }
+            errorstring += "<span style='background-color: yellow'>";
+            errorstring += error.text.substr(error.at,1);
+            errorstring += "</span>";
+            errorstring += error.text.substr(error.at+1,39);
+                
+            this.warningOut("JSON Parse error at char "+error.at+" near <pre>"+errorstring+"</pre>  Full error: "+error.toSource());            
+            return;
+        }
+    }
+
+    var nodename = jsonwidget.getTitleFromNode(schema, "");
+    var rootschema = this.schemaindex.newRef(schema, null, null, nodename);
+    var rootjson = new jsonwidget.jsonTreeRef(this.jsondata, null, null, nodename, rootschema);
+    this.rootjson = rootjson;
+    this.jsonLookupById[rootjson.fullindex]=rootjson;
+
+    this.clearForm();
+
+            
+    rootjson.domparent = document.createElement("form");
+    this.showForm(rootjson.domparent);
+    this.attachNodeInput(rootjson);
+    if(this.showByExampleButton) {
+        this.attachByExampleText();
+    }
+
+    endTime=new Date().getTime();
+    this.debugOut(1, '#2 Elapsed time: '+((endTime-startTime)/1000));
+    this.attachHandlers();
+    this.clearStatusLight();
+}
+jsonwidget.editor.updateJSON = function () {
+    var jsonarea = document.getElementById(this.htmlids.sourcetextarea);
+    var parent = jsonarea.parentNode;
+    var nextsibling = jsonarea.nextSibling;
+    parent.removeChild(jsonarea);
+    if(this.jsondata == null) {
+        jsonarea.value = "";
+    }
+    else {
+        jsonarea.value = JSON.stringify(this.jsondata);
+    }
+    parent.insertBefore(jsonarea, nextsibling);
+}
+
+jsonwidget.editor.error = function (m) {
+    throw {
+        name: 'jsonedit_error',
+        message: m
+    }
+}
+
+jsonwidget.editor.debugOut = function (level, text) {
+    if(level<=this.debuglevel) {
+        this.debugwindow.innerHTML += text+"<br/>\n";
+    }
+}
+
+jsonwidget.editor.warningOut = function (text) {
+    this.warningwindow.innerHTML += text+"<br/>\n";
+}
+
+jsonwidget.editor.clearWarnings = function () {
+    this.warningwindow.innerHTML ="";
+}
+
+
+jsonwidget.editor.contextHelp = function(event, jsonnode) {
+    var helpdiv = document.createElement("div");
+    var title = document.createElement("div");
+    title.appendChild(document.createTextNode(jsonnode.getTitle()));
+    title.style.fontWeight = "bold";
+
+    var sourcename = document.createElement("div");
+    var sourcetext = document.createTextNode("(JSON index: '" +
+                                             jsonnode.schemaref.nodeindex +
+                                             "')")
+    sourcename.appendChild(sourcetext);
+    sourcename.style.fontStyle="italic";
+    sourcename.style.fontSize="smaller";
+
+    var description = document.createElement("div");
+    description.innerHTML=jsonnode.schemaref.node.desc;
+
+    helpdiv.appendChild(title);
+    helpdiv.appendChild(sourcename);
+    helpdiv.appendChild(description);
+    helpdiv.className = "je_helpdiv";
+    jsonnode.domparent.appendChild(helpdiv);
+
+    helpdiv.style.top = event.pageY-10;
+    helpdiv.style.left = event.pageX-10;
+
+    var hideContextHelp = function (event) {
+        if((helpdiv.compareDocumentPosition(event.relatedTarget) 
+            & Node.DOCUMENT_POSITION_CONTAINED_BY) == 0 
+           && helpdiv.compareDocumentPosition(event.relatedTarget) != 0) {
+               jsonnode.domparent.removeChild(helpdiv);
+           }
+        else {
+            event.returnValue=false;
+        }
+    }
+
+    helpdiv.addEventListener('mouseout',hideContextHelp,false);
+}
+
+
+jsonwidget.editor.confirmDelete = function (jsoneditobj, jsonref, el) {
+    var rmyesid='rmyesid.'+jsonref.fullindex;
+    var rmnoid='rmnoid.'+jsonref.fullindex;
+    
+    el.innerHTML='';
+    el.appendChild(document.createElement("br"));
+    el.appendChild(document.createTextNode(_("delete")+"? "));
+    var yesbutton = document.createElement("span");
+    yesbutton.onclick = function (event) {
+        // ie workarounds:
+        var target = window.event ? window.event.srcElement : event.target;
+        if(!event) {event = window.event}
+
+        jsoneditobj.deleteNode(jsonref.fullindex, target);
+        if(undefined != event.stopPropagation) {
+            event.stopPropagation();
+        }
+        else {
+            event.cancelBubble = true;
+        }
+    }
+    yesbutton.appendChild(document.createTextNode("["+_("yes")+"]"));
+    
+    var nobutton = document.createElement("span");
+    nobutton.onclick = function (event) {
+        // ie workarounds:
+        var target = window.event ? window.event.srcElement : event.target;
+        if(!event) {event = window.event}
+
+        target.parentNode.innerHTML = "["+_("del")+"]";
+        if(undefined != event.stopPropagation) {
+            event.stopPropagation();
+        }
+        else {
+            event.cancelBubble = true;
+        }
+    }
+    nobutton.appendChild(document.createTextNode("["+_("no")+"]"));
+    
+    el.appendChild(yesbutton);
+    el.appendChild(nobutton);
+}
+
+jsonwidget.editor.getSchema = function () {
+    var schemaarea = document.getElementById(this.htmlids.schematextarea);
+    
+    try {
+        var retval = JSON.parse(schemaarea.value);
+    }
+    catch (error) {
+        var errorstring = '';
+        if(error.text == undefined) {
+            throw(error);
+        }
+        if(error.at<40) {
+            errorstring += error.text.substr(0,error.at);
+        }
+        else {
+            errorstring += error.text.substr(error.at-40,40);
+        }
+        errorstring += "<span style='background-color: yellow'>";
+        errorstring += error.text.substr(error.at,1);
+        errorstring += "</span>";
+        errorstring += error.text.substr(error.at+1,39);
+        
+        this.warningOut("JSON Parse error at char "+error.at+" near <pre>"+errorstring+"</pre>  Full error: "+error.toSource());            
+    }
+    return retval;
+}
+
+jsonwidget.editor.setFormOnSubmit = function () {
+    var je = this;
+    var sourcetextform = document.getElementById(this.htmlids.sourcetextform);
+    sourcetextform.onsubmit = function () {
+        je.updateJSON();
+    }
+}
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/jsonwidget.css b/auf_savoirs_en_partage_django/media/js/jsonwidget/jsonwidget.css
new file mode 100644 (file)
index 0000000..0baa193
--- /dev/null
@@ -0,0 +1,38 @@
+.rmx, .je_hide, .je_show, .je_help {
+text-align: right; font-size: x-small; cursor: pointer;
+}
+.je_disabled {
+    text-align: right; font-size: x-small; cursor: help; color: grey;
+}
+.je_topcontrols {
+text-align: right; font-size: x-small; vertical-align: super;
+}
+span:hover.je_userkey {
+    border-style: solid;
+    border-color: #444444;
+    border-width: 1px;
+}
+.je_userkey {
+    border-style: solid;
+    border-color: #cccccc;
+    border-width: 1px;
+}
+
+.je_helpdiv {
+    border-style: solid;
+    border-width: 1px;
+    background-color: lightgoldenrodyellow;
+ position: absolute;
+ padding: 10px;
+ padding-left: 30px;
+}
+
+
+.je_foreground {
+    background-color: white;
+}
+
+.je_background {
+    background-color: "#f0f0ff";
+}
+
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/openschema.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/openschema.json
new file mode 100644 (file)
index 0000000..bd1c09d
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "title": "Freeform (unrestricted) JSON",
+    "type": "any"
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/prototype.html b/auf_savoirs_en_partage_django/media/js/jsonwidget/prototype.html
new file mode 100644 (file)
index 0000000..6d048a4
--- /dev/null
@@ -0,0 +1,62 @@
+<html>
+<head>
+<title>JSON widget prototype</title>
+<style type="text/css">
+.rmx {
+text-align: right; font-size: x-small; cursor: pointer; vertical-align: super;
+}
+</style>
+<script type="text/javascript" language="javascript">
+
+function loadJsonAreaFromIFrame() {
+    var foo = document.getElementById("myiframe");
+    var bar = document.getElementById("je_sourcetextarea");
+
+    bar.value = foo.contentDocument.firstChild.lastChild.firstChild.textContent;
+}
+
+function sample_init() {
+    loadJsonAreaFromIFrame();
+    je=new jsonwidget.editor();
+    je.toggleToForm();
+
+    //uncomment if you want to change defaults
+    //je.htmlids.warningdiv = "je_warningdiv";
+    //je.htmlids.formdiv = "je_formdiv";
+    //je.htmlids.sourcetextarea": "je_sourcetextarea";
+}
+
+</script>
+
+<script src="json.js"></script> 
+<script src="sampleschema.json"></script> 
+<script src="jsonedit.js"></script> 
+
+</head>
+<body onload="sample_init();">
+
+<div>
+<span id="formbutton" style="cursor: pointer" onclick='je.toggleToForm()'>[Edit w/Form]</span>
+<span id="sourcebutton" style="cursor: pointer" onclick='je.toggleToSource()'>[Edit Source]</span>
+</div>
+
+<div id="je_warningdiv">
+</div>
+
+<div id="je_formdiv">
+</div>
+
+<div>
+<textarea id="je_sourcetextarea" rows="30" cols="80" name="sourcearea">
+</textarea>
+</div>
+
+<div>
+<IFRAME style="display: none;" id='myiframe' src="sampledata-large.json" width="400" height="500" scrolling="auto" frameborder="1">
+</div>
+
+</body>
+</html>
diff --git a/auf_savoirs_en_partage_django/media/js/jsonwidget/schemaschema.json b/auf_savoirs_en_partage_django/media/js/jsonwidget/schemaschema.json
new file mode 100644 (file)
index 0000000..d828122
--- /dev/null
@@ -0,0 +1,128 @@
+{
+  "title":"Schema",
+  "type":"map",
+  "id":"schemanode",
+  "desc":"A schema describing a particular JSON format",
+  "required":true,
+  "mapping":
+  {
+    "type":
+    {
+      "type":"str",
+      "required":true,
+      "title":"Type (type)",
+      "desc":"The datatype of the property (e.g. number, boolean, etc), used for determining the semantics of the variable described",
+      "enum":
+      [
+        "any",
+        "str",
+        "int",
+        "number",
+        "bool",
+        "seq",
+        "map",
+        "idref"
+      ],
+      "desc_enum":
+      {
+        "any":"Any datatype allowed",
+        "str":"String",
+        "int":"Integer number",
+        "number":"Any number (floating point or integer)",
+        "bool":"Boolean (true or false) value",
+        "seq":"Nested sequence of items ('array' in many languages).  You must also have a 'sequence' property which is itself a sequence containing a single schema definition",
+        "map":"Nested mapping of key/value pairs (a.k.a. 'properties').  You must also have a 'mapping' property which is itself a sequence containing a single schema definition"
+      }
+    },
+    "title":
+    {
+      "type":"str",
+      "title":"Title (title)",
+      "desc":"A user-friendly title for the property"
+    },
+    "id":
+    {
+      "type":"str",
+      "title":"Identifier (id)",
+      "desc":"An identifier used to reference this property using the 'idref' property"
+    },
+    "desc":
+    {
+      "type":"str",
+      "title":"Description (desc)",
+      "desc":"A description for use in documentation and context help"
+    },
+    "user_key":
+    {
+      "type":"str",
+      "title":"User named key (user_key)",
+      "desc":"Key for properties named by the user.  Use only when type=map, and ensure there's a corresponding property schema in the mapping"
+    },
+    "idref":
+    {
+      "type":"str",
+      "title":"Identifier reference (idref)",
+      "desc":"Reference to a schema segment with the given 'id' property.  The 'type' attribute must be set to 'idref'."
+    },
+    "enum":
+    {
+      "type":"seq",
+      "sequence":
+      [
+        {
+          "type":"any"
+        }
+      ],
+      "title":"Enumeration (enum)",
+      "desc":"Enumerated sequence of valid values for this property."
+    },
+    "desc_enum":
+    {
+      "type":"map",
+      "user_key":"enumdesc",
+      "mapping":
+      {
+        "enumdesc":
+        {
+          "title":"Description for enum value",
+          "type":"str",
+          "desc":"A mapping containing a description for each possible value listed in the enumeration (enum) property.  Used for documentation and context help."
+        }
+      }
+    },
+    "required":
+    {
+      "type":"bool",
+      "title":"Required property? (required)",
+      "desc":"If 'true', then this property must always be present"
+    },
+    "mapping":
+    {
+      "type":"map",
+      "title":"Mapping (mapping)",
+      "desc":"A mapping containing schema segments describing each property in the mapping.  The 'type' property must be set to 'map' to use this property.",
+      "user_key":"schemachild",
+      "mapping":
+      {
+        "schemachild":
+        {
+          "type":"idref",
+          "idref":"schemanode"
+        }
+      }
+    },
+    "sequence":
+    {
+      "type":"seq",
+      "title":"Sequence (sequence)",
+      "desc":"A sequence containing a single schema segment",
+      "sequence":
+      [
+        {
+          "type":"idref",
+          "idref":"schemanode"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/auf_savoirs_en_partage_django/media/js/test.html b/auf_savoirs_en_partage_django/media/js/test.html
new file mode 100644 (file)
index 0000000..2fbbf01
--- /dev/null
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <title>JSON test</title>
+    <script src="jsonwidget/json.js"></script> 
+    <script src="jsonwidget/jsonedit.js"></script> 
+    <script type="text/javascript" language="javascript">
+      function sample_init() {
+          var je=new jsonwidget.editor();
+          je.setView('form');
+      }
+
+    </script>
+
+  </head>
+
+  <body onload="sample_init();">
+    <textarea id="je_schematextarea" style="display: none" rows="30" cols="80">
+      {
+      "type": "map",
+      "mapping":
+      {
+      "title": {"type": "str", "required": false },
+      "alt_title": {"type": "str", "required": false },
+      "creator": {"type": "str", "required": false },
+      "contributor": {"type": "seq", "required": false, "sequence": [{"type": "str"}]}
+      }
+      }
+    </textarea>
+    <div id="je_warningdiv">
+    </div>
+    <div style="display: none;">
+      <span id="je_formbutton" style="cursor: pointer">[Edit w/Form]</span>
+      <span id="je_sourcebutton" style="cursor: pointer">[Edit Source]</span>
+    </div>
+    <div id="je_formdiv" style="text-background: white">
+    </div>
+    <div>
+      <div id="je_schemaformdiv" style="text-background: white">
+      </div>
+      <textarea id="je_schematextarea" style="display: none" rows="30" cols="80">
+      </textarea>
+      <form method='POST' id="je_sourcetextform">
+        <textarea id="je_sourcetextarea" rows="30" cols="80" name="sourcearea">
+        </textarea>
+        <!--p>
+        <input type="hidden" name="jsonsubmit" value="true"/>
+        <input type="submit" value="Submit JSON"/>
+        </p-->
+      </form>
+    </div>
+  </body>
+</html>
index e3384f3..dae59d1 100644 (file)
@@ -1,8 +1,10 @@
 configuration = {
-        'max_actualite': 100,
-        'accueil_actualite': 5,
-        'nombre_par_page_actualite': 10,
-        'resultats_par_page': 8, # pas changeable a cause de google
-        'accueil_evenement': 5,
-        'engin_recherche': 'sep'
-        }
+    'max_actualite': 100,
+    'accueil_actualite': 5,
+    'nombre_par_page_actualite': 10,
+    'resultats_par_page': 8, # pas changeable a cause de google
+    'accueil_evenement': 10,
+    'engin_recherche': 'sep',
+    'calendrier': 'http://sogo1:sogo1@sogo-demo.inverse.ca:80/SOGo/dav/sogo1/Calendar/personal/',
+    'calendrier_publique': 'http://sogo-demo.inverse.ca:80/SOGo/dav/sogo1/Calendar/personal/',
+}
index 3305498..e73e961 100644 (file)
@@ -1,7 +1,8 @@
 # -*- encoding: utf-8 -*-
 from django.contrib import admin
-from models import Actualite, Discipline
+from models import Actualite, Discipline, Evenement
 
-admin.site.register (Actualite)
-admin.site.register (Discipline)
+admin.site.register(Actualite)
+admin.site.register(Discipline)
+admin.site.register(Evenement)
 
index 995903f..9f31c07 100644 (file)
@@ -1,5 +1,6 @@
 # -*- encoding: utf-8 -*-
 from django import forms
+from models import Evenement
 
 class RechercheAvancee (forms.Form):
     creator = forms.CharField (max_length=60, required=False, \
@@ -13,3 +14,7 @@ class RechercheAvancee (forms.Form):
     type = forms.CharField (initial='avancee', required=False, widget=forms.HiddenInput)
 
 
+class EvenementForm(forms.ModelForm):
+    class Meta:
+        model = Evenement
+        exclude = ('approuve', 'uid', 'actif')
diff --git a/auf_savoirs_en_partage_django/savoirs/lib/__init__.py b/auf_savoirs_en_partage_django/savoirs/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf_savoirs_en_partage_django/savoirs/lib/calendrier.py b/auf_savoirs_en_partage_django/savoirs/lib/calendrier.py
new file mode 100644 (file)
index 0000000..5e64ac1
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- encoding: utf-8 -*-
+import caldav, datetime, time, pytz
+from savoirs import configuration
+
+def evenements():
+    rc = []
+
+    client = caldav.DAVClient(configuration['calendrier'])
+    cal = caldav.Calendar(client, url = configuration['calendrier'])
+    start = datetime.datetime.now().strftime("%Y%m%dT%H%M%S%z")
+    events = cal.date_search(start)
+
+    for e in events:
+        rc.append(e.instance.vevent)
+
+    rc.sort(lambda x,y: cmp(time.mktime(x.dtstart.value.timetuple()), 
+                            time.mktime(y.dtstart.value.timetuple())))
+
+    return rc
+
+
+
+def evenement_info(uid):
+    client = caldav.DAVClient(configuration['calendrier'])
+    cal = caldav.Calendar(client, url = configuration['calendrier'])
+    return cal.event(uid)
+
+def evenement_publie(event):
+    client = caldav.DAVClient(configuration['calendrier'])
+    cal = caldav.Calendar(client, url = configuration['calendrier'])
+    e = caldav.Event(client, parent = cal, data = event.serialize()).save()
+
+def combine(when, tz):
+    r = datetime.datetime(when.year, when.month, when.day, 
+                          when.hour, when.minute, tzinfo = pytz.timezone(tz))
+    #r = r.replace(tzinfo = pytz.timezone("UTC"))
+    t = r.utctimetuple()
+    r = datetime.datetime(*(t[0:6]), tzinfo = pytz.timezone("UTC"))
+    return r
diff --git a/auf_savoirs_en_partage_django/savoirs/lib/recherche.py b/auf_savoirs_en_partage_django/savoirs/lib/recherche.py
new file mode 100644 (file)
index 0000000..3614b94
--- /dev/null
@@ -0,0 +1,150 @@
+# -*- encoding: utf-8 -*-
+import urllib, httplib, time, simplejson, pprint, math, re
+from django.conf import settings
+from auf_savoirs_en_partage_backend.sep.io import SEP
+from auf_savoirs_en_partage_backend.sep.utils import smart_str
+from savoirs import configuration
+
+
+def google_search (page, q, data):
+    params = {'q': q,
+              'rsz': 'large',
+              'v': '1.0',
+              'start': page * configuration['resultats_par_page'],
+              }
+    if not settings.DEBUG:
+        #TODO: corriger ts
+        params['cref'] = "http://savoirsenpartage.auf.org/recherche.xml?%s" \
+                % int(time.time())
+
+    url = "/ajax/services/search/web?" + \
+            urllib.urlencode (params)
+    handle = httplib.HTTPConnection ('ajax.googleapis.com')
+    handle.request ("GET", url)
+    r = handle.getresponse ()
+    response = simplejson.loads(r.read ())
+    #print pprint.pformat (params)
+    #print pprint.pformat (response)
+    handle.close ()
+
+    if len (response['responseData']['results']) > 0:
+        for i in response['responseData']['cursor']['pages']:
+            p = int (i['label']) - 1
+            if p > data['last_page']:
+                data['last_page'] = p
+
+        for r in response['responseData']['results']:
+            data['results'].append( {'uri': r['url'],
+                        'content': r['content'],
+                        'title': r['title']} )
+
+        data['more_link'] = response['responseData']['cursor']['moreResultsUrl']
+
+
+def sep_build_content (regexp, description):
+    maxlen = 200
+    content = description
+    if len (description) > maxlen:
+        start = 0
+        loc = regexp.search (description)
+        if loc:
+            start = loc.start ()
+
+        f = start - (maxlen / 2)
+        t = 0
+        if f < 0:
+            t = -f
+            f = 0
+        t += start + (maxlen / 2)
+        if f > 0:
+            while description[f] != '.' and f > 0:
+                f -= 1
+            if f > 0:
+                f += 1
+        if t < len (description):
+            while t < len (description) and description[t] != '.':
+                t += 1
+            t += 1
+        content = description[f:t]
+        if f > 0:
+            content = "(...) " + content
+        if t < (len (description) - 1):
+            content = content + " (...)"
+    content = regexp.sub (r'<b>\1</b>', content)
+    return content
+
+
+def make_regexp (q):
+    words = []
+    w = re.compile (r'\W+', re.U)
+    for k in q.keys ():
+        if k != 'operator':
+            words.extend(w.split (smart_str(q[k]).decode("utf-8")))
+    words = filter (lambda x: len(x)>2, words)
+    words.sort (lambda x,y: len(y)-len(x))
+
+    patt = "|".join (words)
+    patt = "([\W]{1})(" + patt + ")([\W]{1})"
+    return re.compile (patt, re.I|re.U)
+
+def hl (r, string):
+    if string is not None:
+        return r.sub (r'\1<b>\2</b>\3', string)
+    return None
+
+
+def sep_search (page, q, data):
+    f = page * configuration['resultats_par_page']
+    t = f + 8
+    s = SEP ()
+    matches = s.search (q)
+    data['last_page'] = math.ceil (float(len (matches)) / \
+            float(configuration['resultats_par_page'])) - 1
+    set = s.get (matches[f:t])
+    regexp = make_regexp (q)
+
+    for r in set:
+        uri = r.get ("source", "")
+        if len (uri) == 0:
+            uri = r.get ("uri")
+
+        title = regexp.sub (r'<b>\1</b>', r.get ("title", ""))
+
+        content = sep_build_content (regexp, r.get ("description", ""))
+
+        contributeurs = r.get('contributor')
+        if contributeurs is not None:
+            contributeurs = "; ".join (contributeurs)
+
+        subject = r.get ('subject')
+        if subject is not None:
+            subject = ", ".join (subject)
+
+        data['results'].append ({'uri': uri, 
+                'id': r.get("uri"), \
+                'title': hl(regexp, title), 
+                'content': hl(regexp, content), \
+                'creator': hl(regexp, r.get('creator')),
+                'contributors': hl(regexp, contributeurs),
+                'subject': hl(regexp, subject),
+                'modified': r.get('modified'),
+                'isbn': r.get('isbn'),
+                })
+
+
+def cherche (page, q, engin=None):
+    rc = {'results': [], 'last_page': 0, 'more_link': ''}
+
+    if engin is None:
+        engin = configuration['engin_recherche']
+
+    if engin == 'google':
+        google_search (page, q, rc)
+
+    elif engin == 'sep':
+        sep_search (page, {'q': q.encode ('utf-8')}, rc)
+
+    elif engin == 'avancee':
+        sep_search (page, q, rc)
+    
+    return rc
index 00f92df..2fc6b10 100644 (file)
@@ -1,4 +1,7 @@
+# -*- encoding: utf-8 -*-
 from django.db import models
+import uuid, datetime
+from timezones.fields import TimeZoneField
 
 
 class Discipline(models.Model):
@@ -6,7 +9,7 @@ class Discipline(models.Model):
     nom = models.CharField(max_length=765, db_column='nom_discipline')
 
     def __unicode__ (self):
-        return "Discipline: %s" % self.nom
+        return self.nom
 
     class Meta:
         db_table = u'discipline'
@@ -28,3 +31,40 @@ class Actualite(models.Model):
     class Meta:
         db_table = u'actualite'
         ordering = ["-date",]
+
+
+class ActiveManager(models.Manager):
+    def get_query_set(self):
+        return super(ActiveManager, self).get_query_set().filter(actif=True)
+
+class Evenement(models.Model):
+    actif = models.BooleanField(default = True)
+    uid = models.CharField(max_length = 255, default = uuid.uuid1)
+    approuve = models.BooleanField(default = False)
+    titre = models.CharField(max_length=255)
+    discipline = models.ForeignKey('Discipline', related_name = "discipline", 
+                                   blank = True, null = True)
+    discipline_secondaire = models.ForeignKey('Discipline', related_name = \
+                                              "discipline_secondaire", 
+                                              verbose_name = \
+                                              "Discipline secondaire", 
+                                              blank = True, null = True)
+    mots_cles = models.TextField('Mots-Clés', blank = True, null = True)
+    type = models.CharField(max_length = 255, choices = \
+                            (('Colloque', 'Colloque'),
+                             ('Conférence', 'Conférence'),
+                             ('Appel à contribution', 'Appel à contribution'),
+                             ('Journée d\'étude', 'Journée d\'étude'),
+                             (None, 'Autre')
+                            )) #TODO: choices
+    fuseau = TimeZoneField(verbose_name = 'Fuseau horaire')
+    debut = models.DateTimeField(default = datetime.datetime.now)
+    fin = models.DateTimeField(default = datetime.datetime.now)
+    lieu = models.TextField()
+    description = models.TextField(blank = True, null = True)
+    #fichiers = TODO?
+    contact = models.TextField(blank = True, null = True)
+    url = models.CharField(max_length=255, blank = True, null = True)
+
+    objects = ActiveManager()
+
diff --git a/auf_savoirs_en_partage_django/savoirs/recherche.py b/auf_savoirs_en_partage_django/savoirs/recherche.py
deleted file mode 100644 (file)
index 3614b94..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-# -*- encoding: utf-8 -*-
-import urllib, httplib, time, simplejson, pprint, math, re
-from django.conf import settings
-from auf_savoirs_en_partage_backend.sep.io import SEP
-from auf_savoirs_en_partage_backend.sep.utils import smart_str
-from savoirs import configuration
-
-
-def google_search (page, q, data):
-    params = {'q': q,
-              'rsz': 'large',
-              'v': '1.0',
-              'start': page * configuration['resultats_par_page'],
-              }
-    if not settings.DEBUG:
-        #TODO: corriger ts
-        params['cref'] = "http://savoirsenpartage.auf.org/recherche.xml?%s" \
-                % int(time.time())
-
-    url = "/ajax/services/search/web?" + \
-            urllib.urlencode (params)
-    handle = httplib.HTTPConnection ('ajax.googleapis.com')
-    handle.request ("GET", url)
-    r = handle.getresponse ()
-    response = simplejson.loads(r.read ())
-    #print pprint.pformat (params)
-    #print pprint.pformat (response)
-    handle.close ()
-
-    if len (response['responseData']['results']) > 0:
-        for i in response['responseData']['cursor']['pages']:
-            p = int (i['label']) - 1
-            if p > data['last_page']:
-                data['last_page'] = p
-
-        for r in response['responseData']['results']:
-            data['results'].append( {'uri': r['url'],
-                        'content': r['content'],
-                        'title': r['title']} )
-
-        data['more_link'] = response['responseData']['cursor']['moreResultsUrl']
-
-
-def sep_build_content (regexp, description):
-    maxlen = 200
-    content = description
-    if len (description) > maxlen:
-        start = 0
-        loc = regexp.search (description)
-        if loc:
-            start = loc.start ()
-
-        f = start - (maxlen / 2)
-        t = 0
-        if f < 0:
-            t = -f
-            f = 0
-        t += start + (maxlen / 2)
-        if f > 0:
-            while description[f] != '.' and f > 0:
-                f -= 1
-            if f > 0:
-                f += 1
-        if t < len (description):
-            while t < len (description) and description[t] != '.':
-                t += 1
-            t += 1
-        content = description[f:t]
-        if f > 0:
-            content = "(...) " + content
-        if t < (len (description) - 1):
-            content = content + " (...)"
-    content = regexp.sub (r'<b>\1</b>', content)
-    return content
-
-
-def make_regexp (q):
-    words = []
-    w = re.compile (r'\W+', re.U)
-    for k in q.keys ():
-        if k != 'operator':
-            words.extend(w.split (smart_str(q[k]).decode("utf-8")))
-    words = filter (lambda x: len(x)>2, words)
-    words.sort (lambda x,y: len(y)-len(x))
-
-    patt = "|".join (words)
-    patt = "([\W]{1})(" + patt + ")([\W]{1})"
-    return re.compile (patt, re.I|re.U)
-
-def hl (r, string):
-    if string is not None:
-        return r.sub (r'\1<b>\2</b>\3', string)
-    return None
-
-
-def sep_search (page, q, data):
-    f = page * configuration['resultats_par_page']
-    t = f + 8
-    s = SEP ()
-    matches = s.search (q)
-    data['last_page'] = math.ceil (float(len (matches)) / \
-            float(configuration['resultats_par_page'])) - 1
-    set = s.get (matches[f:t])
-    regexp = make_regexp (q)
-
-    for r in set:
-        uri = r.get ("source", "")
-        if len (uri) == 0:
-            uri = r.get ("uri")
-
-        title = regexp.sub (r'<b>\1</b>', r.get ("title", ""))
-
-        content = sep_build_content (regexp, r.get ("description", ""))
-
-        contributeurs = r.get('contributor')
-        if contributeurs is not None:
-            contributeurs = "; ".join (contributeurs)
-
-        subject = r.get ('subject')
-        if subject is not None:
-            subject = ", ".join (subject)
-
-        data['results'].append ({'uri': uri, 
-                'id': r.get("uri"), \
-                'title': hl(regexp, title), 
-                'content': hl(regexp, content), \
-                'creator': hl(regexp, r.get('creator')),
-                'contributors': hl(regexp, contributeurs),
-                'subject': hl(regexp, subject),
-                'modified': r.get('modified'),
-                'isbn': r.get('isbn'),
-                })
-
-
-def cherche (page, q, engin=None):
-    rc = {'results': [], 'last_page': 0, 'more_link': ''}
-
-    if engin is None:
-        engin = configuration['engin_recherche']
-
-    if engin == 'google':
-        google_search (page, q, rc)
-
-    elif engin == 'sep':
-        sep_search (page, {'q': q.encode ('utf-8')}, rc)
-
-    elif engin == 'avancee':
-        sep_search (page, q, rc)
-    
-    return rc
index 7f0e6ac..2722433 100644 (file)
@@ -1,23 +1,31 @@
 # -*- encoding: utf-8 -*-
-import datetime, simplejson
+import datetime, simplejson, copy, vobject
+
 from django.shortcuts import render_to_response
 from django.template import Context, RequestContext
-from django.http import HttpResponse
+from django.http import HttpResponse, HttpResponseRedirect
 from django.contrib.auth.decorators import login_required
-from models import Actualite
+from django.core.urlresolvers import reverse
+
+import auf_savoirs_en_partage_backend as sep
+
+from lib.recherche import cherche, google_search
+from lib.calendrier import evenements, evenement_info, evenement_publie, combine
 from savoirs import configuration
-from recherche import cherche, google_search
-from auf_savoirs_en_partage_backend.sep.io import SEP
-from forms import RechercheAvancee
-from auf_savoirs_en_partage_backend.conf import RESOURCES
+from forms import *
+from models import *
+
 
 def index (request):
     delta = datetime.timedelta (days = 90)
     oldest = datetime.date.today () - delta
     articles = Actualite.objects.filter (visible = '1', date__gt = oldest)
     articles = articles[0:configuration['accueil_actualite']]
+    events = evenements()[0:configuration['accueil_evenement']]
     return render_to_response ("savoirs/index.html", \
-            Context ({"articles": articles}), \
+            Context ({"articles": articles,
+                      "events": events,
+                      "caldav_url": configuration['calendrier_publique']}), \
             context_instance = RequestContext(request))
 
 def recherche (request):
@@ -73,12 +81,17 @@ def conseils (request):
 
 def a_propos (request):
     return render_to_response ("savoirs/a-propos.html", \
-            Context ({'count': len(RESOURCES)}), \
+            Context ({'count': len(sep.conf.RESOURCES)}), \
             context_instance = RequestContext(request))
 
 def informations (request):
+    s = sep.sep.io.SEP()
+    t = s.logs()
+    resources = copy.deepcopy (sep.conf.RESOURCES)
+    for k in t.keys ():
+        resources[k]['logs'] = { 'date': t[k][0], 'count': t[k][1] }
     return render_to_response ("savoirs/informations.html", \
-            Context ({'r': RESOURCES}), \
+            Context ({'r': resources}), \
             context_instance = RequestContext(request))
 
 def nous_contacter (request):
@@ -86,11 +99,90 @@ def nous_contacter (request):
             Context (), \
             context_instance = RequestContext(request))
 
+
+def evenement(request, id):
+    event = evenement_info(id)
+    return render_to_response ("savoirs/evenement.html", \
+            Context ({'event': event.instance.vevent}), \
+            context_instance = RequestContext(request))
+
+def evenement_ajout(request):
+    template = "savoirs/evenement_ajout.html"
+    if request.method == "POST":
+        form = EvenementForm(request.POST)
+        if form.is_valid():
+            form.save()
+            template = "savoirs/evenement_confirmation.html"
+    else:
+        form = EvenementForm()
+    return render_to_response (template, \
+                               Context ({'form': form}), \
+                               context_instance = RequestContext(request))
+
+@login_required
+def evenement_moderation(request):
+    events = Evenement.objects.filter(approuve = False)
+    return render_to_response ("savoirs/evenement_moderation.html", \
+                               Context ({'events': events}), \
+                               context_instance = RequestContext(request))
+
+@login_required
+def evenement_accepter(request, pk):
+    e = Evenement.objects.get(pk = pk)
+
+    cal = vobject.iCalendar()
+    cal.add('vevent')
+    cal.vevent.add('summary').value = e.titre
+    
+    kw = e.mots_cles.split(",")
+    try:
+        kw.append(e.discipline.nom)
+        kw.append(e.discipline_secondaire.nom)
+        kw.append(e.type)
+    except: pass
+
+    kw = [x.strip() for x in kw if len(x.strip()) > 0]
+    for k in kw:
+        cal.vevent.add('x-auf-keywords').value = k
+
+    if len(kw) > 0:
+        if len(e.description) > 0:
+            e.description += "\n"
+        e.description += u"Mots-cles: " + ", ".join(kw)
+
+    cal.vevent.add('dtstart').value = combine(e.debut, e.fuseau)
+    cal.vevent.add('dtend').value = combine(e.fin, e.fuseau)
+    cal.vevent.add('created').value = combine(datetime.datetime.now(), "UTC")
+    cal.vevent.add('dtstamp').value = combine(datetime.datetime.now(), "UTC")
+    if len(e.description) > 0:
+        cal.vevent.add('description').value = e.description
+    if len(e.contact) > 0:
+        cal.vevent.add('contact').value = e.contact
+    if len(e.url) > 0:
+        cal.vevent.add('url').value = e.url
+    if len(e.lieu) > 0:
+        cal.vevent.add('location').value = e.lieu
+
+    evenement_publie(cal)
+
+    e.actif = False
+    e.save()
+
+    return HttpResponseRedirect(reverse('savoirs.views.evenement_moderation'))
+
+@login_required
+def evenement_refuser(request, pk):
+    evenement = Evenement.objects.get(pk = pk)
+    evenement.actif = False
+    evenement.save()
+    return HttpResponseRedirect(reverse('savoirs.views.evenement_moderation'))
+
+
 @login_required
 def json_get (request):
     uri = request.GET.get ("uri")
     if uri:
-        s = SEP ()
+        s = sep.sep.io.SEP ()
         res = s.search ({'uri': uri.encode("utf-8")})
         if len (res) > 0:
             r = s.get (res[0])
@@ -104,7 +196,7 @@ def json_set (request):
     if data:
         r = simplejson.loads(data)
         print r
-        s = SEP ()
+        s = sep.sep.io.SEP ()
         s.add (r)
     return HttpResponse(simplejson.dumps("OK"),
             mimetype='application/json')
index 160524e..542769c 100644 (file)
@@ -45,6 +45,7 @@ INSTALLED_APPS = (
     'django.contrib.sessions',
     'django.contrib.admin',
     'django_roa',
+    'timezones',
     'auf_roa_authentification_backend',
     'savoirs',
 )
index 21409e4..be4582d 100644 (file)
@@ -8,7 +8,9 @@
         <script type="text/javascript" src="{{ MEDIA_URL }}js/tabber.js"></script>
         <script type="text/javascript" src="{{ MEDIA_URL }}js/pagination.js"></script>
         <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery/jquery.datepicker.js"></script>
+        <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery/jquery.timepicker.js"></script>
         <link href="{{ MEDIA_URL }}css/jquery/jquery.datepicker.css" rel="stylesheet" type="text/css" />
+        <link href="{{ MEDIA_URL }}css/jquery/jquery.timepicker.css" rel="stylesheet" type="text/css" />
         <link href="{{ MEDIA_URL }}css/global.css" rel="stylesheet" type="text/css" />
         <link href="{{ MEDIA_URL }}css/tabber.css" rel="stylesheet" type="text/css" />
         <link rel="stylesheet" href="{{ MEDIA_URL }}js/jquery/css/smoothness/jquery-ui-1.8rc3.custom.css" type="text/css" media="all" />
diff --git a/auf_savoirs_en_partage_django/templates/savoirs/evenement.html b/auf_savoirs_en_partage_django/templates/savoirs/evenement.html
new file mode 100644 (file)
index 0000000..c2a89e2
--- /dev/null
@@ -0,0 +1,35 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+<h4>{{ event.summary.value }}</h4>
+
+<div class="zone-texte">
+  <table width="100%">
+    <tr>
+      <th width="120px">Début</th>
+      <td>{{ event.dtstart.value|date:"Y-m-d H:i" }} (UTC)</td>
+    </tr>
+    <tr>
+      <th>Fin</th>
+      <td>{{ event.dtend.value|date:"Y-m-d H:i" }} (UTC)</td>
+    </tr>
+    <tr>
+      <th>Déscription</th>
+      <td>{{ event.description.value|linebreaksbr }}</td>
+    </tr>
+    <tr>
+      <th>Contact</th>
+      <td>{{ event.contact.value|linebreaksbr }}</td>
+    </tr>
+    <tr>
+      <th>Emplacement</th>
+      <td>{{ event.location.value|linebreaksbr }}</td>
+    </tr>
+    <tr>
+      <th>URL</th>
+      <td><a href="{{ event.url.value }}">{{ event.url.value }}</a></td>
+    </tr>
+  </table>
+</div>
+
+{% endblock %}
diff --git a/auf_savoirs_en_partage_django/templates/savoirs/evenement_ajout.html b/auf_savoirs_en_partage_django/templates/savoirs/evenement_ajout.html
new file mode 100644 (file)
index 0000000..e89c572
--- /dev/null
@@ -0,0 +1,33 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+
+<style>
+  div.boite-recherche { display: none !important; }
+  div#contenu { margin-top: 20px !important; }
+  div#results { margin-top: 15px; }
+  div.tabber { display: none; }
+  th { font-weight: normal; padding-right: 10px;}
+  input[type=text] { width: 250px; }
+</style>
+
+<script>
+  $(function () {
+      $("#id_debut").datetime({ userLang: 'fr' });
+      $("#id_fin").datetime({ userLang: 'fr' });
+      });
+</script>
+
+<div class="clearfix">
+  <h4>Soumettre un événement</h4>
+  <div class="zone-texte">
+    <form method="POST">
+      <table class="form">
+        {{ form }}
+        <tr><td></td><td><input type="submit" value="Ajouter" /></td></tr>
+      </table>
+    </form>
+  </div>
+</div>
+
+{% endblock %}
diff --git a/auf_savoirs_en_partage_django/templates/savoirs/evenement_confirmation.html b/auf_savoirs_en_partage_django/templates/savoirs/evenement_confirmation.html
new file mode 100644 (file)
index 0000000..2b4e535
--- /dev/null
@@ -0,0 +1,22 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+
+<style>
+  div.boite-recherche { display: none !important; }
+  div#contenu { margin-top: 20px !important; }
+  div#results { margin-top: 15px; }
+  div.tabber { display: none; }
+  th { font-weight: normal; padding-right: 10px;}
+  input[type=text] { width: 250px; }
+</style>
+
+<div class="clearfix">
+  <h4>Soumettre un événement</h4>
+  <div class="zone-texte">
+    <p>Votre évenement a bien été pris en compte, il sera approuvé par notre 
+    équipe bientot.</p>
+  </div>
+</div>
+
+{% endblock %}
diff --git a/auf_savoirs_en_partage_django/templates/savoirs/evenement_moderation.html b/auf_savoirs_en_partage_django/templates/savoirs/evenement_moderation.html
new file mode 100644 (file)
index 0000000..0df7d55
--- /dev/null
@@ -0,0 +1,37 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+
+<div class="clearfix">
+  <h4>Évenements a modérer</h4>
+  <div class="zone-texte">
+    <table width="100%">
+      <tr><th>Évenement</th><th>Actions</th></tr>
+      {% for e in events %}
+      <tr valign="top" class="{% cycle '' 'odd' %}">
+        <td>
+          <ul>
+            <li>Titre: {{ e.titre }}</li>
+            <li>Discipline: {{ e.discipline.nom }}</li>
+            <li>Discipline secondaire: {{ e.discipline_secondaire.nom }}</li>
+            <li>Mots-clés: {{ e.mots_cles }}</li>
+            <li>Type: {{ e.type }}</li>
+            <li>Debut: {{ e.debut }}</li>
+            <li>Fin: {{ e.fin }}</li>
+            <li>Lieu: {{ e.lieu }}</li>
+            <li>Description: {{ e.description }}</li>
+            <li>Contact: {{ e.contact }}</li>
+            <li>Url: {{ e.url }}</li>
+          </ul>
+        </td>
+        <td>
+          <a href="{% url savoirs.views.evenement_accepter e.pk %}">Accepter</a><br />
+          <a href="{% url savoirs.views.evenement_refuser e.pk %}">Refuser</a>
+        </td>
+      </tr>
+      {% endfor %}
+    </table>
+  </div>
+</div>
+
+{% endblock %}
index 50e3ae1..7c74060 100644 (file)
@@ -1,9 +1,10 @@
 {% extends "container_base.html" %}
 
 {% block contenu %}
-<h4>Actualités</h4>
+<div class="demi-gauche clearfix">
+  <h4>Actualités</h4>
 
-<ul class="liste-de-l-accueil">
+  <ul class="liste-de-l-accueil">
     <!-- dans la vue, cloner avoirListeActualitesAccueil -->
     {% for article in articles %}
     <li class="clearfix">
     <span class="le-resume">{{ article.texte }} -&nbsp;<a href="{{ article.url }}">Lire</a></span>
     </li>
     {% endfor %}
-</ul>
+  </ul>
+</div>
+
+
+<div class="demi-droite clearfix">
+  <h4>Agenda</h4>
+  <ul class="liste-de-l-accueil">
+    {% for event in events %}
+    <li>
+    <span class="la-date">{{ event.dtstart.value|date:"Y-m-d" }} 
+      {{ event.dtstart.value|date:"H:i" }}</span>
+    <a href="{% url savoirs.views.evenement event.uid.value %}" 
+      class="le-titre">{{ event.summary.value }}</a>
+    <span class="le-resume">{{ event.description.value }}</span>
+    </li>
+    {% endfor %}
+  </ul>
+  <div id="calendar-links">
+    <p>- <a href="{% url savoirs.views.evenement_ajout %}">Soumettre un événement</a></p>
+    <p>- <a href="{{ caldav_url }}">S'abonner</a></p>
+    {% if user.is_authenticated %}
+    <p>- <a href="{% url savoirs.views.evenement_moderation %}">Modération</a></p>
+    {% endif %}
+  </div>
+</div>
 {% endblock %}
index d3ff66d..a377cea 100644 (file)
@@ -14,7 +14,7 @@
   <strong>{{ site }}</strong>
 </span>
 <table width="100%">
-  <tr><th width="135px">Type</th><td>{{ details.type }}</td></tr>
+  <tr><th width="150px">Type</th><td>{{ details.type }}</td></tr>
   {% ifequal details.type "lodel" %}
     {% ifequal details.acces "html" %}
     <tr><th>URL</th><td><a href="http://{{ details.server }}{{ details.base_url }}">
@@ -34,9 +34,8 @@
     <tr><th>Utilisateur</th><td>{{ details.username }}</td></tr>
     <tr><th>Base de données</th><td>{{ details.db }}</td></tr>
     {% endifequal %}
-  {% endifequal %}
-</table>
-</table>
+    {% endifequal %}
+    <tr><th>Dernier moissonage</th><td>{{ details.logs.date }}, {{ details.logs.count }} articles</td></tr>
 </table>
 </p>
 {% empty %}
index 469594a..6d4e414 100644 (file)
@@ -13,14 +13,21 @@ urlpatterns = patterns(
     (r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'template_name': 'savoirs/logout.html'}),
 
     (r'^$', 'savoirs.views.index'),
-    (r'^conseils$', 'savoirs.views.conseils'),
-    (r'^a-propos$', 'savoirs.views.a_propos'),
-    (r'^informations$', 'savoirs.views.informations'),
-    (r'^nous-contacter$', 'savoirs.views.nous_contacter'),
-    (r'^recherche$', 'savoirs.views.recherche'),
-    (r'^recherche/avancee$', 'savoirs.views.avancee'),
-    (r'^json/get$', 'savoirs.views.json_get'),
-    (r'^json/set$', 'savoirs.views.json_set'),
+    (r'^conseils/$', 'savoirs.views.conseils'),
+    (r'^a-propos/$', 'savoirs.views.a_propos'),
+    (r'^informations/$', 'savoirs.views.informations'),
+    (r'^nous-contacter/$', 'savoirs.views.nous_contacter'),
+    (r'^recherche/$', 'savoirs.views.recherche'),
+    (r'^recherche/avancee/$', 'savoirs.views.avancee'),
+
+    (r'^evenements/creer/$', 'savoirs.views.evenement_ajout'),
+    (r'^evenements/moderer/$', 'savoirs.views.evenement_moderation'),
+    (r'^evenements/moderer/(.+)/accepter/$', 'savoirs.views.evenement_accepter'),
+    (r'^evenements/moderer/(.+)/refuser/$', 'savoirs.views.evenement_refuser'),
+    (r'^evenements/(.+)/$', 'savoirs.views.evenement'),
+
+    (r'^json/get/$', 'savoirs.views.json_get'),
+    (r'^json/set/$', 'savoirs.views.json_set'),
 )
 
 if settings.DEBUG:
index 9137342..4868ceb 100644 (file)
@@ -2,6 +2,7 @@
 parts = django
 find-links = http://pypi.auf.org/auf_savoirs_en_partage_backend/
     http://pypi.auf.org/auf_roa_authentification_backend/
+    http://pypi.auf.org/caldav/
 
 [django]
 recipe = djangorecipe
@@ -12,3 +13,6 @@ settings = production
 extra-paths = auf_savoirs_en_partage_django
 eggs = auf_savoirs_en_partage_backend
     auf_roa_authentification_backend
+    caldav
+    pytz
+    django-timezones