Changeset 3699 for sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/views/budget-tool/main.php
- Timestamp:
- 07/20/2016 04:51:48 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/views/budget-tool/main.php
r3302 r3699 1 <?php 2 $budget = array( 3 array( 'type' => 'meta', 'name' => 'attendees', 'value' => 300 ), 4 array( 'type' => 'meta', 'name' => 'days', 'value' => 2 ), 5 array( 'type' => 'meta', 'name' => 'tracks', 'value' => 4 ), 6 array( 'type' => 'meta', 'name' => 'speakers', 'value' => 25 ), 7 array( 'type' => 'meta', 'name' => 'volunteers', 'value' => 10 ), 8 array( 'type' => 'meta', 'name' => 'currency', 'value' => 'USD' ), 9 array( 'type' => 'meta', 'name' => 'ticket-price', 'value' => 20.00 ), 1 <script> 2 window.wcb = window.wcb || {models:{}, input:[]}; 3 wcb.input = <?php echo json_encode( $budget ); ?>; 4 wcb.urls = <?php echo json_encode( $inspire_urls ); ?>; 5 </script> 10 6 11 array( 'type' => 'income', 'category' => 'other', 'note' => 'Tickets Income', 'amount' => 3500 ), 12 array( 'type' => 'income', 'category' => 'other', 'note' => 'Community Sponsorships', 'amount' => 4300 ), 13 array( 'type' => 'income', 'category' => 'other', 'note' => 'Local Sponsorships', 'amount' => 7000 ), 14 array( 'type' => 'income', 'category' => 'other', 'note' => 'Microsponsors', 'amount' => 500 ), 7 <div class="wrap wcb-budget-tool"> 8 <h2 class="nav-tab-wrapper wp-clearfix"> 9 <a href="#" class="nav-tab nav-tab-active">Preliminary Budget</a> 10 <!--<a href="#" class="nav-tab">Working Budget</a>--> 11 </h2> 15 12 16 array( 'type' => 'expense', 'category' => 'venue', 'note' => 'Venue', 'amount' => 7500 ), 17 array( 'type' => 'expense', 'category' => 'venue', 'note' => 'Wifi Costs', 'amount' => 300, 'link' => 'per-day' ), 18 array( 'type' => 'expense', 'category' => 'other', 'note' => 'Comped Tickets', 'amount' => 300 ), 19 array( 'type' => 'expense', 'category' => 'audio-visual', 'note' => 'Video recording', 'amount' => 500 ), 20 array( 'type' => 'expense', 'category' => 'audio-visual', 'note' => 'Projector rental', 'amount' => 300 ), 21 array( 'type' => 'expense', 'category' => 'audio-visual', 'note' => 'Livestream', 'amount' => 200 ), 22 array( 'type' => 'expense', 'category' => 'signage-badges', 'note' => 'Printing', 'amount' => 800 ), 23 array( 'type' => 'expense', 'category' => 'signage-badges', 'note' => 'Badges', 'amount' => 8.21, 'link' => 'per-attendee' ), 24 array( 'type' => 'expense', 'category' => 'food-beverage', 'note' => 'Snacks', 'amount' => 300 ), 25 array( 'type' => 'expense', 'category' => 'food-beverage', 'note' => 'Lunch', 'amount' => 2350 ), 26 array( 'type' => 'expense', 'category' => 'food-beverage', 'note' => 'Coffee', 'amount' => 500 ), 27 array( 'type' => 'expense', 'category' => 'swag', 'note' => 'T-shirts', 'amount' => 780 ), 28 array( 'type' => 'expense', 'category' => 'speaker-event', 'note' => 'Speakers Dinner', 'amount' => 20, 'link' => 'per-speaker' ), 29 ); 30 ?> 31 <script>var wcb_data = <?php echo json_encode( $budget ); ?>;</script> 13 <p style="max-width: 800px;">Welcome to your WordCamp budget, it's time to crunch some numbers! When you're done with the preliminary budget, hit the "Submit for Approval" button below – a WordCamp deputy will be notified and will review your work. If you're having trouble with these numbers, or if you have any questions, don't hesitate to reach out to your mentor or Central.</p> 32 14 33 <div class="wrap"> 34 <h1>WordCamp Budget</h1> 35 <table id="wcb-budget-container"> 15 <div class="left"> 16 <h2>Event Data</h2> 17 <table class="wcb-budget-container"> 18 <tbody> 19 <tr class="wcb-group-header"> 20 <th style="width: 50%;">Name</th> 21 <th style="width: 50%;">Value</th> 22 </tr> 23 <tr class="wcb-meta-placeholder" style="display: none;"> 24 <td colspan="2"></td> 25 </tr> 26 </tbody> 27 </table> 28 </div> 29 <div class="right"> 30 <h2>Summary</h2> 31 <div class="wcb-summary-placeholder"></div> 32 </div> 33 34 <div class="clear"></div> 35 36 <h2>Expenses</h2> 37 <table class="wcb-budget-container"> 36 38 <tbody> 37 39 <tr class="wcb-group-header"> 38 <th colspan="4">Event Data</th> 39 </tr> 40 <tr class="wcb-meta-placeholder" style="display: none;"> 41 <td colspan="4"></td> 42 </tr> 43 <tr class="wcb-group-header"> 44 <th style="width: 200px;">Category</th> 45 <th>Detail</th> 46 <th style="width: 200px;" class="amount">Amount</th> 47 <th style="width: 100px;"></th> 48 </tr> 49 <tr class="wcb-group-header"> 50 <th colspan="4">Expenses</th> 40 <th style="width: 25%;">Category</th> 41 <th style="width: 25%;">Detail</th> 42 <th style="width: 25%;" class="amount">Amount</th> 43 <th style="width: 25%;"></th> 51 44 </tr> 52 45 <tr class="wcb-expense-placeholder"> 53 46 <td colspan="4">New Expense Item</td> 54 47 </tr> 48 </tbody> 49 </table> 50 51 <h2>Income</h2> 52 <table class="wcb-budget-container"> 53 <tbody> 55 54 <tr class="wcb-group-header"> 56 <th colspan="4">Income</th> 55 <th style="width: 25%;">Category</th> 56 <th style="width: 25%;">Detail</th> 57 <th style="width: 25%;" class="amount">Amount</th> 58 <th style="width: 25%;"></th> 57 59 </tr> 60 58 61 <tr class="wcb-income-placeholder"> 59 62 <td colspan="4">New Income Item</td> … … 62 65 </table> 63 66 64 <p class="submit"> 65 <?php submit_button( 'Save Budget', 'primary', 'submit', false ); ?> 66 <a href="#" class="button">Cancel Changes</a> 67 </p> 67 <form class="wcb-submit-form" action="options.php" method="post"> 68 <?php settings_fields( 'wcb_budget_noop' ); ?> 69 <input type="hidden" name="_wcb_budget_data" value="<?php echo esc_attr( json_encode( $budget ) ); ?>" /> 70 71 <p class="submit"> 72 <?php submit_button( 'Save Draft', 'secondary', 'wcb-budget-save-draft', false ); ?> 73 <a href="<?php echo admin_url( 'admin.php?page=wordcamp-budget' ); ?>" class="button">Cancel Changes</a> 74 <?php submit_button( 'Submit for Approval', 'primary', 'wcb-budget-submit', false ); ?> 75 </p> 76 </form> 68 77 </div> 69 78 70 <style> 71 #wcb-budget-container { 72 width: 100%; 73 table-layout: fixed; 74 white-space:nowrap; 75 text-align: left; 76 border-collapse: collapse; 77 background: white; 78 margin: 12px 0; 79 } 80 81 #wcb-budget-container, 82 #wcb-budget-container td, 83 #wcb-budget-container th { 84 overflow: hidden; 85 text-overflow: ellipsis; 86 border: solid 1px #ccc; 87 height: 30px; 88 line-height: 30px; 89 } 90 91 #wcb-budget-container th { 92 background: #f8f8f8; 93 } 94 95 #wcb-budget-container td, 96 #wcb-budget-container th { 97 vertical-align: top; 98 padding: 0 4px; 99 } 100 101 #wcb-budget-container tr.has-changed td { 102 background: #f7ecdc; 103 } 104 105 #wcb-budget-container tr.is-new td { 106 background: #dcf7e0; 107 } 108 109 #wcb-budget-container .wcb-entry-editor td { 110 background: #d5e7f4; 111 } 112 113 #wcb-budget-container .wcb-entry-editor td.editable { 114 padding: 0; 115 } 116 117 #wcb-budget-container .wcb-entry-editor input, 118 #wcb-budget-container .wcb-entry-editor select { 119 float: left; 120 padding: 0 4px; 121 width: 100%; 122 border: 0; 123 margin: 0; 124 background: transparent; 125 -webkit-appearance: none; 126 -moz-appearance: none; 127 appearance: none; 128 border: none; 129 box-shadow: none; 130 border-radius: 0; 131 height: 30px; 132 line-height: 30px; 133 font-size: inherit; 134 } 135 136 #wcb-budget-container .wcb-entry-editor input:focus { 137 background: #e8f1f7; 138 } 139 140 #wcb-budget-container .dashicons { 141 color: inherit; 142 text-decoration: none; 143 line-height: 30px; 144 color: #aaa; 145 } 146 147 #wcb-budget-container .actions { 148 text-align: right; 149 } 150 151 #wcb-budget-container tr:hover .dashicons { 152 color: #444; 153 } 154 155 #wcb-budget-container .amount { 156 text-align: right; 157 } 158 159 #wcb-budget-container .link-value { 160 display: block; 161 clear: left; 162 color: #aaa; 163 margin-top: -12px; 164 } 165 166 #wcb-budget-container .link-toggle { 167 position: absolute; 168 text-decoration: none; 169 color: #444; 170 } 171 172 #wcb-budget-container .link-toggle .dashicons { 173 font-size: 16px; 174 padding-left: 2px; 175 padding-right: 2px; 176 padding-top: 1px; 177 } 178 179 .wcb-expense-placeholder, 180 .wcb-income-placeholder { 181 color: #aaa; 182 font-style: italic; 183 cursor: pointer; 184 } 185 </style> 186 79 <script type="text/template" id="wcb-tmpl-summary"> 80 <tbody> 81 <tr class="wcb-group-header"> 82 <th style="width: 50%;"></th> 83 <th style="width: 50%;"></th> 84 </tr> 85 <tr> 86 <td>Income</td> 87 <td class="amount">{{data.income.toFixed(2)}}</td> 88 </tr> 89 <tr> 90 <td>Expenses</td> 91 <td class="amount">{{data.expenses.toFixed(2)}}</td> 92 </tr> 93 <tr> 94 <td>Variance</td> 95 <td class="amount <# if (data.variance < 0) { #>wcb-negative<# } #>">{{data.variance.toFixed(2)}}</td> 96 </tr> 97 <tr> 98 <td>Cost Per Person Per Day</td> 99 <td class="amount">{{data.per_person.toFixed(2)}}</td> 100 </tr> 101 <tr> 102 <td></td> 103 <td></td> 104 </tr> 105 <tr> 106 <td></td> 107 <td></td> 108 </tr> 109 <tr> 110 <td></td> 111 <td class="amount"> 112 <# if (data.variance < 0) { #> 113 <a href="#" target="_blank" class="inspire">inspire me</a> 114 <# } #> 115 </td> 116 </tr> 117 </tbody> 118 </script> 187 119 <script type="text/template" id="wcb-tmpl-entry"> 188 <# if (data.type == 'meta' ) { #>189 <td>{{wcb.metaLabels[data.name]}}</td>190 <td>{{data.value}}</td>191 <td></td>192 <td class="actions">193 <a href="#" class="edit"><span class="dashicons dashicons-edit"></span></a>194 </td>195 <# } else { #>196 <td>{{wcb.categories[data.category]}}</td>197 <td>{{data.note}}</td>198 <td class="amount">199 <span>{{data.realAmount.toFixed(2)}}</span>200 <# if (data.link) { #>201 <!--<span class="link-value">{{data.amount.toFixed(2)}} per attendee</span>-->202 <# } #>203 </td>204 <td class="actions">205 <a href="#" class="edit"><span class="dashicons dashicons-edit"></span></a>206 <a href="#" class="delete"><span class="dashicons dashicons-trash"></span></a>207 </td>208 <# } #>209 </script>210 <script type="text/template" id="wcb-tmpl-entry-editor">211 120 <# if (data.type == 'meta' ) { #> 212 121 <td>{{wcb.metaLabels[data.name]}}</td> … … 214 123 <input class="value" type="text" value="{{data.value}}" /> 215 124 </td> 216 <td></td>217 <td class="actions">218 <a href="#" class="save"><span class="dashicons dashicons-yes"></span></a>219 <a href="#" class="cancel"><span class="dashicons dashicons-no-alt"></span></a>220 </td>221 125 <# } else { #> 126 127 <# if (data.type == 'expense') { #> 222 128 <td class="editable"> 223 129 <select class="category"> … … 227 133 </select> 228 134 </td> 135 <# } else { #> 136 <td> 137 Income 138 <input type="hidden" class="category" value="{{data.category}}" /> 139 </td> 140 <# } #> 141 229 142 <td class="editable"> 230 143 <input class="note" type="text" value="{{data.note}}" /> 231 144 </td> 232 145 <td class="editable"> 233 <a href="#" class="link-toggle"><span class="dashicons dashicons-admin-links"></span> {{data.link}}</a> 234 <input class="amount" type="text" value="{{data.amount.toFixed(2)}}" /> 146 <div class="link-toggle"> 147 <select class="link-value"> 148 <option value="" <#if(!data.link){#>selected<#}#>>none</option> 149 <# _.each(wcb.linkData, function(item, k) { #> 150 <option value="{{k}}" <# if (data.link==k) { #>selected<# } #>>{{{item.label}}}</option> 151 <# }); #> 152 </select> 153 <span class="dashicons dashicons-admin-links"></span> 154 </div> 155 <input class="amount" type="text" value="{{data.realAmount.toFixed(2)}}" /> 156 157 <# if (data.link) { #> 158 <div class="link"> 159 <# if (data.linkHasValue) { #> 160 <span>{{data.amount.toFixed(2)}}</span> 161 <# } #> 162 163 {{{data.linkLabel}}} 164 </div> 165 <# } #> 235 166 </td> 236 167 <td class="actions"> 237 <a href="#" class="save"><span class="dashicons dashicons-yes"></span></a> 238 <a href="#" class="cancel"><span class="dashicons dashicons-no-alt"></span></a> 168 <a href="#" class="delete"><span class="dashicons dashicons-trash"></span></a> 239 169 </td> 240 170 <# } #> 241 171 </script> 242 <script type="text/template" id="wcb-tmpl-entry-link">243 <td colspan="2"></td>244 <td class="editable">245 <select class="link-value">246 <option value="" <#if(!data.link){#>selected<#}#>>None</option>247 <option value="per-attendee" <#if(data.link=='per-attendee'){#>selected<#}#>>Per Attendee</option>248 <option value="per-speaker" <#if(data.link=='per-speaker'){#>selected<#}#>>Per Speaker</option>249 <option value="per-day" <#if(data.link=='per-day'){#>selected<#}#>>Per Day</option>250 </select>251 </td>252 <td></td>253 </script>254 255 <script>256 window.wcb = window.wcb || {models:{}};257 258 (function($){259 $(document).on('budget-tool-render.wordcamp-budgets', function() {260 var $container = $('#wcb-budget-container tbody'),261 $income = $container.find('.wcb-income-placeholder'),262 $expense = $container.find('.wcb-expense-placeholder'),263 $meta = $container.find('.wcb-meta-placeholder');264 265 var template_options = {266 evaluate: /<#([\s\S]+?)#>/g,267 interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,268 escape: /\{\{([^\}]+?)\}\}(?!\})/g,269 variable: 'data'270 };271 272 var Category = Backbone.Model.extend({273 defaults: {274 label: 'Category',275 value: 'category'276 }277 });278 279 var Categories = Backbone.Collection.extend({280 model: Category281 });282 283 var Entry = Backbone.Model.extend({284 defaults: {285 type: 'expense',286 category: 'other',287 amount: 0,288 note: '',289 new: false,290 link: null,291 292 // metadata293 name: '',294 value: null295 },296 297 initialize: function() {298 this._realAmount = this.getRealAmount();299 this._attr = _.clone(this.attributes);300 },301 302 getRealAmount: function() {303 if (!this.get('link'))304 return this.get('amount');305 306 if (this.get('link') === 'per-attendee') {307 var attendees = wcb.table.collection.findWhere({type: 'meta', name: 'attendees'}).get('value');308 return this.get('amount') * attendees;309 }310 311 if (this.get('link') === 'per-speaker') {312 var speakers = wcb.table.collection.findWhere({type: 'meta', name: 'speakers'}).get('value');313 return this.get('amount') * speakers;314 }315 316 if (this.get('link') === 'per-day') {317 var days = wcb.table.collection.findWhere({type: 'meta', name: 'days'}).get('value');318 return this.get('amount') * days;319 }320 321 return 0;322 },323 324 hasChanged: function() {325 // console.log(this._attr);326 // console.log(this.attributes);327 // console.log(this._realAmount)328 var changed = _.isEqual(this._attr, this.attributes) && this._realAmount == this.getRealAmount()329 return !changed;330 },331 332 editStart: function() {333 this.trigger('edit-start.wordcamp-budgets');334 }335 });336 337 var EntryView = Backbone.View.extend({338 className: 'wcb-entry',339 tagName: 'tr',340 341 events: {342 'dblclick td': 'editStart',343 'click .edit': 'editStart',344 'click .delete': 'delete',345 },346 347 initialize: function() {348 this.model.bind('change', this.render, this);349 this.model.bind('destroy', this.remove, this);350 this.model.bind('edit-start.wordcamp-budgets', this.editStart, this);351 },352 353 render: function() {354 var data = this.model.toJSON();355 data.realAmount = this.model.getRealAmount();356 357 this.template = _.template($('#wcb-tmpl-entry').html(), null, template_options);358 this.$el.html(this.template(data));359 this.$el.toggleClass('has-changed', this.model.hasChanged() && ! this.model.get('new'));360 this.$el.toggleClass('is-new', this.model.get('new'));361 return this;362 },363 364 editStart: function() {365 if (this.editing)366 return false;367 368 this.editing = true;369 this.editor = new EntryEditorView({model: this.model});370 this.editor.on('edit-save.wordcamp-budgets', this.editSave, this);371 this.editor.on('edit-cancel.wordcamp-budgets', this.editCancel, this);372 373 this.$el.after(this.editor.render().el);374 this.$el.hide();375 return false;376 },377 378 editSave: function() {379 this.clearSelection.apply(this);380 this.model = this.editor.model;381 this.editor.remove();382 this.$el.show();383 this.editing = false;384 },385 386 editCancel: function() {387 this.clearSelection.apply(this);388 this.editor.remove();389 this.$el.show();390 this.editing = false;391 },392 393 clearSelection: function() {394 if (window.getSelection) {395 if (window.getSelection().empty) {396 window.getSelection().empty();397 } else if (window.getSelection().removeAllRanges) {398 window.getSelection().removeAllRanges();399 }400 } else if (document.selection) {401 document.selection.empty();402 }403 },404 405 delete: function() {406 this.model.destroy();407 return false;408 }409 });410 411 var EntryEditorView = Backbone.View.extend({412 className: 'wcb-entry wcb-entry-editor',413 tagName: 'tr',414 415 events: {416 'click .save': 'editSave',417 'click .cancel': 'editCancel',418 'click .link-toggle': 'linkToggle',419 'keyup': 'keyup'420 },421 422 render: function() {423 this.template = _.template($('#wcb-tmpl-entry-editor').html(), null, template_options);424 this.$el.html(this.template(this.model.toJSON()));425 return this;426 },427 428 editSave: function() {429 this.model.set('amount', parseFloat(this.$el.find('.amount').val()));430 this.model.set('note', this.$el.find('.note').val());431 this.model.set('category', this.$el.find('.category').val());432 this.model.set('value', this.$el.find('.value').val() || null);433 434 if (this.linkView)435 this.model.set('link', this.linkView.$el.find('.link-value').val() || null);436 437 this.trigger('edit-save.wordcamp-budgets', this);438 if (this.linkView)439 this.linkView.remove();440 441 return false;442 },443 444 editCancel: function() {445 this.trigger('edit-cancel.wordcamp-budgets', this);446 if (this.linkView)447 this.linkView.remove();448 449 return false;450 },451 452 keyup: function(e) {453 if (e.keyCode == 27) {454 return this.editCancel.apply(this);455 } else if (e.keyCode == 13) {456 return this.editSave.apply(this);457 }458 },459 460 linkToggle: function(e) {461 if (!this.linkView) {462 this.linkView = new EntryLinkView({model: this.model});463 this.$el.after(this.linkView.render().el);464 } else {465 this.linkView.$el.toggle();466 }467 468 return false;469 }470 });471 472 var EntryLinkView = Backbone.View.extend({473 className: 'wcb-entry wcb-entry-editor wcb-entry-link',474 tagName: 'tr',475 476 events: {477 478 },479 480 render: function() {481 this.template = _.template($('#wcb-tmpl-entry-link').html(), null, template_options);482 this.$el.html(this.template(this.model.toJSON()));483 return this;484 }485 })486 487 var Entries = Backbone.Collection.extend({488 model: Entry489 });490 491 var EntriesView = Backbone.View.extend({492 tagName: 'table',493 className: 'wcb-table',494 495 initialize: function() {496 this.collection.bind('add', this.addOne, this);497 this.collection.bind('change reset', this.refresh, this);498 },499 500 refresh: function(model) {501 if (model.get('type') == 'meta') {502 this.render.apply(this);503 }504 505 return this;506 },507 508 addOne: function(item) {509 var view = new EntryView({model: item});510 switch (view.model.get('type')) {511 case 'expense':512 var $c = $expense;513 break;514 case 'income':515 var $c = $income;516 break;517 case 'meta':518 default:519 var $c = $meta;520 }521 522 $c.before(view.render().el);523 },524 525 render: function() {526 $container.find('.wcb-entry').remove();527 this.collection.each(this.addOne, this);528 return this;529 }530 });531 532 wcb.categories = {533 'venue': 'Venue',534 'audio-visual': 'Audio Visual',535 'after-party': 'After Party',536 'camera-shipping': 'Camera Shipping',537 'food-beverage': 'Food & Beverage',538 'office-supplies': 'Office Supplies',539 'signage-badges': 'Signage & Badges',540 'speaker-event': 'Speaker Event',541 'swag': 'Swag',542 'other': 'Other'543 };544 545 wcb.metaLabels = {546 'attendees': 'Attendees',547 'days': 'Days',548 'tracks': 'Tracks',549 'speakers': 'Speakers',550 'volunteers': 'Volunteers',551 'currency': 'Currency',552 'ticket-price': 'Ticket Price'553 };554 555 var table = new EntriesView({collection: new Entries()});556 557 $income.on('click', function() {558 table.collection.add(new wcb.models.Entry({559 type: 'income',560 amount: 0,561 note: 'New Income Item',562 category: 'other',563 new: true564 })).editStart();565 return false;566 });567 568 $expense.on('click', function() {569 table.collection.add(new wcb.models.Entry({570 type: 'expense',571 amount: 0,572 note: 'New Expense Item',573 category: 'other',574 new: true575 })).editStart();576 return false;577 });578 579 wcb.models.Entry = Entry;580 wcb.table = table;581 });582 }(jQuery));583 584 jQuery(document).ready(function(){585 jQuery(document).trigger('budget-tool-render.wordcamp-budgets');586 587 _.each(wcb_data, function(i){588 wcb.table.collection.add(new wcb.models.Entry(i));589 });590 });591 </script>
Note: See TracChangeset
for help on using the changeset viewer.