SlideShare a Scribd company logo
1 of 27
Download to read offline
Django e Backbone.js
  Uma parceria de sucesso


       Thiago Garcia
Quem?
thiagogds14


 thiagogds


 thiagogds

 thiagogds
Disclaimer
Por que Backbone?
Model
Collection
View



Text
Testes!!
• Jasmine.js: http://pivotal.github.com/jasmine/
• Jasmine-Jquery: https://github.com/velesin/jasmine-jquery
• Sinon.js: http://sinonjs.org/
• Jasmine-Sinon: https://github.com/froots/jasmine-sinon
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <title>Jasmine Spec Runner</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css">

  <script   src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  <script   type="text/javascript" src="../underscore-min.js"></script>
  <script   type="text/javascript" src="../handlebars-1.0.0.beta.6.js"></script>
  <script   type="text/javascript" src="../backbone-min.js"></script>
  <script   src="../bootstrap-datepicker.js"></script>
  <script   src="../bootstrap-datepicker.pt-BR.js"></script>
  <script   src="../rrule.js"></script>
  <script   src="../moment.min.js"></script>1
  <script   type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script>
  <script   type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script>
  <script   type="text/javascript" src="lib/sinon-1.5.0.js"></script>
  <script   type="text/javascript" src="lib/jasmine-sinon.js"></script>
  <script   type="text/javascript" src="lib/jasmine-jquery.js"></script>

  <!-- include source files here... -->
  <script type="text/javascript" src="../absenteeism.js"></script>

  <!-- include spec files here... -->
  <script type="text/javascript" src="spec/AbsenteeismSpec.js"></script>


  <script type="text/javascript">
    (function() {
      var jasmineEnv = jasmine.getEnv();
      jasmineEnv.updateInterval = 1000;

      var htmlReporter = new jasmine.HtmlReporter();

      jasmineEnv.addReporter(htmlReporter);

      jasmineEnv.specFilter = function(spec) {
describe("Absenteeism", function() {
    beforeEach(function() {
        this.initial_data = {
           'atested_begin': "03/01/2012",
           'atested_end': "04/01/2012",
           'revised_begin': "03/01/2012",
           'revised_end': "04/01/2012",
        };

          this.absenteeism = new Absenteeism(this.initial_data);
          this.absenteeismCollection = new AbsenteeismCollection([this.absenteeism])
          this.absenteeismReportView = new AbsenteeismReport({collection: this.absenteeismCollection})
    });
describe("AbsenteeismModel", function() {
    beforeEach(function() {
        this.eventSpy = sinon.spy();
    });
    describe("When validating", function() {
        it("should check that first atested date is lower then second date", function() {
            this.absenteeism.bind("error", this.eventSpy);

              this.initial_data["atested_end"] = "01/01/2012";
              this.absenteeism.set(this.initial_data);

              expect(this.eventSpy).toHaveBeenCalledOnce();
              expect(this.eventSpy).toHaveBeenCalledWith(
                  this.absenteeism,
                  "Data Final Atestadada não pode ser menor que a Data Inicial Atestada"
              );
        });
describe("AbsenteeismReport View", function() {
        beforeEach(function() {
            loadFixtures("absenteeism.html");
        });

        describe("When rendering", function() {
            it("should show the correct components", function() {
                this.absenteeismReportView.render();
                var atested_begin = $("input[name=atested_begin]");
                var atested_end = $("input[name=atested_end]");
                var revised_begin = $("input[name=revised_begin]");
                var revised_end = $("input[name=revised_end]");
                var dias_negados = $("span.difference");

                    expect(atested_begin).toHaveValue("03/01/2012");
                    expect(atested_end).toHaveValue("04/01/2012");
                    expect(revised_begin).toHaveValue("03/01/2012");
                    expect(revised_end).toHaveValue("04/01/2012");
              });
        });
Handlebars
                               http://handlebarsjs.com/

                   var abs_template_html = $('#absenteeism_form').html();
                   var abs_template = Handlebars.compile(abs_template_html);

                   $(this.el).html(abs_template(this.model.toJSON()));



{% verbatim %}
<script id="absenteeism_form" type="text/x-handlebars-template">
    <td><button class="close remove">&times;</button></td>
    <td>
      <input type="text" name="atested_begin" class="input-small" value="{{ atested_begin }}"><br>
      <input type="text" name="atested_end" class="input-small" value="{{ atested_end }}">
   </td>
    <td>
      <input type="text" name="revised_begin" class="input-small" value="{{ revised_begin }}"><br>
      <input type="text" name="revised_end" class="input-small" value="{{ revised_end }}">
    </td>
</script>
{% endverbatim %}
var strdt = function(str) {

}
    return moment(str, "DD/MM/YYYY").toDate();         http://momentjs.com/
window.Absenteeism = Backbone.Model.extend({
    validate: function(attributes) {
        var data_inicio_atestado = strdt(attributes.atested_begin);
        var data_fim_atestado = strdt(attributes.atested_end);
        var data_inicio_revisado = strdt(attributes.revised_begin);
        var data_fim_revisado = strdt(attributes.revised_end);

          if(data_inicio_atestado.getYear()   < 0 ||
             data_fim_atestado.getYear() <    0 ||
             data_inicio_revisado.getYear()   < 0 ||
             data_fim_revisado.getYear() <    0 ) {
              return "Data invÃálida";
          }

          if (data_fim_atestado < data_inicio_atestado) {
              return "Data Final Atestadada não pode ser menor que a Data Inicial Atestada";
          }
          if (data_fim_revisado < data_inicio_revisado) {
              return "Data Final Abonada não pode ser menor que a Data Inicial Abonada";
          }
          if (data_inicio_revisado < data_inicio_atestado) {
              return "Data Incial Abonada não pode ser menor que a Data Inicial Atestada";
          }
          if (data_fim_revisado > data_fim_atestado){
              return "Data Final Abonada não pode ser maior que a Data Final Atestada";
          }
      }
});
save: function() {
    var self = this;
    var post_data = {};
    var absenteeism = {};
    var values = [];
    this.collection.each(function(model) {
        values.push(model.toJSON());
    });
    absenteeism['adm_obs'] = $(this.el).find('textarea[name="adm_obs"]').val();
    absenteeism['medical_obs'] = $(this.el).find('textarea[name="medical_obs"]').val();
    absenteeism['entries'] = values;
    post_data['absenteeism'] = absenteeism;
    $.ajax({
        type: 'POST',
        url: window.post_url,
        data: {data: JSON.stringify(post_data)},
        success: function(data) {
             self.process_success(data);
        },
        error: function(data) {
             self.process_error(data);
        },
        dataType: 'json'
    });
},
window.Absenteeism = Backbone.Model.extend({
        validate: function(attributes) {
            var data_inicio_atestado = strdt(attributes.atested_begin);
            var data_fim_atestado = strdt(attributes.atested_end);
            var data_inicio_revisado = strdt(attributes.revised_begin);
            var data_fim_revisado = strdt(attributes.revised_end);

              if(data_inicio_atestado.getYear()   < 0 ||
                 data_fim_atestado.getYear() <    0 ||
                 data_inicio_revisado.getYear()   < 0 ||
                 data_fim_revisado.getYear() <    0 ) {
                  return "Data invÃálida";
              }

              if (data_fim_atestado < data_inicio_atestado) {
                  return "Data Final Atestadada não pode ser menor que a Data Inicial Atestada";
              }
              if (data_fim_revisado < data_inicio_revisado) {
                  return "Data Final Abonada não pode ser menor que a Data Inicial Abonada";
              }
              if (data_inicio_revisado < data_inicio_atestado) {
                  return "Data Incial Abonada não pode ser menor que a Data Inicial Atestada";
              }
              if (data_fim_revisado > data_fim_atestado){
                  return "Data Final Abonada não pode ser maior que a Data Final Atestada";
              }
          }
    });
window.AbsenteeismView = Backbone.View.extend({
        events: {
            'click .remove': 'remove',
            'blur input[name=atested_begin]': 'update_value',
            'blur input[name=atested_end]': 'update_value',
            'blur input[name=revised_begin]': 'update_value',
            'blur input[name=revised_end]': 'update_value'
        },
        tagName: 'tr',
        initialize: function() {
            _.bindAll(this, 'render');
            _.bindAll(this, 'remove');
            _.bindAll(this, 'update_value');
            _.bindAll(this, 'restore_view');
            this.model.on('error', this.restore_view);
        },
        render: function() {
            var abs_template_html = $('#absenteeism_form').html();
            var abs_template = Handlebars.compile(abs_template_html);

              $(this.el).html(abs_template(this.model.toJSON()));

             var self = this;
             $(this.el).find('input[type=text]').datepicker({
                 format: 'dd/mm/yyyy',
                 autoclose: true,
                 language: 'pt-BR',
             }).on('changeDate', function(ev) {
                 self.update_value(ev);
             });

              return this;
          },
          remove: function() {
              $(this.el).remove();
              this.model.collection.remove(this.model);
          },
          update_value: function(event) {
              var data_inicio_atestado = $(this.el).find('input[name=atested_begin]').val();
              var data_fim_atestado = $(this.el).find('input[name=atested_end]').val();
              var data_inicio_revisado = $(this.el).find('input[name=revised_begin]').val();
              var data_fim_revisado = $(this.el).find('input[name=revised_end]').val();

             this.model.set({
                 'atested_begin': data_inicio_atestado,
                 'atested_end': data_fim_atestado,
                 'revised_begin': data_inicio_revisado,
                 'revised_end': data_fim_revisado,
             });
          },
          restore_view: function(model, message) {
              $(this.el).find('input[name=atested_begin]').val(this.model.get('atested_begin'));
              $(this.el).find('input[name=atested_end]').val(this.model.get('atested_end'));
              $(this.el).find('input[name=revised_begin]').val(this.model.get('revised_begin'));
              $(this.el).find('input[name=revised_end]').val(this.model.get('revised_end'));
              $('#myModal .modal-body p').html(message);
              $('#myModal').modal('toggle');
          },
    });
window.AbsenteeismReport = Backbone.View.extend({
        events: {
            'click .add': 'add_entry',
            'click .confirm': 'save',
        },
        el: function () { return $('#main'); },
        initialize: function() {
            _.bindAll(this, 'render');
            _.bindAll(this, 'add');
            _.bindAll(this, 'add_entry');
            _.bindAll(this, 'save');
            _.bindAll(this, 'process_success');
            _.bindAll(this, 'process_error');
            this.collection.on('add', this.add);
        },
        render: function() {
            var view = $(this.el).find('#table_body');
            this.collection.each(function(model) {
                var model_view = new AbsenteeismView({model: model});
                view.append(model_view.render().el);
            });
            return this;
        },
        add: function(item) {
            var entry = new AbsenteeismView({model:item});
            $(this.el).find('#table_body').append(entry.render().el);
        },
        add_entry: function() {
            this.collection.add(new_absenteeism());
        },
        process_success: function (data) {
            alert(data.message);
        },
        process_error: function (data) {
            alert(data.responseText);
        },
        save: function() {
            var self = this;
            var post_data = {};
            var absenteeism = {};
            var values = [];
            this.collection.each(function(model) {
                values.push(model.toJSON());
            });
            absenteeism['adm_obs'] = $(this.el).find('textarea[name="adm_obs"]').val();
            absenteeism['medical_obs'] = $(this.el).find('textarea[name="medical_obs"]').val();
            absenteeism['entries'] = values;
            post_data['absenteeism'] = absenteeism;
            $.ajax({
                type: 'POST',
                url: window.post_url,
                data: {data: JSON.stringify(post_data)},
                success: function(data) {
                     self.process_success(data);
                },
                error: function(data) {
                     self.process_error(data);
                },
                dataType: 'json'
            });
        },
    });
window.AbsenteeismCollection = Backbone.Collection.extend({
    model: Absenteeism
});
Tá, e o Django?
def save(request):
    absenteeism_data = json.loads(request.POST['data'])
    absenteeism = absenteeism_data['absenteeism']

    absenteeism_entries = absenteeism['entries']
    absenteeism.pop('entries')
class AbsenteeismEntryForm(forms.ModelForm):

    class Meta:
        model = AbsenteeismEntry
        exclude = ('absenteeism',)

    def clean(self):
        super(AbsenteeismEntryForm, self).clean()

        if self.cleaned_data.get('atested_begin') > 
           self.cleaned_data.get('atested_end'):
            raise forms.ValidationError(
                u'Data Final Atestadada não pode ser menor que a Data Inicial Atestada')

        if self.cleaned_data.get('revised_begin') > 
           self.cleaned_data.get('revised_end'):
            raise forms.ValidationError(
                u'Data Final Abonada não pode ser menor que a Data Inicial Abonada')

        if self.cleaned_data.get('atested_begin') > 
           self.cleaned_data.get('revised_begin'):
            raise forms.ValidationError(
                u'Data Incial Abonada não pode ser menor que a Data Inicial Atestada')

        if self.cleaned_data.get('revised_end') > 
           self.cleaned_data.get('atested_end'):
            raise forms.ValidationError(
                u'Data Final Abonada não pode ser maior que a Data Final Atestada')

        return self.cleaned_data
return HttpResponse(json.dumps(dict(url="/success/")),
                    mimetype="application/json")
def save(request):
    absenteeism_data = json.loads(request.POST['data'])
    absenteeism = absenteeism_data['absenteeism']

    absenteeism_entries = absenteeism['entries']
    absenteeism.pop('entries')


    absenteeism_form = AbsenteeismForm(absenteeism)
    if absenteeism_form.is_valid():
        entries_form = []
        for entry in absenteeism_entries:
            entry_form = AbsenteeismEntryForm(entry)
            if entry_form.is_valid():
                entries_form.append(entry_form.cleaned_data)
            else:
                return HttpResponseServerError(json.dumps(entry_form.errors),
                                               mimetype="application/json")

    else:
        return HttpResponseServerError(json.dumps(absenteeism_form.errors),
                                       mimetype="application/json")


    new_absenteeism = absenteeism_form.save()
    for entry in entries_form:
        new_absenteeism.absenteeismentry_set.create(**entry)

    return HttpResponse(json.dumps(dict(message="Salvou com sucesso!")),
                        mimetype="application/json")
https://github.com/thiagogds/backbone-PyBR-8

More Related Content

What's hot

Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomlaguestebb21a
 
Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015chicagonewsyesterday
 
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...irwinvifxcfesre
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Offirwinvifxcfesre
 
jQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptjQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptNando Vieira
 
Working With Ajax Frameworks
Working With Ajax FrameworksWorking With Ajax Frameworks
Working With Ajax FrameworksJonathan Snook
 
התוסף הראשון שלי - וורדפרס
התוסף הראשון שלי - וורדפרסהתוסף הראשון שלי - וורדפרס
התוסף הראשון שלי - וורדפרסYoav Farhi
 
Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomlaguestebb21a
 
Drupal Cms Prezentace
Drupal Cms PrezentaceDrupal Cms Prezentace
Drupal Cms PrezentaceTomáš Kafka
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keefchicagonewsonlineradio
 
2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHPCarlos Pires
 
Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2André Tapia
 
Jquery Introduction Hebrew
Jquery Introduction HebrewJquery Introduction Hebrew
Jquery Introduction HebrewAlex Ivy
 
Check out our photos of the Pixies' Metro show
Check out our photos of the Pixies' Metro showCheck out our photos of the Pixies' Metro show
Check out our photos of the Pixies' Metro showchicagonewsyesterday
 

What's hot (20)

Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomla
 
Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015
 
Get more votes!
Get more votes!Get more votes!
Get more votes!
 
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off
 
Dwr实战
Dwr实战Dwr实战
Dwr实战
 
jQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptjQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe Javascript
 
Working With Ajax Frameworks
Working With Ajax FrameworksWorking With Ajax Frameworks
Working With Ajax Frameworks
 
iBatis course (beta)
iBatis course (beta)iBatis course (beta)
iBatis course (beta)
 
התוסף הראשון שלי - וורדפרס
התוסף הראשון שלי - וורדפרסהתוסף הראשון שלי - וורדפרס
התוסף הראשון שלי - וורדפרס
 
Quiz Component For Joomla
Quiz Component For JoomlaQuiz Component For Joomla
Quiz Component For Joomla
 
Drupal Cms Prezentace
Drupal Cms PrezentaceDrupal Cms Prezentace
Drupal Cms Prezentace
 
Best hotel
Best hotelBest hotel
Best hotel
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keef
 
2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP2km Workshop: Desenvolvimento ágil com o CakePHP
2km Workshop: Desenvolvimento ágil com o CakePHP
 
Code
CodeCode
Code
 
Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2Aller plus loin avec Doctrine2
Aller plus loin avec Doctrine2
 
Introducción a Bolt
Introducción a BoltIntroducción a Bolt
Introducción a Bolt
 
Jquery Introduction Hebrew
Jquery Introduction HebrewJquery Introduction Hebrew
Jquery Introduction Hebrew
 
Check out our photos of the Pixies' Metro show
Check out our photos of the Pixies' Metro showCheck out our photos of the Pixies' Metro show
Check out our photos of the Pixies' Metro show
 

Viewers also liked

Rocky shore
Rocky shoreRocky shore
Rocky shorejbron83
 
Heop 1102.pptx instrtech
Heop   1102.pptx instrtechHeop   1102.pptx instrtech
Heop 1102.pptx instrtechrjsnell82
 
登陆系统
登陆系统登陆系统
登陆系统playn
 
市场
市场市场
市场playn
 
Test security 2012-2013
Test security 2012-2013Test security 2012-2013
Test security 2012-2013Edunut
 

Viewers also liked (9)

Rocky shore
Rocky shoreRocky shore
Rocky shore
 
Nmdl wwhp
Nmdl wwhpNmdl wwhp
Nmdl wwhp
 
Heop 1102.pptx instrtech
Heop   1102.pptx instrtechHeop   1102.pptx instrtech
Heop 1102.pptx instrtech
 
登陆系统
登陆系统登陆系统
登陆系统
 
Ha lo halo
Ha lo   haloHa lo   halo
Ha lo halo
 
市场
市场市场
市场
 
Test security 2012-2013
Test security 2012-2013Test security 2012-2013
Test security 2012-2013
 
Motocontinuum FISL15
Motocontinuum FISL15Motocontinuum FISL15
Motocontinuum FISL15
 
Katana slide show
Katana slide showKatana slide show
Katana slide show
 

Palestra PythonBrasil[8]

  • 1. Django e Backbone.js Uma parceria de sucesso Thiago Garcia
  • 6.
  • 10. Testes!! • Jasmine.js: http://pivotal.github.com/jasmine/ • Jasmine-Jquery: https://github.com/velesin/jasmine-jquery • Sinon.js: http://sinonjs.org/ • Jasmine-Sinon: https://github.com/froots/jasmine-sinon
  • 11. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css"> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script type="text/javascript" src="../underscore-min.js"></script> <script type="text/javascript" src="../handlebars-1.0.0.beta.6.js"></script> <script type="text/javascript" src="../backbone-min.js"></script> <script src="../bootstrap-datepicker.js"></script> <script src="../bootstrap-datepicker.pt-BR.js"></script> <script src="../rrule.js"></script> <script src="../moment.min.js"></script>1 <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script> <script type="text/javascript" src="lib/sinon-1.5.0.js"></script> <script type="text/javascript" src="lib/jasmine-sinon.js"></script> <script type="text/javascript" src="lib/jasmine-jquery.js"></script> <!-- include source files here... --> <script type="text/javascript" src="../absenteeism.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/AbsenteeismSpec.js"></script> <script type="text/javascript"> (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) {
  • 12. describe("Absenteeism", function() { beforeEach(function() { this.initial_data = { 'atested_begin': "03/01/2012", 'atested_end': "04/01/2012", 'revised_begin': "03/01/2012", 'revised_end': "04/01/2012", }; this.absenteeism = new Absenteeism(this.initial_data); this.absenteeismCollection = new AbsenteeismCollection([this.absenteeism]) this.absenteeismReportView = new AbsenteeismReport({collection: this.absenteeismCollection}) });
  • 13. describe("AbsenteeismModel", function() { beforeEach(function() { this.eventSpy = sinon.spy(); }); describe("When validating", function() { it("should check that first atested date is lower then second date", function() { this.absenteeism.bind("error", this.eventSpy); this.initial_data["atested_end"] = "01/01/2012"; this.absenteeism.set(this.initial_data); expect(this.eventSpy).toHaveBeenCalledOnce(); expect(this.eventSpy).toHaveBeenCalledWith( this.absenteeism, "Data Final Atestadada não pode ser menor que a Data Inicial Atestada" ); });
  • 14. describe("AbsenteeismReport View", function() { beforeEach(function() { loadFixtures("absenteeism.html"); }); describe("When rendering", function() { it("should show the correct components", function() { this.absenteeismReportView.render(); var atested_begin = $("input[name=atested_begin]"); var atested_end = $("input[name=atested_end]"); var revised_begin = $("input[name=revised_begin]"); var revised_end = $("input[name=revised_end]"); var dias_negados = $("span.difference"); expect(atested_begin).toHaveValue("03/01/2012"); expect(atested_end).toHaveValue("04/01/2012"); expect(revised_begin).toHaveValue("03/01/2012"); expect(revised_end).toHaveValue("04/01/2012"); }); });
  • 15. Handlebars http://handlebarsjs.com/ var abs_template_html = $('#absenteeism_form').html(); var abs_template = Handlebars.compile(abs_template_html); $(this.el).html(abs_template(this.model.toJSON())); {% verbatim %} <script id="absenteeism_form" type="text/x-handlebars-template"> <td><button class="close remove">&times;</button></td> <td> <input type="text" name="atested_begin" class="input-small" value="{{ atested_begin }}"><br> <input type="text" name="atested_end" class="input-small" value="{{ atested_end }}"> </td> <td> <input type="text" name="revised_begin" class="input-small" value="{{ revised_begin }}"><br> <input type="text" name="revised_end" class="input-small" value="{{ revised_end }}"> </td> </script> {% endverbatim %}
  • 16. var strdt = function(str) { } return moment(str, "DD/MM/YYYY").toDate(); http://momentjs.com/ window.Absenteeism = Backbone.Model.extend({ validate: function(attributes) { var data_inicio_atestado = strdt(attributes.atested_begin); var data_fim_atestado = strdt(attributes.atested_end); var data_inicio_revisado = strdt(attributes.revised_begin); var data_fim_revisado = strdt(attributes.revised_end); if(data_inicio_atestado.getYear() < 0 || data_fim_atestado.getYear() < 0 || data_inicio_revisado.getYear() < 0 || data_fim_revisado.getYear() < 0 ) { return "Data invÃálida"; } if (data_fim_atestado < data_inicio_atestado) { return "Data Final Atestadada não pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado < data_inicio_revisado) { return "Data Final Abonada não pode ser menor que a Data Inicial Abonada"; } if (data_inicio_revisado < data_inicio_atestado) { return "Data Incial Abonada não pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado > data_fim_atestado){ return "Data Final Abonada não pode ser maior que a Data Final Atestada"; } } });
  • 17. save: function() { var self = this; var post_data = {}; var absenteeism = {}; var values = []; this.collection.each(function(model) { values.push(model.toJSON()); }); absenteeism['adm_obs'] = $(this.el).find('textarea[name="adm_obs"]').val(); absenteeism['medical_obs'] = $(this.el).find('textarea[name="medical_obs"]').val(); absenteeism['entries'] = values; post_data['absenteeism'] = absenteeism; $.ajax({ type: 'POST', url: window.post_url, data: {data: JSON.stringify(post_data)}, success: function(data) { self.process_success(data); }, error: function(data) { self.process_error(data); }, dataType: 'json' }); },
  • 18. window.Absenteeism = Backbone.Model.extend({ validate: function(attributes) { var data_inicio_atestado = strdt(attributes.atested_begin); var data_fim_atestado = strdt(attributes.atested_end); var data_inicio_revisado = strdt(attributes.revised_begin); var data_fim_revisado = strdt(attributes.revised_end); if(data_inicio_atestado.getYear() < 0 || data_fim_atestado.getYear() < 0 || data_inicio_revisado.getYear() < 0 || data_fim_revisado.getYear() < 0 ) { return "Data invÃálida"; } if (data_fim_atestado < data_inicio_atestado) { return "Data Final Atestadada não pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado < data_inicio_revisado) { return "Data Final Abonada não pode ser menor que a Data Inicial Abonada"; } if (data_inicio_revisado < data_inicio_atestado) { return "Data Incial Abonada não pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado > data_fim_atestado){ return "Data Final Abonada não pode ser maior que a Data Final Atestada"; } } });
  • 19. window.AbsenteeismView = Backbone.View.extend({ events: { 'click .remove': 'remove', 'blur input[name=atested_begin]': 'update_value', 'blur input[name=atested_end]': 'update_value', 'blur input[name=revised_begin]': 'update_value', 'blur input[name=revised_end]': 'update_value' }, tagName: 'tr', initialize: function() { _.bindAll(this, 'render'); _.bindAll(this, 'remove'); _.bindAll(this, 'update_value'); _.bindAll(this, 'restore_view'); this.model.on('error', this.restore_view); }, render: function() { var abs_template_html = $('#absenteeism_form').html(); var abs_template = Handlebars.compile(abs_template_html); $(this.el).html(abs_template(this.model.toJSON())); var self = this; $(this.el).find('input[type=text]').datepicker({ format: 'dd/mm/yyyy', autoclose: true, language: 'pt-BR', }).on('changeDate', function(ev) { self.update_value(ev); }); return this; }, remove: function() { $(this.el).remove(); this.model.collection.remove(this.model); }, update_value: function(event) { var data_inicio_atestado = $(this.el).find('input[name=atested_begin]').val(); var data_fim_atestado = $(this.el).find('input[name=atested_end]').val(); var data_inicio_revisado = $(this.el).find('input[name=revised_begin]').val(); var data_fim_revisado = $(this.el).find('input[name=revised_end]').val(); this.model.set({ 'atested_begin': data_inicio_atestado, 'atested_end': data_fim_atestado, 'revised_begin': data_inicio_revisado, 'revised_end': data_fim_revisado, }); }, restore_view: function(model, message) { $(this.el).find('input[name=atested_begin]').val(this.model.get('atested_begin')); $(this.el).find('input[name=atested_end]').val(this.model.get('atested_end')); $(this.el).find('input[name=revised_begin]').val(this.model.get('revised_begin')); $(this.el).find('input[name=revised_end]').val(this.model.get('revised_end')); $('#myModal .modal-body p').html(message); $('#myModal').modal('toggle'); }, });
  • 20. window.AbsenteeismReport = Backbone.View.extend({ events: { 'click .add': 'add_entry', 'click .confirm': 'save', }, el: function () { return $('#main'); }, initialize: function() { _.bindAll(this, 'render'); _.bindAll(this, 'add'); _.bindAll(this, 'add_entry'); _.bindAll(this, 'save'); _.bindAll(this, 'process_success'); _.bindAll(this, 'process_error'); this.collection.on('add', this.add); }, render: function() { var view = $(this.el).find('#table_body'); this.collection.each(function(model) { var model_view = new AbsenteeismView({model: model}); view.append(model_view.render().el); }); return this; }, add: function(item) { var entry = new AbsenteeismView({model:item}); $(this.el).find('#table_body').append(entry.render().el); }, add_entry: function() { this.collection.add(new_absenteeism()); }, process_success: function (data) { alert(data.message); }, process_error: function (data) { alert(data.responseText); }, save: function() { var self = this; var post_data = {}; var absenteeism = {}; var values = []; this.collection.each(function(model) { values.push(model.toJSON()); }); absenteeism['adm_obs'] = $(this.el).find('textarea[name="adm_obs"]').val(); absenteeism['medical_obs'] = $(this.el).find('textarea[name="medical_obs"]').val(); absenteeism['entries'] = values; post_data['absenteeism'] = absenteeism; $.ajax({ type: 'POST', url: window.post_url, data: {data: JSON.stringify(post_data)}, success: function(data) { self.process_success(data); }, error: function(data) { self.process_error(data); }, dataType: 'json' }); }, });
  • 22. Tá, e o Django?
  • 23. def save(request): absenteeism_data = json.loads(request.POST['data']) absenteeism = absenteeism_data['absenteeism'] absenteeism_entries = absenteeism['entries'] absenteeism.pop('entries')
  • 24. class AbsenteeismEntryForm(forms.ModelForm): class Meta: model = AbsenteeismEntry exclude = ('absenteeism',) def clean(self): super(AbsenteeismEntryForm, self).clean() if self.cleaned_data.get('atested_begin') > self.cleaned_data.get('atested_end'): raise forms.ValidationError( u'Data Final Atestadada não pode ser menor que a Data Inicial Atestada') if self.cleaned_data.get('revised_begin') > self.cleaned_data.get('revised_end'): raise forms.ValidationError( u'Data Final Abonada não pode ser menor que a Data Inicial Abonada') if self.cleaned_data.get('atested_begin') > self.cleaned_data.get('revised_begin'): raise forms.ValidationError( u'Data Incial Abonada não pode ser menor que a Data Inicial Atestada') if self.cleaned_data.get('revised_end') > self.cleaned_data.get('atested_end'): raise forms.ValidationError( u'Data Final Abonada não pode ser maior que a Data Final Atestada') return self.cleaned_data
  • 26. def save(request): absenteeism_data = json.loads(request.POST['data']) absenteeism = absenteeism_data['absenteeism'] absenteeism_entries = absenteeism['entries'] absenteeism.pop('entries') absenteeism_form = AbsenteeismForm(absenteeism) if absenteeism_form.is_valid(): entries_form = [] for entry in absenteeism_entries: entry_form = AbsenteeismEntryForm(entry) if entry_form.is_valid(): entries_form.append(entry_form.cleaned_data) else: return HttpResponseServerError(json.dumps(entry_form.errors), mimetype="application/json") else: return HttpResponseServerError(json.dumps(absenteeism_form.errors), mimetype="application/json") new_absenteeism = absenteeism_form.save() for entry in entries_form: new_absenteeism.absenteeismentry_set.create(**entry) return HttpResponse(json.dumps(dict(message="Salvou com sucesso!")), mimetype="application/json")