Пример #1
0
define(function(require) {
  /**
   * 
   * Extends Backbone.View
   * @exports views/admin/ClinicDetailsView
   */
  var jquery                  = require('libs/jquery'),
      underscore              = require('libs/underscore'),
      Backbone                = require('libs/backbone'),
      Clinic                  = require('models/ClinicList'),
      clinicDetailsTpl        = require('text!/templates/admin/admin-clinic-details-tpl.html');

  ClinicDetailsView = Backbone.View.extend({

    initialize: function () {
      if (this.model != undefined | null) {
        this.model.on('updated', this.render, this);
      }
    },

    className: 'clinic-details-el',

    render: function() {
      if (this.model == undefined || null) return this;
      var tpl = _.template(clinicDetailsTpl, {clinic: this.model.toJSON()});
      $(this.el).html(tpl);
      this.delegateEvents();
      return this;
    },

    events: {
      'click #myonoffswitch': 'onActiveToggle'
    },

    /** 
     * Change the model the instance of ClinicDetailsView is listening to.
     * @param {Clinic} newModel - The new model the view is to listen to.
     * An instance of Clinic.
     */
    changeModel: function(newModel) {
      this.model = newModel;
      this.render();
      this.model.on('updated', this.render, this);
    },

    onActiveToggle: function() {
      var checked = $(this.el).find('input:checkbox:checked');
      var isActive = (checked.length == 0) ? 0 : 1;
      this.model.set({
        isActive: isActive
      });

      this.model.put();
    }

  });

  return ClinicDetailsView;

});
Пример #2
0
define(function(require) {
  /**
   * Renders and manages events associated with a list element of the list of
   * categories in the category management window on the administrative page.
   * Extends Backbone.View
   * @exports views/admin/CategoryListElementView
   */
  var jquery              = require('libs/jquery'),
      underscore          = require('libs/underscore'),
      Backbone            = require('libs/backbone'),
      Category            = require('models/InterestCategory'),
      categoryListElemTpl = require('text!/templates/admin/category-list-element-tpl.html');

  CategoryListElementView = Backbone.View.extend({

    initialize: function(options) {
      /** Reference to parent view.  Instance of CategoryListView. */
      this.parent = options.parent;

      this.model.on('destroyed', this.onModelDestroyed, this);
    },

    /** Class name of the <div> DOM element into which this view will render its
     * template. */
    className: 'category-list-elem-el',

    /** Render view template into this.el */
    render: function() {
      var tpl = _.template(categoryListElemTpl, {category: this.model.toJSON()});
      $(this.el).html(tpl);
      this.delegateEvents();
      return this;
    },

    events: {
      'click .delete-category-btn': 'onCategoryDelete'
    },

    onCategoryDelete: function() {
      this.model.destroy();
    },

    onModelDestroyed: function() {
      this.parent.trigger('categoryDestroyed', this.model);
    },

  });

  return CategoryListElementView;

});
Пример #3
0
define(function(require) {
  /**
   * Renders templates and manages events associated with zoomed picture view
   * modal window displayable on pet profile page.
   * Extends Backbone.View
   * @exports views/pet/ZoomPictureView
   */
  var jquery            = require('libs/jquery'),
    underscore          = require('libs/underscore'),
    Backbone            = require('libs/backbone'),
    Picture             = require('models/Picture'),
    zoomPictureTpl      = require('text!/templates/pet/zoom-picture-window-tpl.html');

  ZoomPictureView = Backbone.View.extend({

    initialize: function() {
      /** The model to which this view listens.  Instance of Picture. */
      this.model;

      if (this.model != undefined) this.delegateListeners();
    },

    /** The class of <div> element appended to the DOM into which this
     * view renders its template. */
    className: 'zoom-picture-el',

    /** Render view template into this.el */
    render: function() {
      var tpl = _.template(zoomPictureTpl, {picture: this.model.toJSON()});
      $(this.el).html(tpl);
      this.delegateEvents();
      return this;
    },

    /** Defines DOM event listeners and callbacks. */
    events: {
      'click #edit-description-btn': 'renderEditView',
      'click #save-description-btn': 'onSaveDescription'
    },

    /** 
     * Called to change the model to which this view listens.
     * @param {Picture} newModel - the new model to which this view is to listen
     */
    changeModel: function(newModel) {
      this.unbind();
      this.undelegateEvents();
      this.$el.off();
      this.model = newModel;
      this.delegateListeners();
      this.render();
    },

    /** Define model event listeners and callbacks. */
    delegateListeners: function() {
      this.model.on('updated', this.renderRegularView, this);
    },

    /**
     * Replace picture description with editable text box.
     */
    renderEditView: function() {
      var description = $(this.el).find('.description').html();
      var textBoxEl = $('<textarea rows="10" maxlength="120">').val(description);
      $(this.el).find('#description').html(textBoxEl);
      $(this.el).find('#edit-description-btn').html('Save Description &nbsp;&nbsp;');
      $(this.el).find('#edit-description-btn').append($('<i>').addClass('glyphicon')
        .addClass('glyphicon-save'));
      $(this.el).find('#edit-description-btn').attr('id', 'save-description-btn');
      this.delegateEvents();
    },
    /**
     * Callback to click of save description button.  Sets model attributes
     * and calls Picture.put()
     */
    onSaveDescription: function() {
      this.model.set({description: $(this.el).find('textarea').val()});
      this.model.put();
    },

    /**
     * Redisplay the comment associated with the picture in a non-editable
     * way
     */
    renderRegularView: function() {
      var description = $(this.el).find('textarea').val();
      $(this.el).find('#description').html($('<span>').addClass('description')
        .html(description));
      $(this.el).find('#save-description-btn')
        .html('Edit Picture Description&nbsp;&nbsp;');
      $(this.el).find('#save-description-btn').append($('<i>').addClass('glyphicon')
        .addClass('glyphicon-edit'));
      $(this.el).find('#save-description-btn').attr('id', 'edit-description-btn');
      this.delegateEvents();        
    },

    /** Display modal window associated with this view. */
    show: function() {
      $(this.el).find('#zoom-picture-window').modal('show');
    },

    /** Hide modal window associated with this view. */
    hide: function() {
      $(this.el).find('#zoom-picture-window').modal('hide');
    }

  });

  return ZoomPictureView;

});
Пример #4
0
define(function(require) {
  /**
   * Owner profile view.  Manages rendering of elements of owner profile.
   * Extends Backbone.View
   * @exports views/owner/OwnerView
   */
  var jquery                       = require('libs/jquery'),
    underscore                     = require('libs/underscore'),
    Backbone                       = require('libs/backbone'),
    Owner                          = require('models/Owner'),
    OwnerSidebarView               = require('views/owner/OwnerSidebarView'),
    PetAchievementCompletionView   = require('views/owner/PetAchievementCompletionView'),
    PetListView                    = require('views/owner/PetListView'),
    AddPetModalView                = require('views/owner/AddPetModalView');

  OwnerView = Backbone.View.extend({

    initialize: function() {
      this.isOwnerFetched = false;
      this.on('addPet', this.onAddPet, this);
      this.delegateListeners();
    },

    /** Render View templates into associated DOM element. */
    render: function() {
      // If the owner has not yet been fetched, return.
      // Note that we are guaranteed that the owner will never be fetched 
      // at the time of instantiation of ownerView.
      if (!this.isOwnerFetched) return this;
      this.renderAchievementsView();
      this.renderSidebarView();
      this.delegateEvents();
      return this;
    },

    delegateListeners: function() {
      this.model.on('fetched', this.onFetch, this);
    },
// Content rendering functions. -----------------------------------------------/

    /**
     * Instantiate instance of OwnerSidebarView and render it.
     */
    renderSidebarView: function() {
      if (this.sidebarView == undefined | null) {
        this.sidebarView = new OwnerSidebarView (
          {
            model: this.model,
            parent: this
          }
        );
      }
      this.sidebarView.render();
      $('#profile-sidebar').html(this.sidebarView.el);
    },

    /**
     *  Instantiate instance of PetAchievementCompletionView and render it. 
     */
    renderAchievementsView: function() {
      if (this.achievementsView == undefined | null) {
        this.achievementsView = new PetAchievementCompletionView(
          {
            model: this.model
          }
        );
      }
      $('#profile-content').html(this.achievementsView.render().el);
    },

    /**
     * Callback to 'fetch' event triggered by the instance of Owner model
     * to which this view listens.
     */
    onFetch: function() {
      this.isOwnerFetched = true;
      this.render();
    },

    /**
     * Callback to click of "addPet button".  Instantiates instance of 
     * AddPetModalView, renders it, and displays the modal window
     * associated with the view.
     */
    onAddPet: function() {
      if (this.addPetView == undefined | null) {
        this.addPetView = new AddPetModalView({
          model: Pet.findOrCreate({id: -2, owner: this.model}),
          owner: this.model
        });
        $('body').append(this.addPetView.render().el);
      } else {
        this.addPetView.render();
      }

      this.addPetView.show();
    }
  });

  return OwnerView;

});
Пример #5
0
export var ToursView = Backbone.View.extend({
    title: _l("Tours"),
    initialize: function() {
        var self = this;
        this.setElement("<div/>");
        this.model = new Tours();
        this.model.fetch({
            success: function() {
                self.render();
            },
            error: function() {
                // Do something.
                console.error("Failed to fetch tours.");
            }
        });
    },

    render: function() {
        var tpl = _.template(TOURPAGE_TEMPLATE);

        var tourtags = {};
        _.each(this.model.models, tour => {
            if (tour.attributes.tags === null) {
                if (tourtags.Untagged === undefined) {
                    tourtags.Untagged = { name: "Untagged", tours: [] };
                }
                tourtags.Untagged.tours.push(tour);
            } else {
                _.each(tour.attributes.tags, tag => {
                    tag = tag.charAt(0).toUpperCase() + tag.slice(1);
                    if (tourtags[tag] === undefined) {
                        tourtags[tag] = { name: tag, tours: [] };
                    }
                    tourtags[tag].tours.push(tour);
                });
            }
        });
        var tourtagorder = Object.keys(tourtags).sort();

        this.$el
            .html(
                tpl({
                    tours: this.model.models,
                    tourtags: tourtags,
                    tourtagorder: tourtagorder
                })
            )
            .on("click", ".tourItem", function(e) {
                e.preventDefault();
                giveTourById($(this).data("tour.id"));
            })
            .on("click", ".tag-selector-button", e => {
                var elem = $(e.target);
                var display = "block";
                var tag = elem.attr("tag-selector-button");

                elem.toggleClass("btn-primary");
                elem.toggleClass("btn-secondary");

                if (elem.hasClass("btn-secondary")) {
                    display = "none";
                }
                $(`div[tag='${tag}']`).css({ display: display });
            });
    }
});
define(function(require) {
  /**
   * Renders and manages events related to an element in the list of 
   * achievement sets on the achievements manage page in the administrative
   * console page.
   * Extends Backbone.View
   * @xports views/admin/AchievementSetListElementView
   */
  var jquery                      = require('libs/jquery'),
    underscore                    = require('libs/underscore'),
    Backbone                      = require('libs/backbone'),
    AchievementSet                = require('models/AchievementSetList'),
    DeleteAchievementSetModalView = require('views/admin/DeleteAchievementSetModalView'),
    asleViewTpl                   = require('text!/templates/admin/achievement-set-list-element-tpl.html');

  AchievementSetListElementView = Backbone.View.extend({

    initialize: function(options) {
      /** Reference to parent view.  Instance of AchievementSetListView. */
      this.parent = options.parent;

      /** Subview handling the deletion of an achievement set.  Instance of
       * DeleteAchievementSetModalView. */
      this.deleteAchievementSetView;

    },

    /** Class name of <div> DOM element into which this view renders its 
     * template. */
    className: 'asle-el',

    /** Render view template into this.el */
    render: function() {
      var tpl = _.template(asleViewTpl, {set: this.model.toJSON()});
      $(this.el).html(tpl);
      this.delegateEvents();
      return this;
    },

    /** Register DOM event listeners and callbacks. */
    events: {
      'click': 'onSetClick',
      'click .delete-achievement-set-btn': 'onDeleteSet'
    },

    /** Callback to click of list element.  Triggers 'setClick' event on parent
     * view. */
    onSetClick: function() {
      this.parent.trigger('setClick', this);
    },

    /**
     * Callback to click of achievement set deletion button.
     * Displays confirmation window.
     */
    onDeleteSet: function() {
      if (this.deleteAchievementSetView == undefined) {
        this.deleteAchievementSetView = new DeleteAchievementSetModalView({
          model: this.model
        });
        this.deleteAchievementSetView.changeModel(this.model);
        $('body').append(this.deleteAchievementSetView.render().el);
      }
      this.deleteAchievementSetView.show();
    },

  });
  return AchievementSetListElementView;
});
Пример #7
0
var ConfigSettingCollectionView = Backbone.View.extend({
    className: "config-settings-view",

    /**
     * Renders form for editing configuration settings.
     */
    render: function() {
        var container = this.$el;

        this.collection.each((param, index) => {
            // Hidden params have no representation in the form
            if (param.get("hidden")) {
                return;
            }

            // Build row for param.
            var id = `param_${index}`;

            var type = param.get("type");
            var value = param.get("value");
            var row = $("<div class='form-row' />").appendTo(container);
            row.append(
                $("<label />")
                    .attr("for", id)
                    .text(`${param.get("label")}:`)
            );
            // Draw parameter as checkbox
            if (type === "bool") {
                row.append(
                    $('<input type="checkbox" />')
                        .attr("id", id)
                        .attr("name", id)
                        .attr("checked", value)
                );
            } else if (type === "text") {
                // Draw parameter as textbox
                row.append(
                    $('<input type="text"/>')
                        .attr("id", id)
                        .val(value)
                        .click(function() {
                            $(this).select();
                        })
                );
            } else if (type === "select") {
                // Draw parameter as select area
                var select = $("<select />").attr("id", id);
                _.each(param.get("options"), option => {
                    $("<option/>")
                        .text(option.label)
                        .attr("value", option.value)
                        .appendTo(select);
                });
                select.val(value);
                row.append(select);
            } else if (type === "color") {
                // Draw parameter as color picker
                var container_div = $("<div/>").appendTo(row);

                var input = $("<input />")
                    .attr("id", id)
                    .attr("name", id)
                    .val(value)
                    .css("float", "left")
                    .appendTo(container_div)
                    .click(function(e) {
                        // Hide other pickers.
                        $(".tooltip").removeClass("in");

                        // Show input's color picker.
                        var tip = $(this)
                            .siblings(".tooltip")
                            .addClass("in");
                        tip.css({
                            // left: $(this).position().left + ( $(input).width() / 2 ) - 60,
                            // top: $(this).position().top + $(this.height)
                            left: $(this).position().left + $(this).width() + 5,
                            top: $(this).position().top - $(tip).height() / 2 + $(this).height() / 2
                        }).show();

                        // Click management:

                        // Keep showing tip if clicking in tip.
                        tip.click(e => {
                            e.stopPropagation();
                        });

                        // Hide tip if clicking outside of tip.
                        $(document).bind("click.color-picker", () => {
                            tip.hide();
                            $(document).unbind("click.color-picker");
                        });

                        // No propagation to avoid triggering document click (and tip hiding) above.
                        e.stopPropagation();
                    });
                // Icon for setting a new random color; behavior set below.
                var new_color_icon = $("<a href='javascript:void(0)'/>")
                    .addClass("icon-button arrow-circle")
                    .appendTo(container_div)
                    .attr("title", "Set new random color")
                    .tooltip();

                // Color picker in tool tip style.
                var tip = $("<div class='tooltip right' style='position: absolute;' />")
                    .appendTo(container_div)
                    .hide();

                // Inner div for padding purposes
                var tip_inner = $("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(tip);

                $("<div class='tooltip-arrow'></div>").appendTo(tip);

                var farb_obj = $.farbtastic(tip_inner, {
                    width: 100,
                    height: 100,
                    callback: input,
                    color: value
                });

                // Clear floating.
                container_div.append($("<div/>").css("clear", "both"));

                // Use function to fix farb_obj value.
                (fixed_farb_obj => {
                    new_color_icon.click(() => {
                        fixed_farb_obj.setColor(util_mod.get_random_color());
                    });
                })(farb_obj);
            } else {
                row.append(
                    $("<input />")
                        .attr("id", id)
                        .attr("name", id)
                        .val(value)
                );
            }
            // Help text
            if (param.help) {
                row.append($("<div class='help'/>").text(param.help));
            }
        });

        return this;
    },

    /**
     * Render view in modal.
     */
    render_in_modal: function(title) {
        // Set up handlers for cancel, ok button and for handling esc key.
        var self = this;

        var cancel_fn = () => {
            Galaxy.modal.hide();
            $(window).unbind("keypress.check_enter_esc");
        };

        var ok_fn = () => {
            Galaxy.modal.hide();
            $(window).unbind("keypress.check_enter_esc");
            self.update_from_form();
        };

        var check_enter_esc = e => {
            if ((e.keyCode || e.which) === 27) {
                // Escape key
                cancel_fn();
            } else if ((e.keyCode || e.which) === 13) {
                // Enter key
                ok_fn();
            }
        };

        // Set keypress handler.
        $(window).bind("keypress.check_enter_esc", check_enter_esc);

        // Show modal.
        if (this.$el.children().length === 0) {
            this.render();
        }
        Galaxy.modal.show({
            title: title || "Configure",
            body: this.$el,
            buttons: {
                Cancel: cancel_fn,
                OK: ok_fn
            }
        });
    },

    /**
     * Update settings with new values entered via form.
     */
    update_from_form: function() {
        var self = this;
        this.collection.each((setting, index) => {
            if (!setting.get("hidden")) {
                // Set value from view.
                var id = `param_${index}`;
                var value = self.$el.find(`#${id}`).val();
                if (setting.get("type") === "bool") {
                    value = self.$el.find(`#${id}`).is(":checked");
                }
                setting.set_value(value);
            }
        });
    }
});
Пример #8
0
define(function (require, exports, module) {
    
    var _          = require('libs/underscore'),
        Backbone   = require('libs/backbone'),
        $          = require('libs/jqueryui'),
        Busy       = require('libs/busy'),
        Mustache   = require('libs/mustache');
        //Test       = require('app/models/test.js'),
        //TestList   = require('app/models/tests.js');

     module.exports    = Backbone.View.extend({
        events    : {
            "click .submit" : "save",
            "click .reset"  : "reset"
        },
        initialize : function () {
            //_.bindAll(this,'render');
            //this.model.bind('change', this.render);
            this.render();
        },
        reset      : function () {
            this.$("form")[0].reset();
            return false;
        },
        render     : function () {
            var self  = this,
                url   = 'assets/views/addTest.html',
                content = $("#main-wrap");

            //显示加载状态
            this._dealLoad(content[0], 'addViewLoad');

            //加载view
            $.get( url, function (data) {
                $(self.el).html(Mustache.to_html(data, self.model.toJSON() ) );
                self.$(".button a").button();
                content.html(self.el);
                module.load('libs/ckeditor/ckeditor',function () {
                    CKEDITOR.replace("tDescribe");
                }); 
                self.trigger('addViewLoad');
            });
        },
        /**
         *
         * 增加测试,表单提交时触发此函数
         */
        save      : function () {
            var self = this;
            this._dealLoad(self.el,'saveTest');
            var tDescribe = '';
            if(CKEDITOR) {
                tDescribe = CKEDITOR.instances.tDescribe.getData();
            }

            var data = {
                tTitle    : this.$('[name=tTitle]').val(),
                tDescribe : tDescribe || this.$('[name=tDescribe]').val()
            };

            var message = this.model.isNew() ? "成功创建测试" : "修改成功";
            this.model.save(data,
            {
                success   : function () {
                    var json = {};
                    json.message = message;

                    json.buttons = [{
                        text   : '好了,就这样吧',
                        click  : function () { 
                            $(this).dialog("close");
                            CKEDITOR && CKEDITOR.instances['tDescribe'].destroy();
                            self.trigger('testSaved','tests/lists');
                        }
                    },
                    {
                        text   : '继续修改',
                        click : function () {
                            $(this).dialog("close");
                        }
                    }];

                    self._tips('success', json);
                },
                error     : function (model,error) {
                    self._tips('error', error );
                }
            });

            return false;
        },
        /**
         *
         * 控制加载状态提示
         * @param node HTMLDOM the node show the loading images
         * @param event String 加载完成的事件
         * @param obj   Object 绑定事件的对象
         */
        _dealLoad : function (node, event, obj) {
            var loading = Busy(node);

            obj = obj || this;
            obj.bind(event, function () {
                loading.remove();
            });
        },
        _tips     : function (type, message) {
            var self = this;
            module.load('app/tips', function (Tips) {
                var tip = new Tips({'position': ['center',100]});
                self.trigger("saveTest");
                if( type === 'error' )
                    tip.error(message);
                else
                    tip.success(message);

                tip = undefined;
            });
        }

    });
});
Пример #9
0
define(function(require) {
  /**
   * View used in administrative console.  Responsible for managing the rendering of
   * ManageInterestsView, ManageClinicsView, and ManageAchievementsView. 
   * Extends Backbone.View
   * @exports views/admin/AdminConsoleView
   */
  var jquery              = require('libs/jquery'),
    underscore            = require('libs/underscore'),
    Backbone              = require('libs/backbone'),
    Admin                 = require('models/Admin'),
    adminConsoleTpl       = require('text!/templates/admin/admin-console-tpl.html');

    AdminConsoleView = Backbone.View.extend({

      initialize: function() {

      },

      /** The element this view renders its template into. */
      el: 'body',

      /** Render View template into this.el */
      render: function() {
        var tpl = _.template(adminConsoleTpl, {admin: this.model});
        $(this.el).html(tpl);
      },

      /** Defines event listeners and callbacks. */
      events: {
        'click #manage-clinics-btn':   'showClinics',
        'click #manage-interests-btn': 'showInterests',
        'click #manage-accounts-btn':   'showAccounts',
        'click #manage-achievements-btn': 'showAchievements'
      },

      /** 
       * Highlights the option in the console sidebar given the by the query.
       * @param {string} query - The query to select the element to which to
       * add the highlighting.
       */
      highlightOption: function(query) {
        $(this.el).find('.selection-highlighter').remove();
        $(this.el).find('.selected').removeClass('selected');
        $(this.el).find(query).addClass('selected');
        $(this.el)
          .find(query)
          .prepend($('<span>')
          .addClass('selection-highlighter').html('&nbsp;'));
      },

// Event callback functions ---------------------------------------------------/
      /**
       * Callback on Manage Interest button click.  Routes user to appropriate
       * url such ManageInterestView will be rendered.
       */
      showInterests: function() {
        this.highlightOption('#manage-interests-btn');
        router.navigate('/admin/' + this.model.get('id') + '/interests', true);
      },

      /** 
       * Callback on Manage Clinics button click.  Routes user to appropriate
       * url such that ManageClinicView will be rendered. 
       */
      showClinics: function() {
        this.highlightOption('#manage-clinics-btn');
        router.navigate('/admin/' + this.model.get('id') + '/clinics', true);
      },

      /** 
       * Callback on Manage Accounts button click.  Routes user to appropriate
       * url such that ManageAccountsView will be rendered. 
       */
      showAccounts: function() {
        this.highlightOption('#manage-accounts-btn');
        router.navigate('/admin/' + this.model.get('id') + '/accounts', true);
      },

      /** Callback on Manage Achievement button click.  Routes user to 
       * appropriate url sucht hat the ManageAhievementsView will be rendered. */
      showAchievements: function() {
        this.highlightOption('#manage-achievements-btn');
        router.navigate('/admin/' + this.model.get('id') + '/achievements', true);
      }

      
    });

    return AdminConsoleView;
});
Пример #10
0
define(function(require) {

    'use strict';

    var $ = require('libs/jquery'),
        _ = require('libs/underscore'),
        Backbone = require('libs/backbone'),
        dialogTemplate = require('libs/text!./dialog.html'),
        fieldTemplates = {};
        fieldTemplates.checkbox = require('libs/text!./templates/checkbox.html');
        fieldTemplates.select = require('libs/text!./templates/select.html');
        fieldTemplates.textarea = require('libs/text!./templates/textarea.html');
        fieldTemplates.input = require('libs/text!./templates/input.html');



    var DialogView = Backbone.View.extend({
        template: _.template(dialogTemplate),
        events: {
            'click .execute-btn': 'onExecute',
            'click .cancel-btn': 'onCancel',
            'click .close': 'close'
        },
        initialize: function() {
            _.bindAll(this);
            this.actionsDisabled = false;
        },
        show: function() {
            this.setElement(this.template(_.extend({
                executeButtonText: null,
                cancelButtonText: null,
                cssClass: ''
            }, this.options)));

            var body = this.$('.modal-body');
            (this.options.fields || []).forEach(function(field) {
                var template = fieldTemplates[field.type];
                if(!template) {
                    throw new Error('Field type {type} not recognized.'.replace('{type}', field.type));
                }
                var widget = $(_.template(template)(_.extend({description: '', initialValue: ''}, field)));

                body.append(widget);

                if(_.isFunction(field.prePasteHandler) && field.type === 'input') { // TODO: extract this out to widget specific impl.
                    widget.find('input').on('paste', function(e) {
                        var clipboardData = e.originalEvent.clipboardData;
                        if(!clipboardData || !clipboardData.getData) {
                            return;
                        }
                        e.preventDefault();
                        var text = clipboardData.getData('text/plain').replace(/\r?\n|\r/g, ' ');
                        $(e.target).val(field.prePasteHandler(text));
                    });
                }
            });

            if(this.options.text) {
                body.append('<p>' + this.options.text + '</p>');
            }

            this.$el.modal({backdrop: 'static'});
            this.$el.modal('show');
            this.$('textarea, input').first().focus();
        },
        onExecute: function(e) {
            e.preventDefault();
            var view = this,
                formData = {};

            (this.options.fields || []).forEach(function(field) {
                var widget = view.$('[name=' + field.name +']');
                var widget_type = widget.attr('type');
                if (!(widget_type == 'checkbox' || widget_type == 'radio') || widget.is(':checked')) {
                    formData[field.name] = widget.val();
                }
            });

            this.trigger('execute', {
                formData: formData,
                success: function() { view.actionsDisabled = false; view.close(); },
                error: function() { view.actionsDisabled = false; view.close(); },
            });
        },
        onCancel: function() {
            this.trigger('cancel');
            this.close();
        },
        close: function(e) {
            if(e) {
                e.preventDefault();
            }
            if(!this.actionsDisabled) {
                this.$el.modal('hide');
                this.$el.remove();
            }
            this.trigger('close');
        },
        toggleButtons: function(toggle) {
            this.$('.btn, button').toggleClass('disabled', !toggle);
            this.$('textarea').attr('disabled', !toggle);
            this.actionsDisabled = !toggle;
        },
        setContentView: function(view) {
            var body = this.$('.modal-body');
            body.append(view);
        }
    });

    return {
        create: function(config) {
            return new DialogView(config);
        }
    };

});
Пример #11
0
define(function(require) {
    	/**
    	* Renders and manages events associated 
     	* Extends Backbone.View
     	* @exports views/login/LoginView
     	*/
	var jquery 			= require('libs/jquery'),
		underscore 		= require('libs/underscore'),
		Backbone 		= require('libs/backbone'),
		formTpl			= require('text!/templates/login/form.html'),
		
	LoginView = Backbone.View.extend({
		
	    /**
	     * Initializes the view by rendering the login page with a login form.
	     * Binds functions in this view to the model.
	     * Bind event listeners.
	     */	
	    initialize:function () {
	
	    this.render();
	    

	    // Bind listeners on changes in model.
	    this.model.bind('error', this.onModelError, this);
	    
	    /** Defines DOM element event listeners and callbacks. */
	    this.events = {

		    'click #confirm-login-btn': 'login',
		    'keydown input': 'checkForEnterKey',
	        'keydown #username': '******',
	        'keydown #password': '******'
	    	};
	    
	    },

		// The container in the DOM for this view to render into.
		el : $('#login-col'),

		// Called to render the template to this.el
		render : function() {
			var tpl = _.template(formTpl, {});
			$(this.el).html(tpl);
		},

	    // Getters for values from form inputs
		// ----------------------------------------/
	    /**
	     * @return (string) The value input field specified by the given id
	     */
	     getValById: function(id) {
	      return $(this.el).find('#' + id).val();
	     },
	     
	     /**
	      * @return The element with the given class
	      */
	     getElementClass: function(id) {
	       return $(this.el).find('.' + id);
	     },
	    
	     // Events listener callbacks --------------------------------------------------/
		  
	     /**
	      * Set the login data into the model and call the model's save() function.
	      */
	     login: function (e) {
 	    	
	    	 this.model.set({
	    		 username: this.getValById('username'),
	    		 password: this.getValById('password'),
	    		 role: $(this.el).find('input[name="role"]:checked').val()
	         });
	         this.model.save();	        
	     },
	     
	     /**
	      * Set the enter key to click submit.
	      */
	     checkForEnterKey: function(e) {
	    	 
	         var keyCode = (e.keyCode ? e.keyCode : e.which);
	         if (keyCode == '13') {
	        	 e.preventDefault();
	        	 this.login();
	         }
	     },
	     
	     /**
	      * Called when the model this view is observing (an instance of the Login
	      * model) triggers an 'error' event.  The expectation is that the callback
	      * will be returned with an object 'errors' which has for each field in the
	      * model and message indicated whether or not validation failed for that
	      * particular attribute.
	      */
	     onModelError: function(errors) {

	    		 this.addWarning(this.getElementClass('error-message'), errors.message);
	     },
	     
	     
	     // Feedback drawing functions -------------------------------------------------/

	     /**
	      * Remove all feedback from the given element.
	      * @param formGroup The DOM element from which we wish to remove all feedback.
	      */
	     removeFeedback: function(formGroup) {
	    	 $(formGroup)	
	         	.empty();
	     },

	     /**
	      * Displays a warning on the given form element.
	      */
	     addWarning: function(formGroup, message) {
	    	
	    	 // Clear previous messages.
	    	 this.removeFeedback(formGroup);

	    	 $(formGroup)
	         	.text(message);
	     }
	});

	return LoginView;
});
Пример #12
0
define(function(require) {
  /**
   * View responsible for rendering and managing views associated with
   * managing Interests.
   * Extends Backbone.View
   * @exports views/admin/ManageInterestsView
   */
  var jquery                  = require('libs/jquery'),
      underscore              = require('libs/underscore'),
      Backbone                = require('libs/backbone'),
      CategoryList            = require('models/CategoryList'),
      AddInterestView         = require('views/admin/AddInterestView'),
      PreviewInterestView     = require('views/admin/PreviewInterestView'),
      InterestListView        = require('views/admin/InterestListView'),
      ManageCategoriesView    = require('views/admin/ManageCategoriesView'),
      manageInterestsTpl      = require('text!/templates/admin/admin-manage-interests-tpl.html');

  ManageInterestsView = Backbone.View.extend({

    initialize: function() {
      // Get all categories from the server.
      /** All categories available at the server.  Instance of CategoryList.*/
      this.categories = new CategoryList({});
      this.listenTo(this.categories, 'changed', this.onCategoriesChanged); 
      this.categories.fetch();

      // Listen for click of interest in interest list
      this.on('interestClick', this.onInterestClick);
      this.on('newInterest', this.onNewInterest);
      this.on('interestUpdated', this.onInterestUpdate);

    },
    /** The class name of the div DOM element into which the View will render its template. */
    className: 'manage-interests-el',

    /** Define DOM event listeners and callbacks. */
    events: {
      'click #show-add-interest-btn':  'showAddInterest',
      'click #show-manage-categories-btn': 'showManageCategories'
    },

    showAddInterest: function() {
      if (this.addInterestView == undefined) {
        /** Instance of views/admin/AddInterestView. */
        this.addInterestView = 
          new AddInterestView(
            {
              parent: this,
              categories: this.categories
            }
          );
        this.addInterestView.render();
        $('html').append(this.addInterestView.el);
      }
      this.addInterestView.render().show();
    },

    showManageCategories: function() {
      if (this.manageCategoriesView == undefined || null) {
        /** Instance of views/admin/ManageCategoriesView */
        this.manageCategoriesView = 
          new ManageCategoriesView(
            {
              parent: this,
              collection: this.categories,
            }
          );
        $('html').append(this.manageCategoriesView.render().el);
      }
      this.manageCategoriesView.render().show();
    },

    /** Render View template into this.el.  Instanstiates and renders
     * InterestListView, AddInterestView, and PreviewInterestView. */
    render: function() {
      var tpl = _.template(manageInterestsTpl);
      $(this.el).html(tpl);

      // Render subviews.
      if (this.interestListView == undefined) {
        /** Instance of views/admin/InterestListView. */
        this.interestListView = 
          new InterestListView(
             {
              parent: this,
              categories: this.categories
            }
          );
      }
      this.interestListView.render();
      $(this.el).find('.interests-list').append(this.interestListView.el);

      if (this.previewInterestView == undefined) {
        /** Instance of views/admin/PreviewInterestView. */
        this.previewInterestView = 
          new PreviewInterestView(
            {
              parent: this,
              categories: this.categories
            }
          );
      }
      this.previewInterestView.render();
      $(this.el).find('.preview-interest-panel').append(this.previewInterestView.el);
      
      this.delegateEvents();

      return this;

    },
// Event callbacks. -----------------------------------------------------------/

    /**
     * Called by having this.interestListView trigger the 'interest click' event,
     * such that this class can inform other subviews of the event and let them
     * handle the event as appropriate.
     */
    onInterestClick: function(e) {
      this.previewInterestView.changeModel(e.model);
      this.previewInterestView.remove();
      this.previewInterestView.unbind();
      this.previewInterestView.undelegateEvents();
      this.previewInterestView.$el.off();
      this.previewInterestView.render();
      $(this.el).find('.preview-interest-panel').append(this.previewInterestView.el);
     
    },

    /**
     * Callback on trigger of 'newInterest' by subview.  Adds new interest to
     * InterestListView collection.
     */
    onNewInterest: function(e) { 
      this.interestListView.collection.add(e.interest);
    },

    /** Callback on trigger of 'interestUpdated' event by subview.  Re-renders
     * this.interestListView. */
    onInterestUpdate: function(e) {
      this.interestListView.render();
    }

  });
  return ManageInterestsView;
});
Пример #13
0
define(function(require) {
  /**
   * Renders and manages events associated with the achievement edit view
   * view on the achievements management page of the administrative console.
   * Extends Backbone.View
   * @exports views/admin/AchievementEditView
   */
  var jquery              = require('libs/jquery'),
    underscore            = require('libs/underscore'),
    Backbone              = require('libs/backbone'),
    jqueryUi              = require('libs/jquery-ui'),
    Achievement           = require('models/Achievement'),
    PictureUtils          = require('utils/PictureUtils'),
    DeleteAchievementView = require('views/admin/DeleteAchievementModalView'),
    confirmDeleteTpl      = require('text!/templates/admin/achievement-confirm-delete-tpl.html'),
    achievementEditTpl    = require('text!/templates/admin/achievement-edit-tpl.html');


  AchievementEditView = Backbone.View.extend({

    initialize: function() {
      /** Instance of PictureUtils.  Used in rendering of image associated with
       * the achievement this view listens to. */
      this.picUtils = new PictureUtils({
        maxHeight:  80,
        maxWidth:   80
      });

      this.model.on('error', this.onModelError, this);
      this.model.on('updated', this.onModelUpdate, this);

      /** Boolean value.  Changed to true when file associated with this achievement is
       * changed. */
      this.fileChanged = false;

      /** Subivew handling the deletion of an achievement from the set.
       * Instance of DeleteAchievementModalView. */
      this.deleteAchievementView;

    },

    /** Class name of <div> DOM element into which this view will render its
     * template. */
    className: 'achievement-edit-el',

    /** Render view template into this.el */
    render: function() {
      $(this.el).addClass('ui-state-default');
      var tpl = _.template(achievementEditTpl, {achievement: this.model.toJSON()});
      $(this.el).html(tpl);

      this.picUtils.set({
        canvas:   $(this.el).find('#resize-canvas').get(0),
        imgEl:    $(this.el).find('img').get(0)
      });

      // Render deletion modal window
      $('#delete-achievement')

      this.delegateEvents();
      return this;
    },

    /** Define DOM event listeners and callbacks. */
    events: {
      'change #achievement-img':        'onFileSelect',
      'click #save-achievement-btn':    'onAchievementSave',
      'click #delete-achievement-btn':  'onAchievementDelete'
    },

    showSpinner: function() {
      $(this.el).find('.small-spinner').css('opacity', 1);
    },

    hideSpinner: function() {
      $(this.el).find('.small-spinner').css('opacity', 0);
    },

    /**
     * Return JSON object of values of inputs in template.
     * @return {Object} JSON object 
     */
    getFormValues: function() {
      return {
        name:         $(this.el).find('#name').val(),
        description:  $(this.el).find('#description').val(),
        points:       $(this.el).find('#points').val(),
        imgFile:      this.picUtils
                        .dataURItoBlob(
                          $(this.el)
                          .find('#resize-canvas')
                          .get(0)
                          .toDataURL()
                        )
      };
    },

    /** Remove feedback from input elements. */
    removeFeedback: function(formGroup) {
      $(formGroup)
        .removeClass('has-error')
        .removeClass('has-success')
        .find('.feedback').html('');
      $(this.el).find('.glyphicon-ok').css('display', 'none');
    },

    /**
     * Displays a warning in the feedback div of the given form group element.
     * @param {domelement} fromGroup -  The form group corresponding to the
     * input with the error.
     * @param {string} message - The error message to be displayed.
     */
    addWarning: function(formGroup, message) {
      this.removeFeedback(formGroup);
      $(formGroup)
        .addClass('has-error')
        .find('.feedback').html(message);
    },

    /**
     * Callback to trigger of "error" event by the model to which this view 
     * listens.  Renders errors message to appropriate places in form.
     */    
    onModelError: function(err) {
      this.hideSpinner();
      if (err.name != undefined) {
        this.addWarning(
          $(this.el).find('#name').closest('.form-group'),
          err.name
        );
      }

      if (err.description != undefined) {
        this.addWarning(
          $(this.el).find('#description').closest('.form-group'),
          err.description
        );
      }

      if (err.points != undefined) {
        this.addWarning(
          $(this.el).find('#points').closest('.form-group'),
          err.points
        );
      }

      if (err.msg != undefined) {
        this.addWarning(
          $(this.el).find('#msg').closest('.form-group'),
          err.msg
        );
      }
    },

    /**
     * Listens for the selection of a file.  This event handler will be used to
     * render live preview of the achievement image. 
     */
    onFileSelect: function(e) {
      var imgFile = $(this.el).find('#achievement-img')[0].files[0];
      this.fileChanged = true;
      this.picUtils.loadImg(imgFile);
    },

    /**
     * Callback to click of save achievement button.  Sets model attributes 
     * and call model.post() function.
     */
    onAchievementSave: function() {
      var self = this;
      var values = this.getFormValues();

      this.showSpinner();

      // Remove feedback from input elements.
      $(this.el).find('.form-group').each(function(index) {
        self.removeFeedback($(this));
      });

      if (this.model.validate(values)) {
        this.model.set(values);
        this.model.put(this.fileChanged == true ? values.imgFile : null);
      }
    },

    /**
     * Callback to click of delete achievement button.  Displays modal
     * confirmation window. 
     */
    onAchievementDelete: function(e) {
      if (this.deleteAchievementView == undefined) {
        this.deleteAchievementView = new DeleteAchievementView({
          model: this.model
        });
        $('body').append(this.deleteAchievementView.render().el);
      }
      this.deleteAchievementView.show();
    },

    /**
     * Callback to trigger of 'updated' event by model to which this view
     * listenes.
     * Removes spinner, provides visual feedback that update was successful.
     */
    onModelUpdate: function(e) {
      this.hideSpinner();
      $(this.el).find('.glyphicon').css('display', 'block');
    },

  });
  return AchievementEditView;
});
Пример #14
0
define(function(require) {
  /** 
   * View used in pet profile page for displaying the interest list header
   * and implementing functionality regarding to the addition of an interest to
   * a pet's profile.
   * Extends Backbone.View
   * @exports views/pet/AddInterestView
   */
  var jquery            = require('libs/jquery'),
    underscore          = require('libs/underscore'),
    Backbone            = require('libs/backbone'),
    InterestRecord      = require('models/InterestRecord'),
    InterestList        = require('models/InterestList'),
    jQueryUI            = require('libs/jquery-ui'),
    addInterestTpl      = require('text!/templates/pet/interests-header-tpl.html');

  AddInterestView = Backbone.View.extend({

    initialize: function(options) {
      /**
       * Reference to containing parent view -- an instance of PetSocialView.
       */
      this.parent = options.parent;
      /** The model this view listens to -- a new instance of InterestRecord */
      this.model = InterestRecord.findOrCreate({id: -1});

      /** List of all interests currently at server. */
      this.interestsList = new InterestList();

      /** 
       * Array of descriptions of interests at server -- used to aid in 
       * autocompletion.
       */
      this.values = [];

      this.delegateListeners();
      this.delegateEvents();
      this.interestsList.fetch();
    },

    /** 
     * Class name given to <div> element this view will render its template 
     * into.
     */
    className: 'interest-header-el',

    /** 
     * Set instance attributes based on object passed.
     * @param {Object} attributes - JSON objects of instance attributes to be set.
     */
    set: function(attributes) {
      this.pet = attributes.pet;
      this.model.set({pet: attributes.pet});
    },

    /** Render View template into div element. */
    render: function() {
      var tpl = _.template(addInterestTpl);
      var self = this;
      $(this.el).html(tpl);
      if (this.values != null | undefined) {
        $(this.el).find('#add-interest').autocomplete({
          source: self.values
        });       
      }
      this.delegateEvents();
      return this;
    },

    /** Defines event listeners and callbacks. */
    events: {
      'click #add-interest-btn': 'onAddInterest',
      'keyup #add-interest': 'onKeyup'
    },

    /** Bind callbacks for object events that the view listens to. */
    delegateListeners: function() {
      this.listenTo(this.interestsList, 'interestsFetched', this.onInterestsFetched);
      this.listenTo(this.model, 'uploaded', this.onUpload);
    },

    /**
     * Determines if the given string is a description in the interest list,
     * returns the interest object whose description matches the string, 
     * @param {string} str - The string value currently in the input field.
     */
    getInterestFromValue: function(str) {
      var ret = null;
      this.interestsList.models.forEach(function(interest) {
        if (interest.get('description') == str) {
          ret = interest;
        }
      });
      return ret;
    },
// Event callbacks ------------------------------------------------------------/

    /**
     * Callback for keyup event -- determines if 'enter' key was pressed and 
     * fires onAddInterest if this is the case.
     */
    onKeyup: function(e) {
      var keyCode = e.keyCode | e.which;
      if (keyCode == '13') {
        this.onAddInterest();
      }
    },

    /**
     * Callback fired on update of list of interests retrieved from server.
     * Populates this.values array.
     */
    onInterestsFetched: function(e) {
      this.values = [];
      var self = this;
      this.interestsList.models.forEach(function(interest) {
        self.values.push(interest.get('description'));
      });

      $(this.el).find('#add-interest').autocomplete({
        source: self.values
      });
    },

    /**
     * Callback fired on click of add interest button.
     * Calls the associated InterestRecord's post() method to save interest at 
     * server after validation of value in input.
     */
    onAddInterest: function(e) {
      var val = $(this.el).find('#add-interest').val();
      
      // Need to confirm that value in input box is in array of allowed interests.
      var interest = this.getInterestFromValue(val);

      if (interest == null) return;

      this.model.set({interest: interest});
      this.model.post();
    },

    /**
     * Callback fired on trigger of 'uploaded' event by InterestRecord instance
     * this model is listening to.
     */
    onUpload: function(interestRecord) {
      this.parent.trigger('interestRecordUpload', interestRecord);
      this.model = InterestRecord.findOrCreate({id: -1});
      this.model.set({pet: interestRecord.get('pet')});
      this.render();
      this.delegateEvents();
      this.delegateListeners();
    }

    });

  return AddInterestView;

});
Пример #15
0
define(function(require) {
	/**
	 *  Renders and handles events associate with the owner signup view.
	 *  Extends Backbone.View
	 *  @exports views/signup/SignupView
	 */
	var jquery 		= require('libs/jquery'),
		underscore 	= require('libs/underscore'),
		Backbone 	= require('libs/backbone'),
		formTpl		= require('text!/templates/signup/form.html'),
		ServerControll	= require('controllers/ServerController');
	SignupView = Backbone.View.extend({

		// Function called on object instantiation.
		initialize: function() {
			this.render();

      /** The model to which this view listens.  Instance of OwnerSignup. */
      this.model;

      // Bind listeners on changes in model.
      this.model.bind('error', this.onModelError, this);

      /** Define DOM event listeners and callbacks. */
      this.events = {
        'click #confirm-signup-btn': 'confirmSignup',
        'focusout #email':        'emailChanged',
        'focusout #username':     '******',
        'focusout #password':     '******',
        'keyup #password-dupl':   'passwordChanged',
        'keydown input':          'checkForEnterKey',
        'focusin input':          'destroyPopup'
      };

		},

    /** The DOM element into which this view's template will be rendered. */
		el: $('#signup-col'),

    // Called to render the template to this.el
    render: function() {
      var tpl = _.template(formTpl, {});
      $(this.el).html(tpl);
    },
// Getters for values from form inputs ----------------------------------------/
    /**
     * @return (string) The value input field specified by the given iden.
     */
     getValById: function(id) {
      return $(this.el).find('#' + id).val();
     },

    /**
     * @return The element with class from-group which is closest to the element
     * with the given id. 
     */
    getFormGroupById: function(id) {
      return $(this.el).find('#' + id).closest('.form-group');
    },

// Events listener callbacks --------------------------------------------------/
    
    /** Check for input of enter key -- if is enter key, trigger click of 
     * */
    checkForEnterKey: function(e) {
      var keyCode = (e.keyCode ? e.keyCode : e.which);
      if (keyCode == '13') {
        e.preventDefault();
        this.confirmSignup();
      }
    },

    /** 
     * Callback to click of signup confirmation button.  Sets model
     * attributes and calls associated post() function.
     */
    confirmSignup: function(e) {
      this.model.set({
        email: this.getValById('email'),
        username: this.getValById('username'),
        password: this.getValById('password'),
        passwordDupl: this.getValById('password-dupl')
      });
      this.model.save();
    },

    /**
     * Callback to change of email value.  Calls model validation functions
     * to ensure it is an acceptable value.
     */
    emailChanged: function(e) {
      this.removeFeedback(this.getFormGroupById('email'));
      this.model.set({email: this.getValById('email')}, {validate: true});
    },
    /**
     * Callback to change of username value.  Calls model validation functions
     * to ensure it is an acceptable value.
     */
    usernameChanged: function(e) {
      this.removeFeedback(this.getFormGroupById('username'));
      this.model.set({username: this.getValById('username')}, {validate: true});
    },
    /**
     * Callback to change of password value.  Calls model validation functions
     * to ensure it is an acceptable value.
     */
    passwordChanged: function(e) {
      this.removeFeedback(this.getFormGroupById('password'));
      this.removeFeedback(this.getFormGroupById('password-dupl'));
      this.model.set({
        password: this.getValById('password'),
        passwordDupl: this.getValById('password-dupl')
      }, {validate: true});
    },



    /**
     * Called when the model this view is observing (an instance of the Owner
     * model) triggers an 'error' event.  The expectation is that the callback
     * will be returned with an object 'errors' which has for each field in the
     * model and message indicated whether or not validation failed for that
     * particular attribute.
     */
    onModelError: function(errors) {
      if (errors.email != undefined) {
        this.addWarning(this.getFormGroupById('email'), errors.email);
      }

      if (errors.username != undefined) {
        this.addWarning(this.getFormGroupById('username'), errors.username);
      }

      if (errors.password != undefined) {
        this.addWarning(this.getFormGroupById('password'), errors.password);
        this.addWarning(this.getFormGroupById('password-dupl'));
      }

    },
// Feedback drawing functions -------------------------------------------------/

    /**
     * Destroys the popup over the input field which was called as context for this
     * callback function.
     */
    destroyPopover: function(e) {
      $(this).popover('destroy');
    },

    /**
     * Remove all feedback from the given form group element.
     * @param formGroup The DOM element from which we wish to remove all feedback.
     */
    removeFeedback: function(formGroup) {
      $(formGroup)
        .removeClass('has-error')
        .removeClass('has-success');

      $(formGroup).find('span')
        .removeClass('glyphicon-warning-sign')
        .removeClass('text-danger')
        .removeClass('text-success')
        .removeClass('glyphicon-ok')
        .removeClass('glyphicon-repeat')
        .removeClass('spin');
      $(formGroup).find('input').popover('destroy');
    },

    /**
     * Displays a warning on the given form group element and create a popover 
     * with the given message.  No popover create if message == "", null or is 
     * undefined.
     */
    addWarning: function(formGroup, message) {
      // Clear previous messages.
      this.removeFeedback(formGroup);

      $(formGroup)
        .removeClass('has-success')
        .addClass('has-error');

      $(formGroup).find('span')
        .removeClass('glyphicon-ok')
        .addClass('glyphicon-warning-sign').removeClass('text-success')
        .addClass('text-danger');

      // If called with no message defined, we should not create a popover.
      if (message == "" | null | undefined) return;

      // Else, create new popover with message.
      $(formGroup).find('input').popover({
        placement: 'right',
        content: function() {
          // Allows us to redefine popover message content.
          var msg = message;
          return msg;
        }
      });

      $(formGroup).find('input').popover('show');
    }

  });

	return SignupView;
});
Пример #16
0
define(function(require) {
  /**
   * Resonsible for rendering the window which allows the admin to add a new
   * new clinic account and handling all associated functionality.
   * Extends Backbone.View
   * @exports views/admin/AddClinicView
   */
  var jquery                  = require('libs/jquery'),
      underscore              = require('libs/underscore'),
      Backbone                = require('libs/backbone'),
      Clinic                  = require('models/Clinic'),
      addClinicModalTpl       = require('text!/templates/admin/add-clinic-modal-tpl.html');

  AddClinicView = Backbone.View.extend({

    initialize: function(options) {
      /** Reference to parent view.  Instance of ManageClinicsView. */
      this.parent = options.parent;
      /** The model to which this view listens.  Instance of Clinic.*/
      this.model = new Clinic({id: -1});
      this.delegateListeners();
    },

    /** Classname of <div> element to be appended to DOM into which this view
     * will render its template. */
    className: 'add-pet-el',

    /** Render template to this.el */
    render: function() {
      var tpl = _.template(addClinicModalTpl);
      $(this.el).html(tpl);
      this.delegateEvents();
      return this;
    },

    /** Show view modal windowl. */
    show: function() {
      $(this.el).find('.modal').modal('show');
    },
    /** Hide view modal window. */
    hide: function() {
      $(this.el).find('.modal').modal('hide');
    },

    /**
     * Return object containing values of input fields in View's template.
     * @return {Object} A JSON object which as as key values the id's of the
     * input elements in the view template and values equal to the associated
     * input values.
     */
    getValuesFromForm: function() {
      return {
        name:           $(this.el).find('#name').val(),
        email:          $(this.el).find('#email').val(),
        password:       $(this.el).find('#password').val(),
        repassword:     $(this.el).find('#password').val(),
        address:        $(this.el).find('#address').val(),
        postalCode:     $(this.el).find('#postal-code').val(),
        city:           $(this.el).find('#city').val(),
        province:       $(this.el).find('#province').val(),
        phoneNumber:    $(this.el).find('#phone-number').val(),
        contactPerson:  $(this.el).find('#contact-person').val(),
        website:        $(this.el).find('#website').val()
      }
    },
    /** Register model event listeners and callbacks. */
    delegateListeners: function() {
      this.model.on('coordinatesFetched', this.onCoordinatesFetched, this);
      this.model.on('coordinatesError', this.onCoordinatesError, this);
      this.model.on('error', this.onModelError, this);
      this.model.on('uploaded', this.onUpload, this);
    },

    /** Animate spinner in appropriate element in view template. */
    showSpinner: function() {
      $(this.el).find('.coords-spinner').css('opacity', 1);
    },

    /** Hide animation of spinner in view template. */
    hideSpinner: function() {
      $(this.el).find('.coords-spinner').css('opacity', 0);
    },

    /** Defines DOM event callbacks and listeners. */
    events: {
      'click .close': 'hide',
      'focusout #address': 'getCoordinates',
      'focusout #city': 'getCoordinates',
      'click #confirm-add-clinic-btn': 'onAddClinic'
    },

    /**
     * Call model.getCoordinates() function in order to query google 
     * geocoding api to receive latitude and longitude for associated clinic.
     */
    getCoordinates: function() {
      var attrs = this.getValuesFromForm();
      if ((attrs.address == "") || (attrs.city == "")) {
        return null;
      } else {
        this.showSpinner();
        this.model.getCoordinates(attrs.address, attrs.city);
      }
    },

    /**
     * Callback to succesful return of coordinates by google geocode api call.
     * @param {Object} rep - The response returned by the google geocode api
     * call.
     */
    onCoordinatesFetched: function(rep) {
      this.hideSpinner();
      $(this.el).find('.google-feedback')
        .removeClass('text-danger').addClass('text-success')
        .html('Google returned coordinates ' +
        'for the follow address:<br>' + rep.formatted_address);
    },

    /**
     * Callback to unsuccessful return of coordinates by the google geocode
     * api call.
     * @param {Object} err - The error mesage returned by the Google geocode
     * api call.
     */
    onCoordinatesError: function(err) {
      this.hideSpinner();
      $(this.el).find('.google-feedback')
      .removeClass('text-success').addClass('text-danger')
      .html('Google responded with:\n ' +
        err);
    },

    /**
     * Callback to click of confirm-edit-clinic-btn.  Sets model attributes
     * according to form values and calls the associate update function.
     */
    onAddClinic: function() {
      this.showSpinner();
      this.removeFeedback();
      var attrs = this.getValuesFromForm();
      this.model.set(attrs);
      this.model.post();
    },

    /**
     * Callback to trigger of 'uploaded' event by listened to model associated
     * with this view.
     * Triggers 'uploaded' event on parent view and dismisses modal window,
     * resets this clinic's model.
     */
    onUpload: function() {
      this.hideSpinner();
      this.parent.trigger('uploaded', this.model);
      this.model = new Clinic({id: -1});
      this.hide();
    },

    onModelError: function(err) {
      this.hideSpinner();

      if (err.email != undefined) {
        this.addWarning(
          $(this.el).find('#email').closest('.form-group'),
          err.email
        );
      }
      if (err.password != undefined) {
        this.addWarning(
          $(this.el).find('#password').closest('.form-group'),
          err.password
        );
      }

    },

    /** Remove feedback from input elements. */
    removeFeedback: function(formGroup) {
      $(formGroup)
        .removeClass('has-error')
        .removeClass('has-success')
        .find('.feedback').html('');
    },

    /**
     * Displays a warning in the feedback div of the given form group element.
     * @param {domelement} fromGroup -  The form group corresponding to the
     * input with the error.
     * @param {string} message - The error message to be displayed.
     */
    addWarning: function(formGroup, message) {
      this.removeFeedback(formGroup);
      $(formGroup)
        .addClass('has-error')
        .find('.feedback').html(message);
    },
  });

  return AddClinicView;

});
Пример #17
0
import historyCopyDialog from "mvc/history/copy-dialog";
import ERROR_MODAL from "mvc/ui/error-modal";
import baseMVC from "mvc/base-mvc";
import ajaxQueue from "utils/ajax-queue";
import "ui/search-input";

/* global $ */
/* global Galaxy */

var logNamespace = "history";
/* ==============================================================================
TODO:

============================================================================== */
/** @class A container for a history panel that renders controls for that history (delete, copy, etc.) */
var HistoryViewColumn = Backbone.View.extend(baseMVC.LoggableMixin).extend({
    _logNamespace: logNamespace,

    tagName: "div",
    className: "history-column flex-column flex-row-container",
    id: function id() {
        if (!this.model) {
            return "";
        }
        return `history-column-${this.model.get("id")}`;
    },

    // ------------------------------------------------------------------------ set up
    /** set up passed-in panel (if any) and listeners */
    initialize: function initialize(options) {
        options = options || {};
Пример #18
0
define(function(require) {
	
  var jquery              = require('libs/jquery'),
    Backbone              = require('libs/backbone'),
	ownerCreateTpl    	  = require('text!/templates/clinic/owner-create-tpl.html'),
	ownerSuccessTpl    	  = require('text!/templates/clinic/owner-create-success-tpl.html'),
    searchTpl			  = require('text!/templates/clinic/owner-search-tpl.html'),
    profileTpl			  = require('text!/templates/clinic/owner-profile-tpl.html');
  
  
  /**
  * Clinic console view. Used for rendering the clinic console panel along with
  * the create pet owner account modal window.
  * 
  * In addition, this view allows the clinic to search for a specific owner by
  * email or username.
  * 
  * Lastly, the user may edit the clinic's profile from selecting the My Profile
  * button at the top right. The user may also logout from the Logout button
  * at the top right of the page.
  * 
  * Extends Backbone.View
  * @exports views/clinic/ClinicView
  */
  ClinicView = Backbone.View.extend({

	/**
	 * Initializes this view with the clinic's email address and the 
	 * create/search pet owner feature
	 */
    initialize: function() {
    	
    	// Insert the left sidebar template
    	this.render();
    	
	    // Bind listeners on changes in model.
    	this.model.bind('errorNewAccount', this.onCreateModelError, this);
    	this.model.bind('onCreateSuccess', this.onCreateSuccess, this);
    	this.model.bind('onCreateFailure', this.onCreateFailure, this);
	    this.model.bind('error', this.onModelError, this);
	    this.model.bind('onFetched', this.onFetched, this);
	    this.model.bind('onLogout', this.onLogout, this);
        
	    // Event bindings
        this.events = {
        		
    		// Create feature
		    'click #create-owner-btn': 'showCreateOwner',
	        'click #confirm-create-btn': 'createOwner',
	        'focusout #owner-username-new': 'usernameChanged',
	        'focusout #owner-email-new': 'emailChanged',
	        'keydown #create-owner-form input': 'checkForEnterKeyCreate',
	        'focusin #create-owner-form input': 'destroyPopup',
    		
    		// Search feature
  		    'click #owner-search-btn': 'searchOwner',
		    'keydown #owner-email': 'checkForKeyDownSearch',
		    
		    // Logout
	        'click #logout-btn': 'logout',
	        
	        // Edit profile
	        'click #myprofile-btn': 'editProfile',
        };    
        
        // Set the base URL for the clinic
        window.location.base = window.location.pathname;
    },

    
	// The container in the DOM for this view to render into.
	el:	'body',
	
	
	// ===================== Getters for form inputs ===========================/
    /**
     * @return (string) The value input field specified by the given id.
     */
    getValById: function(id) {
    	 return $(this.el).find('#' + id).val();
     },
     
    /**
     * @return The element with class from-group which is closest to the element
     * with the given id. 
     */
    getFormGroupById: function(id) {
    	return $(this.el).find('#' + id).closest('.form-group');
    },
    
	
    // =================== Content rendering functions =========================/
	
	/**
	 *	Render the initial template.
	 */
	render: function() {
		var searchtpl = _.template(searchTpl, {});
		$('#search-sidebar').html(searchtpl);
		var ownercreateTpl = _.template(ownerCreateTpl, {});
  		$(this.el).append(ownercreateTpl);
  			
	},
		
	
	// -------------------------- Create feature -------------------------------/
	/**
	 * Set the enter key to click Create Account.
	 */
    checkForEnterKeyCreate: function(e) {
        var keyCode = (e.keyCode ? e.keyCode : e.which);
        if (keyCode == '13') {
          e.preventDefault();
          this.createOwner();
        }
      },
      
	/**
     * Show the modal window to create a new pet owner account
     */
	showCreateOwner: function() {
    	
		// Reset the modal window then show it in ClinicCreatePetView
		this.removeCreateFeedback($(this.el).find('#owner-email-new').closest('.form-group'));
		this.removeCreateFeedback($(this.el).find('#owner-username-new').closest('.form-group'));
		this.destroyPopover();

    	router.navigate(window.location.base +'/pet', 
    			{trigger: true, replace: true});
    },    
    
    /**
     * Create the new owner account
     */
    createOwner: function() {
        this.model.set({
        	newUsername: this.getValById('owner-username-new'),
        	newEmail: this.getValById('owner-email-new')
        });
        
        // Validate the owner's fields
        this.model.validateNewAccount();
        
        // Validate the pet's fields, if it passes, create the owner
        if (window.router.clinicCreatePetView.addPet()) {
        	this.model.create();
	    }
    },
      
    /**
     * Validate the new username
     */
	usernameChanged: function() {
		this.removeCreateFeedback(this.getFormGroupById('owner-username-new'));
		this.model.set({newUsername: this.getValById('owner-username-new')});
		this.model.validateNewAccount();
	},

    /**
     * Validate the new email
     */
    emailChanged: function() {
        this.removeCreateFeedback(this.getFormGroupById('owner-email-new'));
        this.model.set({newEmail: this.getValById('owner-email-new')});
        this.model.validateNewAccount();
    },
    
    /**
     * Called when the model this view is observing (an instance of the Owner
     * model) triggers an 'error' event.  The expectation is that the callback
     * will be returned with an object 'errors' which has for each field in the
     * model and message indicated whether or not validation failed for that
     * particular attribute.
     */
    onCreateModelError: function(errors) {
        if (errors.username != undefined) {
            this.addCreateWarning(this.getFormGroupById('owner-username-new'), errors.username);
        }
        
        if (errors.email != undefined) {
        	this.addCreateWarning(this.getFormGroupById('owner-email-new'), errors.email);
        }
    },
    
    /**
     * Destroys the popup over the input field which was called as context for this
     * callback function.
     */
    destroyPopover: function() {
    	$(this).popover('destroy');
    },

    /**
     * Remove all feedback from the given form group element.
     * @param formGroup The DOM element from which we wish to remove all feedback.
     */
    removeCreateFeedback: function(formGroup) {
      $(formGroup)
        .removeClass('has-error')
        .removeClass('has-success');

      $(formGroup).find('span')
        .removeClass('glyphicon-warning-sign')
        .removeClass('text-danger')
        .removeClass('text-success')
        .removeClass('glyphicon-ok')
        .removeClass('glyphicon-repeat')
        .removeClass('spin');
      $(formGroup).find('input').popover('destroy');
    },

    /**
     * Displays a warning on the given form group element and create a popover 
     * with the given message.  No popover create if message == "", null or is 
     * undefined.
     */
    addCreateWarning: function(formGroup, message) {
    	
      // Clear previous messages.
      this.removeCreateFeedback(formGroup);
      
      $(formGroup)
        .addClass('has-error');

      $(formGroup).find('span')
        .removeClass('glyphicon-ok')
        .addClass('glyphicon-warning-sign').removeClass('text-success')
        .addClass('text-danger');

      // If called with no message defined, we should not create a popover.
      if (message == "" | null | undefined) return;

      // Else, create new popover with message.
      $(formGroup).find('input').popover({
        placement: 'right',
        content: function() {
        	
          // Allows us to redefine popover message content.
          var msg = message;
          return msg;
        }
      });

      $(formGroup).find('input').popover('show');
    },

    /**
     * 	This function is called after creating a new owner account has been
     * 	successfully completed. It then calls the Pet model to create the new
     * 	pet profile of this owner's pet.
     */
    onCreateSuccess: function(message) {
    	
		// Create pet next
    	window.router.clinicCreatePetView.model.set({ownerId: 
    		this.model.get('newEmail')});
    	
    	window.router.clinicCreatePetView.model.set({owner: 
    		this.model.get('newEmail')});
		window.router.clinicCreatePetView.model.post();
    	
    	// Set the router to the base URL
    	router.navigate(window.location.base, {trigger: false, replace: true});
    	
    	// Insert a success message
    	var ownersuccesstpl = _.template(ownerSuccessTpl, {});
    	$('#owner-profile').html(ownersuccesstpl);
    	$('#create-owner-success').text(message);
		$('#create-owner-window').modal('hide');
    },
    
    /**
     * 	This function is called after creating a new owner account has failed.
     * 	It will display the appropriate error messages.
     */
    onCreateFailure: function(message) {
    	
    	// Insert an error message
    	$('#create-owner-form-errors').empty();
    	$('#create-owner-form-errors').text(message);
    },
     
    
    // -------------------------- Search feature -------------------------------/
	/**
	 * Set the enter key to click search.
	 */
    checkForKeyDownSearch: function(e) {
   	 
        var keyCode = (e.keyCode ? e.keyCode : e.which);
        if (keyCode == '13') {
        	e.preventDefault();
        	this.searchOwner();
        }
    },
    
	/**
     * Search for the specified email with the model's search() function.
     */
    searchOwner: function() {

    	this.model.set({
     		id: this.$('#owner-email').val()
     	});	

     	this.model.fetch();
    },
    
 	/**
     * Called on successfully finding an owner's email.
     */
    onFetched: function() {
    	
        this.removeFeedback();
        this.renderOwner();
    },
    
 	/**
      * Render owner's profile panel once a search is successful.
      */
    renderOwner: function() {
    	
    	// Set the router to the correct URL
    	router.navigate(window.location.base +'/owner/' + this.model.get('id'), 
    			{trigger: false, replace: true});
    	
    	// Insert the owner's profile panel
    	var profiletpl = _.template(profileTpl, {});
    	$('#owner-profile').empty();
    	$('#owner-profile').html(profiletpl);
    	
    	// Insert the owner's username and email into the panel
    	$('#owner-profile-username').text(this.model.get('username'));
    	$('#owner-profile-email').text(this.model.get('email'));

    	// Populate the owner's pet listing and profile appropriately
    	if (this.model.get('pets').length > 0) {
    		
    		// Redirect to the view that will render the pet listing and profile
    		this.redirectPetList();
    	}
    	else {
    		$('#pet-panel').html('&nbsp;&nbsp;This owner has no pets.');
    	}
    },
    
    /**
     *  Redirect to the pet list view.
     */
    redirectPetList: function() {

    	// By default, show the first pet
    	router.navigate(window.location.base +'/owner/' + this.model.get('id') + 
    			'/pet/' + this.model.get('pets').models[0].get('name'), 
    			{trigger: true, replace: true});	
       	
    },
    
      
    /**
     * Called when the model this view is observing (an instance of the Owner
     * model) triggers an 'error' event.  The expectation is that the callback
     * will be returned with an object 'errors' which has the error message.
     */
    onModelError: function(errors) {

		// Clear previous messages.
		this.removeFeedback();
		// Add warning
		this.addWarning(errors.message);
	},
        
    /**
     * Remove all feedback from the given element.
     */
    removeFeedback: function() {
    	$('.error-message').empty();
    },

    /**
     * Displays a warning on the given form element.
     */
    addWarning: function(message) {
    	$('.error-message').text(message);
    },
    
    
    // ------------------------------ Logout -----------------------------------/
	/**
     * Logout from this clinic.
     */
    logout: function() {

     	this.model.logout();
    },
    
 	/**
     * Logout successful, redirect to index page.
     */
    onLogout: function() {
  
     	window.location.replace("/");
    },
    
    
    // --------------------------- Edit Profile --------------------------------/
	/**
     * Edit clinic's profile.
     */
    editProfile: function() {

    	// Route to the editClinicView
    	router.navigate(window.location.base +'/profile', 
    			{trigger: true, replace: true});	
    }
    
    
  });

  return ClinicView;

});
Пример #19
0
define(function(require) {
  /**
   * Renders and manages views associated with the achievement set addition
   * modal window on the manage achievement page of the administrative console.
   * Extends Backbone.View
   * @exports views/admin/AddAchievementView
   */
  var jquery              = require('libs/jquery'),
    underscore            = require('libs/underscore'),
    Backbone              = require('libs/backbone'),
    AchievementSet        = require('models/AchievementSet'),
    SpeciesList           = require('models/SpeciesList'),
    addSetTpl             = require('text!/templates/admin/add-achievement-set-modal-tpl.html');

  AddAchievementSetView = Backbone.View.extend({

    initialize: function(options) {

      /** The model to which this view listens.  Instance of AchievementSet. */
      this.model;

      /** Reference to parent view.  Instance of AchievementSetListView. */
      this.parent = options.parent;

      /** Collection of species which could potentially be eligible the new 
       * achievement set.  Instance of SpeciesList. */
      this.species = new SpeciesList();
      this.species.on('fetched', this.onSpeciesFetch, this);
      this.species.fetch();
      this.resetModel();

      /** Array of species which are available to be declared eligible for the 
       * new achievement.  Equal to this.species remove species selected. */
      this.speciesAvailable;

    },

    /**
     * Called on initialization and after successful upload to make this
     * view listen to a new instance of AchievementSet.
     */
    resetModel: function() {
      var self = this;
      this.model = AchievementSet.findOrCreate({id: -1});
      this.model.on('uploaded', this.onModelUpload, this);
      this.model.on('error', this.onModelError, this);
      this.speciesAvailable = [];
      this.species.models.forEach(function(s) {
        self.speciesAvailable.push(s);
      });
    },

    /** The class name of <div> DOM element into which this view will render
     * its template. */
    className: 'add-achievement-set-window-el',

    /** Render viev temlate into this.el */
    render: function() {
      var tpl = _.template(addSetTpl, {});
      $(this.el).html(tpl);

      // Do not render species list if they have not yet been fetched.
      if (this.species.models.length > 0) {
        this.renderSpecies();
      }

      this.delegateEvents();
      return this;
    },

    /** Populate available list of species ofr this achievement. */
    renderSpecies: function() {
      var self = this;
      var availableSpeciesList = 
        $(this.el).find('#available-species-list');
      var container = document.createDocumentFragment();

      container.appendChild(new Option('', ''));
      this.speciesAvailable.forEach(function(s) {
        var name = s.get('name');
        var id = s.get('id');
        container.appendChild(
          new Option(name, id)
        );
      });

      $(availableSpeciesList).html('');
      $(availableSpeciesList).append(container);
      this.delegateEvents();
    },  

    events: {
      'click #add-new-set-btn':         'onAddSet',
      'click .close':                   'hide',
      'change #available-species-list': 'onAddSpecies',
      'click .remove-species-btn':      'onRemoveSpecies'
    },

    /**
     * Return array of species objects for each species which has been 
     * selected to be elligible to receive the achievement set.
     * @return {Array} Array of species JSON objects.
     */
    getSelectedSpecies: function() {
      var self = this;
      var ret = [];
      var list = 
        $(this.el)
        .find('#selected-species-list')
        .find('.selected-species');

      list.each(function(i, el) {
        var id = $(el).find('input').val();
        ret.push(self.species.getSpeciesById(id).toJSON());
      });

      return ret;
    },

    /**
     * Callback to 'fetched' event triggered by the species collection which
     * this view uses to display which species are eligible for the new 
     * achievement.
     * Initializes 
     *
     */
    onSpeciesFetch: function() {
      var self = this;
      this.speciesAvailable = [];
      this.species.models.forEach(function(s) {
        self.speciesAvailable.push(s);
      });
      this.renderSpecies();
    },

    /**
     * Return JSON object of values of inputs in the template.
     * @return {Object} JSON object
     */
    getFormValues: function() {
      return {
        name:         $(this.el).find('#name').val(),
        description:  $(this.el).find('#description').val(),
        species:      this.getSelectedSpecies()
      };  
    },

    /** Display modal window associated with this view. */
    show: function() {
      $(this.el).find('.modal').modal('show');
    },

    /** Hide modal window associated with this view. */
    hide: function() {
      $(this.el).find('.modal').modal('hide');
      $('body').removeClass('modal-open');
      $('body').find('.modal-backdrop').remove();
    },

    /** Remove feedback from input elements. */
    removeFeedback: function(formGroup) {
      $(formGroup)
        .removeClass('has-error')
        .removeClass('has-success')
        .find('.feedback').html('');
    },

    /**
     * Displays a warning in the feedback div of the given form group element.
     * @param {domelement} fromGroup -  The form group corresponding to the
     * input with the error.
     * @param {string} message - The error message to be displayed.
     */
    addWarning: function(formGroup, message) {
      this.removeFeedback(formGroup);
      $(formGroup)
        .addClass('has-error')
        .find('.feedback').html(message);
    },


    /**
     * Callback to trigger of "error" event by the model to which this view 
     * listens.  Renders errors message to appropriate places in form.
     */
    onModelError: function(err) {
      if (err.name != undefined) {
        this.addWarning(
          $(this.el).find('#name').closest('.form-group'),
          err.name
        );
      }

      if (err.description != undefined) {
        this.addWarning(
          $(this.el).find('#description').closest('.form-group'),
          err.description
        );
      }    
      if (err.msg != undefined) {
        this.addWarning(
          $(this.el).find('#msg').closest('.form-group'),
          err.msg
        );
      }
    },

    /**
     * Callback to 'uploaded' event triggered by the model to which this view
     * listens.  Triggers 'setUploaded' event on parent view, resets the
     * model to which this view listens, then dismisses the modal window
     * associated with this view.
     */
    onModelUpload: function() {
      this.parent.trigger('setUploaded', this.model);
      this.resetModel();
      this.render();
      this.delegateEvents();
      this.hide();
    },

    /**
     * Callback to click of add new achievement set butotn in the add
     * achievement modal windows.  Sets model attributes and calls model.post()
     */
    onAddSet: function(e) {
      var self = this;
      var values = this.getFormValues();

      // Remove feedback from input elements.
      $(this.el).find('.form-group').each(function(index) {
        self.removeFeedback($(this));
      });

      this.model.set(values);
      this.model.post();      
    },

    /** 
     * Callback to change event on species select list.  Adds species to list
     * of species ellgible for this particular achievement.
     */
    onAddSpecies: function(e) {
      var id = e.currentTarget.value;

      // Select blank option.  Do nothing.
      if (id == "") return;

      var species = this.species.getSpeciesById(id);
      var name = species.get('name');
      var speciesElem = 
        $('<div>')
          .addClass('text-info')
          .addClass('selected-species')
          .css('cursor', 'pointer');

      speciesElem.append(
        $('<div>')
          .addClass('pull-right')
          .addClass('text-danger')
          .addClass('remove-species-btn')
          .html('&times;')
      );

      // Append hidden input field such that id it can retrieved for deletion
      // and value acquisition operations.
      speciesElem.append(
        $('<input type="hidden">').val(id)
      );

      speciesElem.append(
        $('<div>')
          .html(name)
      );

      $(this.el).find('#selected-species-list').append(speciesElem);

      // Remove species selected from those available.
      this.speciesAvailable = _.filter(this.speciesAvailable, function(s) {
        return s.get('id') != id;
      });

      this.renderSpecies();
      this.delegateEvents();
      this.getSelectedSpecies();
    },

    onRemoveSpecies: function(e) {
      var selectedSpeciesEl = $(e.currentTarget).closest('.selected-species');
      var id = $(selectedSpeciesEl).find('input').val();

      // Remove element from DOM.
      $(selectedSpeciesEl).remove();

      // Re-add species to species available array.
      var species = this.species.getSpeciesById(id);
      this.speciesAvailable.push(species);
      this.species.sort(this.speciesAvailable);
      this.renderSpecies();
      this.delegateEvents();
    },

  });

  return AddAchievementSetView;

});
Пример #20
0
define(function(require) {
  /**
   * Renders and manages events asociated with the achievement set list displayed
   * on the achievements management page of the administrative console.
   * Extends Backbone.View
   * @exports views/admin/AchievementSetListView
   */
  var jquery                      = require('libs/jquery'),
    underscore                    = require('libs/underscore'),
    Backbone                      = require('libs/backbone'),
    AchievementSetList            = require('models/AchievementSetList'),
    AddAchievementSetView         = require('views/admin/AddAchievementSetView'),
    AchievementSetListElementView = require('views/admin/AchievementSetListElementView'),
    achievementSetListTpl         = require('text!/templates/admin/achievement-set-list-tpl.html');

  AchievementSetListView  = Backbone.View.extend({

    initialize: function(options) {
      var self = this;

      /** Reference to parent view.  Instance of ManageAchievementsView. */
      this.parent = options.parent;

      /** Array of subviews.  Instances of AchievementSetListElemetnView. */
      this.views = [];
      this.initSubviews();

      this.on("setUploaded", this.onSetUpload, this);
      this.on("setUpdated", this.onSetUpdate, this);

    },

    initSubviews: function() {
      var self = this;
      this.views = [];
      this.collection.models.forEach(function(set) {
        var aslev = new AchievementSetListElementView ({
          model: set,
          parent: self
        });
        self.views.push(aslev);
        // Set up views to display by defualt
        aslev.filters = {};
        aslev.filters.descriptionFilter = true;
        aslev.filters.speciesFilter = true;
      });      
    },

    destroySubviews: function() {
      this.views.forEach(function(aselv) {
        aselv.unbind();
        aselv.undelegateEvents();
        aselv.$el.off();
        aselv.remove();
      }); 
    },

    /** Class name of <div> DOM element into which this view will renders its
     * template. */
    className: 'achievement-set-list-el',

    /** Render view template into this.el */
    render: function() {
      var tpl = _.template(achievementSetListTpl, {});
      $(this.el).html(tpl);
      this.renderSubviews();
      this.delegateListeners();
      this.delegateEvents();
      return this;
    },

    /** Render subviews associated with this view and append to appropriate
     * to appropriate place in DOM */
    renderSubviews: function() {
      $(this.el).find('.list-div').html('');
      var container = document.createDocumentFragment();
      this.views.forEach(function(aslev) {
        if (aslev.filters.descriptionFilter == true &&
            aslev.filters.speciesFilter == true) {
          container.appendChild(aslev.render().el);     
        }
      });
      $(this.el).find('.list-div').append(container);
    },

    /** Define DOM event listeners and callbacks. */
    events: {
      'keyup #description-filter': 'filterByDescriptionAndName',
      'keyup #species-filter':     'filterBySpecies',
      'click #add-achievement-set-btn': 'onAddSet',
    },

    /** 
     * Build and cache regexp used in filtering. Cache hash is the regular
     * expression built from the passed pattern.
     * @param {string} pattern - The string from which to build a matching
     * pattern. 
     * @returns {regexp} A regular expression 
     */
    cache: _.memoize(function(pattern) {
        return new RegExp(pattern.split('').reduce(function(a, b) {
          return a+'[^'+b+']*'+b;
        }))
      }),

    /** 
     * Perform test for fuzzy match of str against pattern.
     * @param {string} str - The string to be matched.
     * @param {string} pattern - The pattern against which to match str.
     * @return {boolean} true if str is fuzzy match of pattern, false otherwise.
     */
    match: function(pattern, str) {
      if (pattern == "") return;
      return this.cache(pattern).test(str);
    },

    /** Filter which achievement sets are displayed in the list based on the
     * value in the species search box. */
    filterBySpecies: function(e) {
      var self = this;
      var query = (e != undefined) ?
        e.currentTarget.value.toLowerCase() :
        $(this.el).find('#species-filter').val();


      if (query == "") {
        // If query is the empty string, do not filter by species
        this.views.forEach(function(aslev) {
          aslev.filters.speciesFilter = true;
        }); 
      } else {
        this.views.forEach(function(aslev) {

          // Break list of species into array, separate query at ' 's
          // Try matching every species element against every query element
          var queries = query.split(' ');
          queries = _.filter(queries, function(q) {return q != ""});
          var terms = $(aslev.el).find('.eligible-species-list').html().toLowerCase();
          var toMatch = terms.split(',');
          var querySz = queries.length;

          // Default to false
          var matches = 0;
          aslev.filters.speciesFilter = false;
          toMatch.forEach(function(term) {
            queries.forEach(function(q) {
              if (self.match(q.toLowerCase(), term.toLowerCase())) {
                matches++;
              }
            });
          });
          if (matches >= querySz) aslev.filters.speciesFilter = true;
        });
      }
      this.renderSubviews();
    },

    /** Filter which achievement sets are displayed in the list based on the
     * value in the name/description search box. */
    filterByDescriptionAndName: function(e) {
      var self = this;
      var query = (e != undefined) ?
        e.currentTarget.value.toLowerCase() :
        $(this.el).find('#description-filter').val();

      if (query == "") {
        // If query is the empty string, do not filter by name or description
        this.views.forEach(function(aslev) {
          aslev.filters.descriptionFilter = true;
        });
      } else {
        this.views.forEach(function(aslev) {

          var toMatch = aslev.model.get('description').toLowerCase();

          toMatch += ' ' + aslev.model.get('name').toLowerCase();

          if (self.match(query, toMatch)) {

            aslev.filters.descriptionFilter = true;

          } else {

            aslev.filters.descriptionFilter = false;

          }
        });
      }
      this.renderSubviews();
    },

    delegateListeners: function() {
      this.on('setClick', this.onSetClick, this);
    },

    /**
     * Called when subview triggers 'setCLick' event.
     * Highlights the list element that was click and passes model corresponding
     * to element clicked to parent view. 
     */
    onSetClick: function(e) {
      // Remove clicked attribute from list elements and add clicked class
      // to the event target
      $(this.el).find('.achievement-set-list-element').removeClass('clicked');
      $(e.el).find('.achievement-set-list-element').addClass('clicked');

      // Trigger event on parent view.
      this.parent.trigger('setClick', e);
    },

    /** 
     * Callback to click of Add Achievement Set button.  Displays achievement
     * set addition modal window.
     */
    onAddSet: function() {
      if (this.addAchievementSetView == undefined) {
        this.addAchievementSetView = new AddAchievementSetView({
          parent: this
        });
        $('body').append(this.addAchievementSetView.render().el);
      }
      this.addAchievementSetView.show();
    },
    /** Callback to trigger of "setUploaded" event by AddAchievement view.
     * Adds a new subview to render the new set. */
    onSetUpload: function(e) {
      var self = this;

      if (_.find(this.views, 
          function(v) {return e.get('id') == v.model.get('id')}) == undefined) {
       
        var aslev = new AchievementSetListElementView ({
          model: e,
          parent: self
        });
        self.views.push(aslev);
        // Set up new view to display by defualt
        aslev.filters = {};
        aslev.filters.descriptionFilter = true;
        aslev.filters.speciesFilter = true;

        this.renderSubviews();       
      }

    },

    /** Callback to trigger of "setUpdated" event by parent view.  Re-renders
     * the list element corresponding to the updated achievement set. */
    onSetUpdate: function(e) {
      var self = this;

      this.views.forEach(function(aslev) {
        if (aslev.model.get('id') == e.get('id')) {
          aslev.render();
          aslev.delegateEvents();
        }
      });
    },
  });
    return AchievementSetListView;
});
Пример #21
0
define(function(require) {
  /**
   * View which renders and manages events associated picture carousel on
   * pet profile page.
   * Extends Backbone.View
   * @exports views/pet/CarouselPetView
   */
  var jquery              = require('libs/jquery'),
    underscore            = require('libs/underscore'),
    Backbone              = require('libs/backbone'),
    CarouselPictureView   = require('views/pet/CarouselPictureView')
    carouselTpl           = require('text!/templates/pet/profile-pic-carousel-tpl.html');

  CarouselView = Backbone.View.extend({

    initialize: function(options) {
      /** Reference to parent view.  Instance of PetSocialInfoView. */
      this.parent = options.parent;

      var self = this;

      /** Collection of subviews.  Instances of CarouselPictureView. */
      this.views = [];
      if (this.collection != undefined) {
        this.collection.forEach(function(picture) {
          var cpv = new CarouselPictureView({model: picture, parent: self});
          self.views.push(cpv)
        });
      }

      this.on('zoom', this.onZoom, this);
      this.delegateListeners();
    },

    /** DOM element into which this view will render its template. */
    className: 'carousel-el',

    /** 
     * Render View template into this.el 
     * For each Picture in the collection that this instance of CarouselView
     * listens to, we instantiate an instance of CarouselPictureView and 
     * render it into appropriate <div> in the template.
     */
    render: function() {
      var tpl = _.template(carouselTpl);
      var isActive = 1;
      var self = this;
      $(this.el).html(tpl);

      // Render subviews.
      this.views.forEach(function(cpv) {
        if (isActive == 1 && self.didThis == 0) {
          $(self.el)
            .find('.carousel-inner')
            .append($(cpv.render().el).addClass('active'));
        } else {
          $(self.el)
            .find('.carousel-inner')
            .append(cpv.render().el);
        }
        isActive = 0;

      });

      return this;
    },

    /** 
     * Set instance attributes based on object passed.
     * @param {object} attributes JSON Object with instance attributes to be set.
     */
    set: function(attributes) {
      var self = this;
      this.didThis = 0;
      if (attributes.collection != undefined | null) {
        this.collection = attributes.collection;
        this.views = [];
        if (this.collection != undefined) {
          this.collection.forEach(function(picture) {
            var cpv = new CarouselPictureView({model: picture, parent: self});
            self.views.push(cpv)
          });
        }      
      }
      this.delegateListeners();
    },

    /** Bind callbacks for object events that the view listens to. */
    delegateListeners: function() {
      if (this.collection == undefined | null) return this;
      this.collection.bind('remove', this.onModelDestroyed, this);
      this.collection.bind('add', this.addOne, this);
    },

    /** Defines event listeners and callbacks. */
    events: {
    },

// Event callback functions. --------------------------------------------------/
    /**
     * Called on addition of new Picture to collection.  Renders new picture
     * into carousel.
     * @param {Picture} newPicture - The instance of Picture model which was added
     * to the collection this View listens to.
     */
    addOne: function(newPicture) {
      var self = this;
      if (this.views.length == 0) {
        this.didThis = 1;
        var cpv = new CarouselPictureView({model: newPicture, parent: this});
        this.views.push(cpv);
        $(this.el)
          .find('.carousel-inner')
          .append($(cpv.render().el).addClass('active'));

      } else {

        var result = _.filter(this.views, function(view) {
          return view.model.get('id') == newPicture.get('id');
        });

        if (result.length == 0) {
          // If length == 0, safe to instantiate new view.
          var cpv = new CarouselPictureView({model: newPicture, parent: this});
          this.views.push(cpv);
          $(this.el).find('.carousel-inner').append(cpv.render().el);
        } else {
          // Do not append view to DOM, do not instantiate
        }
      }

      return this;
    },

    /** Callback to trigger of 'zoom' event by subview.  Trigger same event
     * on parent view and pass along same context. */
    onZoom: function(picture) {
      this.parent.trigger('zoom', picture);
    },

    /** Callback to destruction of picture model in collection.  Re-renders the View. */
    onModelDestroyed: function(pic) {
      this.render();
    }
  });

  return CarouselView;

});
Пример #22
0
define(function(require) {
  /**
   * Renders and manages events associated with the accounts management view
   * on the administrative console page.
   * Extends Backbone.View
   * @exports views/admin/ManageCategoriesView
   */
  var jquery              = require('libs/jquery'),
      underscore          = require('libs/underscore'),
      Backbone            = require('libs/backbone'),
      Owner               = require('models/Owner'),
      PetListView         = require('views/admin/PetListView'),
      manageAccountsTpl   = require('text!/templates/admin/manage-accounts-tpl.html');


  ManageAccountsView = Backbone.View.extend({

    initialize: function() {
      this.model = Owner.findOrCreate({id: -1});
      this.petListView = new PetListView();
      this.model.on('fetched', this.onOwnerFetch, this);
      this.model.on('error', this.onOwnerError, this);
    },

    /** Class name of <div> DOM element into which this view will render its
     * template. */
    className: 'manage-accounts-el',

    /** Render view template into this.el */
    render: function() {  
      var tpl = _.template(manageAccountsTpl, {owner: this.model.toJSON()});
      $(this.el).html(tpl);
      this.delegateEvents();
      this.hideSpinner();
      return this;
    },

    /** Render list of pets. */
    renderPetList: function() {
      if (this.petListView == undefined) {
        // this.petListView = new PetListView({});
      }
    },

    /** Defines DOM element listeners and callbacks. */
    events: {
      'keyup #owner-search-input':  'onKeyUp',
      'click #myonoffswitch': 'onActiveToggle'
    },

    /** Animate spinner in appropriate element in view template. */
    showSpinner: function() {
      $(this.el).find('.coords-spinner')
        .css('height', '68px')
        .css('width', '68px')
        .css('opacity', 1);
    },

    /** Hide animation of spinner in view template. */
    hideSpinner: function() {
      $(this.el).find('.coords-spinner')
        .css('opacity', 0)
        .css('height', '0px')
        .css('width', '0px');
    },

// Event callbacks. -----------------------------------------------------------/
    
    /**
     * Callback to toggle of inactive/active switch displayed with other 
     * owner information.
     */
    onActiveToggle: function(e) {
      var lastActiveVal = 
        parseInt($(this.el).find('input:checkbox').val());

      this.model.set({isActive: (lastActiveVal + 1) % 2});
      if (lastActiveVal == 0) {
        $(this.el).find('input:checkbox').val("1");
        this.model.put();
      } else {
        $(this.el).find('input:checkbox').val("0");
        this.model.destroy();
      }
    },

    /**
     * Callback to keyup event in owner search input.
     * If enter key is pressed, initiates search for owner.
     */
    onKeyUp: function(e) {
      var keyCode = e.keyCode || e.which;
      if (keyCode == '13') {
        this.onOwnerSearch();
      }
    },

    /**
     * Callback to click of search for owner button.  Sets 
     * this.owner's id and calls its fetch() method.
     */
    onOwnerSearch: function() {
      var id = $(this.el).find('#owner-search-input').val();
      $(this.el).find('.feedback').html('');
      this.model.set({id: id});

      this.model.fetch();

      this.showSpinner();
    },

    /**
     * Callback to trigger of 'fetched' event by the model
     * to which this view listens.  Updates petlistview
     */
    onOwnerFetch: function() {
      this.hideSpinner();
      this.render();
      this.petListView.changeModel(this.model);
      $(this.el).find('.pet-list-panel').html(this.petListView.render().el);
    },

    /**
     * Callback to trigger of "error" by the model to which this
     * view listens.  Renders error message to template.
     */
    onOwnerError: function(err) {
      this.hideSpinner();
      $(this.el).find('.feedback').html(err.message);
    }

  });
  return ManageAccountsView;
});
Пример #23
0
define(function(require) {
  /**
   * View which renders and manages events associated with the picture management
   * window on the pet profile page.
   * Extends Backbone.View
   * @exports views/pet/ManagePicturesView
   */
  var jquery                  = require('libs/jquery'),
    underscore                = require('libs/underscore'),
    Backbone                  = require('libs/backbone'),
    Pictures                  = require('models/Admin'),
    GridPictureView           = require('views/pet/GridPictureView'),
    UploadPictureModalView    = require('views/pet/UploadPictureModalView'),
    mangagePicturesTpl        = require('text!/templates/pet/manage-pictures-window-tpl.html');

    ManagePicturesView = Backbone.View.extend({

      initialize: function(options) {
        /** Reference to parent view.  Instance of views/pet/PetSocialInfoView. */
        this.parent = options.parent;
        /** Instance of Pet model for which the pictures in this view belong. */
        this.pet = options.pet;
        /** The collection to which this View listens.  Instance of PictureList. */
        this.collection = options.collection;
        this.registerListeners();
      },
      /** 
       * Class name given to <div> element this view will render its template 
       * into.
       */
      className: 'manage-pictures-el',

      /** Render View template into div element. */
      render: function() {
        var tpl = _.template(mangagePicturesTpl);
        var self = this;
        $(this.el).html(tpl);
        this.collection.forEach(function(picture) {
          var gridPicture = new GridPictureView({parent: self, model: picture});
          $(self.el).find('.picture-grid').find('.row').append(gridPicture.render().el);

        });
  
        this.delegateEvents();

        return this;

      },

      /** Show modal window associated with this View. */
      show: function() {
        $(this.el).find('#manage-pictures-window').modal('show');
      },

      /** hide modal window associated with this View. */
      hide: function() {
        $(this.el).find('#manage-pictures-window').modal('hide');
      },
    /** Defines event listeners and callbacks. */
      events: {
        'click #upload-picture-btn':  'showUploadPicture',
        'click img': 'showZoomPicture'
      },

    /** Bind callbacks for object events that the view listens to. */
      registerListeners: function() {
        this.collection.bind('add', this.addOne, this);
        this.on('zoom', this.onZoom, this);
        this.on('modelDestroyed', this.onModelDestroyed, this);
      },

// Event callback functions ---------------------------------------------------/
    /**
     * Called on addition of new Picture to collection.  Renders new picture
     * into carousel.
     * @param {Picture} newPicture - The instance of Picture model which was added
     * to the collection this View listens to.
     */
      addOne: function(newPicture) {
        var gridPicture = new GridPictureView({parent: this, model: newPicture});
        $(this.el)
          .find('.picture-grid')
          .find('.row')
          .append(gridPicture.render().el);
      },
      
      onModelChange: function() {

      },

      /** 
       * Instantiate UploadPictureView and display modal window.
       */
      showUploadPicture: function() {
        if (this.uploadPictureWindow == undefined | null) {
          this.uploadPictureWindow = 
            new UploadPictureModalView(
              {
                pictures: this.collection
              }
            );
          $('html').append(this.uploadPictureWindow.render().el);
          this.uploadPictureWindow.show();
        } else {
          this.uploadPictureWindow.render();
          this.uploadPictureWindow.show();
        }
      },

      /** 
       * Subivew triggered 'zoom' event, pass it up the chain to PetSocialInfoView
       * to handle actually rendering and displaying zoomed picture view.
       */
      onZoom: function(picture) {
        this.parent.trigger('zoom', picture);
      },

      /**
       * A model was deleted.  Remove model from collection, destroy it,
       * and destroy subview.
       */
      onModelDestroyed: function(picture, view) {
        this.collection.remove(picture);
        view.remove();
      }
    });

    return ManagePicturesView;
});
Пример #24
0
define(function(require) {
  /** 
   * View rendering view of picture in picture grid in picture management window
   * on pet profile page.  Also handles associated events.
   * Extends Backbone.View
   * @exports views/pet/GridPictureView
   */
  var jquery              = require('libs/jquery'),
    underscore            = require('libs/underscore'),
    Backbone              = require('libs/backbone'),
    Picture               = require('models/Picture'),
    gridPictureTpl        = require('text!/templates/pet/grid-picture-tpl.html');

  GridPictureView = Backbone.View.extend({

    initialize: function(options) {
      /** Reference to parent view.  Instance of views/pet/ManagePicturesView. */
      this.parent = options.parent;

      /** The model this View listens to.  Instance of Picture. */
      this.model = options.model;
      this.delegateListeners();
    },

    /** Render View template into div element. */
    render: function() {
      $(this.el)
        .addClass('col-xs-4')
        .addClass('padded-top')
        .addClass('picture-col');

      var tpl = _.template(gridPictureTpl, {picture: this.model.toJSON()});
      $(this.el).html(tpl);

      this.delegateEvents();

      return this;
    },

    /** Defines event listeners and callbacks. */
    events: {
      'mouseover':  'onMouseover',
      'mouseleave': 'onMouseleave',
      'click img':  'onImgClick',
      'click .picture-delete': 'onPictureDelete'
    },

    /** Register model event listeners and callbacks. */
    delegateListeners: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.onModelDestroy);
    },

    /**
     * Change the model to which this view listens.
     * @param {Picture} newModel - The new model to which this view is to listen.
     */
    changeModel: function(newModel) {
      /** The model to which this view listens. Instance of Picture. */
      this.model = newModel;
      this.delegateEvents();
      this.delegateListeners();
    },

// Event callback functions. --------------------------------------------------/
    /** Callback to event of 'mouseover' on a picture .  Sets opacity
     * of picture stats to 1. */
    onMouseover: function(e) {
      $(this.el).find('.picture-stats').css('opacity', 1);
      $(this.el).find('.picture-delete').css('opacity', 1);
    },
    /** Callback to event of 'mouseleave' on a picture.  Sets opacity
     * of picture stats to 1. */
    onMouseleave: function(e) {
      $(this.el).find('.picture-stats').css('opacity', 0);
      $(this.el).find('.picture-delete').css('opacity', 0);
    },

    /** Callback to click of image in grid.  Triggers 'zoom' event on parent view. */
    onImgClick: function(e) {
      this.parent.trigger('zoom', this.model);
    },

    /** Callback to click of picture deletion button in grid.  Destroy model*/
    onPictureDelete: function(e) {
      this.model.destroy();
    },

    /** Callback to 'destroy' event triggered by model this View listens to.  
     Gracefully animates this picture away from the grid and triggers 'modelDestroyed' 
     event on parent view.*/
    onModelDestroy: function(model) {
      var self = this;
      $(this.el).css('opacity', 0);
      setInterval(function() {
        self.parent.trigger('modelDestroyed', model, self);
      }, 1000);
    }

  });

  return GridPictureView;

});