PageRenderTime 50ms CodeModel.GetById 34ms app.highlight 13ms RepoModel.GetById 0ms app.codeStats 1ms

/city_aware/templates/staff/edit_sponsors.html

https://github.com/hack4reno2011/Rock-Star-Scientists
HTML | 344 lines | 322 code | 22 blank | 0 comment | 0 complexity | f2632fe4463c5e136cbdaa2b60ba5fbd MD5 | raw file
  1{% extends "foundation.html" %}
  2{% load url from future %}
  3{% block headers %}
  4    <style type="text/css">
  5.editHolder {
  6    width:600px;
  7}
  8.label {
  9    width:600px;
 10    clear:both;
 11}
 12.options {
 13    float:right;
 14}
 15.inputBar {
 16    
 17}
 18.labelInput {
 19    width:400px;
 20}
 21#searchResults {
 22    width:300px;
 23}
 24    </style>
 25    <script>
 26var inputMenu = "<div id='barCell'><span class='inputBar'><label>Name:<input id='newName' type='text'></input></label>Venue:<input type='text' id='defaultVenue' placeholder='No default venue selected' readonly=true></input><input id='venuePK' type='hidden'></input><button id='removeVenue'>Remove Venue</button><button id='add'>Add</button></div><div id='searchArea'></span></div>";
 27var sortMenu = "<button id='sortByName'>Sort by Name</button><button id='sortById'>Sort by ID</button>";
 28var noIdItem = '<div class="label"><%- name %><div class="options"><button class="delete">delete</button></div></div>';
 29var wIdItem = '<div class="label"><%- name %>(<%- venue %>)<div class="options"><button class="delete">delete</button></div></div>';
 30var editTemp = '<div class="editHolder"><input class="labelInput" value="<%= name %>"></input><div class="options"><button class="delete">delete</button></div></div>';
 31var viewSearchResult = '<span class="label"><%- name %></span>';
 32var searchMenu = '<label>Find a venue:<input id="searchBox" type="text"></input></label>';
 33
 34var data = []
 35
 36$(function() {
 37
 38    var Item = Backbone.Model.extend({
 39        defaults: {'name': "Unknown"},
 40        urlRoot: '/api/sponsors/',
 41
 42    });
 43
 44    var List = Backbone.Collection.extend({
 45        model: Item,
 46        url: '/api/sponsors/',
 47        parse: function(data) {
 48            return data.objects;
 49        },
 50        comparator: function(item) {
 51            return item.get('id');
 52        }
 53    });
 54    
 55    var Venue = Backbone.Model.extend({
 56        defaults: {'name': "Unknown Venue"},
 57        urlRoot: '/api/venues/',
 58    });
 59
 60    var VenueView = Backbone.View.extend({
 61        tagName: 'li',
 62        events: {
 63            'click span.label': 'selectVenue',
 64        },
 65        initialize: function() {
 66            _.bindAll(this, 'render', 'unrender', 'remove', 'selectVenue');
 67            this.model.bind('change', this.render);
 68            this.model.bind('remove', this.unrender);
 69        },
 70        render: function() {
 71            console.log("render venue");
 72            $(this.el).html(_.template(viewSearchResult, this.model.toJSON()));
 73            return this;
 74        },
 75        unrender: function() {
 76            $(this.el).remove();
 77        },
 78        selectVenue: function() {
 79            console.log("venue selected:", this.model.get('id'));
 80            $('#defaultVenue').val(this.model.get('name'));
 81            $('#venuePK').val(this.model.get('id'));
 82        },
 83    });
 84        
 85
 86    var VenueList = Backbone.Collection.extend({
 87        model: Venue,
 88        url: '/api/venues/',
 89        parse: function(data) {
 90            return data.objects;
 91        },
 92        comparator: function(item) {
 93            return item.get('name');
 94        }
 95    });
 96    
 97    var SearchResults = Backbone.View.extend({
 98        tagName: 'div',
 99        className: 'searchArea',
100        events: {
101        },
102        initialize: function() {
103            _.bindAll(this, 'render', 'renderSearchResults', 'newSearch', 'appendVenue');
104            //TODO fetch results starting with the characters
105            this.collection = new VenueList();
106            this.collection.bind('add', this.appendVenue);
107            this.collection.bind('reset', this.renderSearchResults);
108            this.render();
109            this.newSearch();
110        },
111        render: function() {
112            console.log("rendering search results");
113            console.log(this.el);
114            //$(this.el).append(_.template(searchMenu, {})).append("<ul id='searchResults'></ul>");
115            $('#searchArea').append(_.template(searchMenu, {})).append("<ul id='searchResults'></ul>");
116            $('#searchBox').keyup(this.newSearch);
117        },
118        renderSearchResults: function() {
119            //$('#searchResults', this.el).empty();
120            $('#searchResults').empty();
121            // _.each?
122            for (var i = 0; i < this.collection.models.length; i++) {
123                this.appendVenue(this.collection.models[i]);
124            }
125        },
126        newSearch: function() {
127            //TODO grab the search term from the search
128            //var searchTerm = "Pioneer Center";
129            //TODO strip!
130            var searchTerm = $('#searchBox').val();
131            if (searchTerm) {
132                console.log("searching for:", searchTerm);
133                this.collection.fetch({data: {'name__istartswith': searchTerm}});
134            } else {
135                //empty the list
136                this.collection.reset();
137            }
138        },
139        appendVenue: function(item) {
140            console.log("appending new venue:", item);
141            var venueResult = new VenueView({
142                model: item
143            });
144            //$('#searchResults', this.el).append(venueResult.render().el);
145            $('#searchResults').append(venueResult.render().el);
146        },
147        newItem: function() {
148            var newText = $('input', this.el).val();
149            if (newText) {
150                //TODO not empty?
151                var randItem = new Item({'name': newText});
152                randItem.save({}, {success: buildSuccessReponse(this.collection)});
153                var newText = $('input', this.el).val("");
154            }
155        },
156    });
157    
158    
159
160    var ItemView = Backbone.View.extend({
161        tagName: 'li',
162        className: 'green',
163        events: {
164            'click button.delete': 'remove',
165            'dblclick div.label': "editLabel",
166        },
167        initialize: function() {
168            _.bindAll(this, 'render', 'unrender', 'remove', 'editLabel', 'saveLabel');
169            this.model.bind('change', this.render);
170            this.model.bind('remove', this.unrender);
171        },
172        render: function() {
173            if (this.model.get('venue')) {
174                $(this.el).html(_.template(wIdItem, this.model.toJSON()));
175            } else {
176                $(this.el).html(_.template(noIdItem, this.model.toJSON()));
177            }
178            return this;
179        },
180        editLabel: function() {
181            //change the template to editing mode
182            $(this.el).html(_.template(editTemp, this.model.toJSON()))
183            //TODO should only save on change
184            $('input.labelInput', this.el).focusout(this.saveLabel).change(this.saveLabel).bind("keypress", function(e) {if (e.keyCode == 13) {this.saveLabel};});
185        },
186        saveLabel: function() {
187            //TODO confirm new text, delete if empty
188            var newText = $('input.labelInput', this.el).val();
189            this.model.set({'name': newText});
190            this.model.save();
191            //TODO rerender no matter what happened: avoid duplication with save call
192            $(this.el).html(_.template(noIdItem, this.model.toJSON()));
193        },
194        unrender: function() {
195            $(this.el).remove();
196        },
197        remove: function() {
198            //this.model.destroy();
199            //TODO no need for custom callbacks?
200            console.log("preparing to destroy:", this.model);
201            this.model.destroy({error: function(model, response) {
202                    console.log("DELETE error:", response);
203                },
204                success: function(model, response) {
205                    //apparently, reports success on 301 ?!?!
206                    console.log("DELETE success:", model, response);
207                }
208            });
209        }
210    });
211    
212    //TODO why global?
213    var iList = (new List()).add(data);
214    
215    var AppView = Backbone.View.extend({
216
217        el: $('#tableCell'),
218        events: {
219            'click button#refresh': "refreshList",
220            'click button#add': "newItem",
221            'click button#removeVenue': "removeVenue",
222            'click button#sortByName': "sortByName",
223            'click button#sortById': "sortById",
224        },
225        initialize: function() {
226            _.bindAll(this, 'render', 'addItem', 'appendItem', 'sortByName', 'renderList', 'sortById', 'newItem', 'refreshList', 'removeVenue');
227            this.collection = iList.bind('add', this.appendItem);
228            this.sortOrder = -1;
229            this.render();
230            this.collection = iList.bind('reset', this.renderList);
231            this.collection.fetch(); //fires 'reset'
232            //this.collection.fetch({add: true}); //otherwise list will 'reset'
233            //this.collection.fetch({add: true, data: {offset: 50}}); //otherwise list will 'reset'
234            //this.collection.sort(); //should fire 'reset'
235        },
236        render: function() {
237            $(this.el).append(_.template(inputMenu, {})).append(_.template(sortMenu, {})).append("<ul id='sponsorList'></ul>");
238            //TODO after rendering the search area, start up the search view
239            this.renderList();
240            var venueSearch = new SearchResults();
241        },
242        renderList: function() {
243            $('ul#sponsorList', this.el).empty();
244            // _.each?
245            for (var i = 0; i < this.collection.models.length; i++) {
246                this.appendItem(this.collection.models[i]);
247            }
248        },
249        addItem: function() {
250            this.collection.add(new Item({'name': "new bus stop"}));
251        },
252        appendItem: function(item) {
253            var itemView = new ItemView({
254                model: item
255            });
256            $('ul#sponsorList', this.el).append(itemView.render().el);
257        },
258        sortByName: function() {
259            this.sortOrder = -this.sortOrder;
260            this.collection.comparator = buildNameComparator(this.sortOrder);
261            this.collection.sort();
262        },
263        sortById: function() {
264            this.sortOrder = -this.sortOrder;
265            this.collection.comparator = buildIdComparator(this.sortOrder);
266            this.collection.sort();
267        },
268        newItem: function() {
269            //TODO add optional venue key
270            var newText = $('#newName', this.el).val();
271            var newVenue = $('#venuePK', this.el).val();
272            if (!newVenue) {
273                newVenue = null;
274                
275            } else {
276                //TODO in case of error set null? or reject addition
277                newVenue = parseInt(newVenue, 10);
278            }
279            console.log("preparing to save sponsor:", newText, newVenue);
280            if (newText) {
281                //var newSponsor = new Item({'name': newText, 'venue': {'pk': newVenue}});
282                if (newVenue == null) {
283                    var newSponsor = new Item({'name': newText, 'venue': null});
284                    console.log('saving:', newSponsor);
285                    newSponsor.save({}, {success: buildSuccessReponse(this.collection)});
286                } else {
287                    var newSponsor = new Item({'name': newText, 'venue': "/api/venues/" + newVenue + "/"});
288                    console.log('saving:', newSponsor);
289                    newSponsor.save({}, {success: buildSuccessReponse(this.collection)});
290                }
291                
292                
293                var newText = $('#newName', this.el).val("");
294                this.removeVenue();
295            }
296        },
297        refreshList: function() {
298            this.collection.fetch(); //fires 'reset'
299        },
300        removeVenue: function() {
301            //remove the select default venue from the add sponsor list
302            console.log("removing the default venue");
303            $('#defaultVenue').val("");
304            $('#venuePK').val("");
305        }
306    });
307    
308    function buildIdComparator(sortOrder) {
309        return function(country) {
310            return sortOrder * country.get('id');
311        }
312    }
313    function buildNameComparator(sortOrder) {
314        return function(item) {
315            return _.map(item.get("name").toLowerCase().split(""), function(letter) { 
316                return String.fromCharCode(sortOrder * (letter.charCodeAt(0)));
317            });;
318        }
319    }
320    function buildSuccessReponse(collection) {
321        return function(model, response) {
322            collection.add(model);
323            collection.sort();
324        }
325    }
326    var app = new AppView();
327});
328    </script>
329{% endblock %}
330
331{% block content %}
332<p><a href="{% url 'staff_home' %}">&lt&lt&lt Return to Staff Homepage</a></p>
333<h4>Add a sponsor:</h4>
334<div id="tableCell"></div>
335<div id="overlay" style="display:none">
336    <div id="overlayPrompt">
337        <span id="overlayQuestion"></span>
338        <div id="overlayButtons">
339            <button id="overlayYes" >Yes</button>
340            <button id="overlayNo" >No</button>
341        </div>
342    </div>
343</div>
344{% endblock %}