//-- copyright // OpenProject Backlogs Plugin // // Copyright (C)2013-2014 the OpenProject Foundation (OPF) // Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda // Copyright (C)2010-2011 friflaj // Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns // Copyright (C)2009-2010 Mark Maglana // Copyright (C)2009 Joe Heck, Nate Lowrie // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License version 3. // // OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. // The copyright follows: // Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj // Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // See doc/COPYRIGHT.rdoc for more details. //++ /*************************************** MODEL Common methods for sprint, work_package, story, task, and impediment ***************************************/ RB.Model = (function ($) { return RB.Object.create({ initialize: function (el) { this.$ = $(el); this.el = el; }, afterCreate: function (data, textStatus, xhr) { // Do nothing. Child objects may optionally override this }, afterSave: function (data, textStatus, xhr) { var isNew, result; isNew = this.isNew(); result = RB.Factory.initialize(RB.Model, data); this.unmarkSaving(); this.refresh(result); if (isNew) { this.$.attr('id', result.$.attr('id')); this.afterCreate(data, textStatus, xhr); } else { this.afterUpdate(data, textStatus, xhr); } }, afterUpdate: function (data, textStatus, xhr) { // Do nothing. Child objects may optionally override this }, beforeSave: function () { // Do nothing. Child objects may or may not override this method }, cancelEdit: function () { this.endEdit(); if (this.isNew()) { this.$.hide('blind'); } }, close: function () { this.$.addClass('closed'); }, copyFromDialog: function () { var editors; if (this.$.find(".editors").length === 0) { editors = $("
").appendTo(this.$); } else { editors = this.$.find(".editors").first(); } editors.html(""); editors.append($("#" + this.getType().toLowerCase() + "_editor").children(".editor")); this.saveEdits(); }, displayEditor: function (editor) { var pos = this.$.offset(), self = this; editor.dialog({ buttons: { OK : function () { self.copyFromDialog(); $(this).dialog("close"); }, Cancel : function () { self.cancelEdit(); $(this).dialog("close"); } }, close: function (e, ui) { if (e.which === 27) { self.cancelEdit(); } }, dialogClass: this.getType().toLowerCase() + '_editor_dialog', modal: true, position: [pos.left - $(document).scrollLeft(), pos.top - $(document).scrollTop()], resizable: false, title: (this.isNew() ? this.newDialogTitle() : this.editDialogTitle()) }); editor.find(".editor").first().focus(); }, edit: function () { var editor = this.getEditor(), self = this, maxTabIndex = 0; $('.stories .editors .editor').each(function (index) { var value; value = parseInt($(this).attr('tabindex'), 10); if (maxTabIndex < value) { maxTabIndex = value; } }); this.$.find('.editable').each(function (index) { var field, fieldType, fieldLabel, fieldName, fieldOrder, input, newInput, typeId, statusId ; field = $(this); fieldId = field.attr('field_id'); fieldName = field.attr('fieldname'); fieldLabel = field.attr('fieldlabel'); fieldOrder = parseInt(field.attr('fieldorder'), 10); fieldType = field.attr('fieldtype') || 'input'; if (!fieldLabel) { fieldLabel = fieldName.replace(/_/ig, " ").replace(/ id$/ig, ""); } if (fieldType === 'select') { // Special handling for status_id => they are dependent of type_id if (fieldName === 'status_id') { typeId = $.trim(self.$.find('.type_id .v').html()); // when creating stories we need to query the select directly if (typeId == '') { typeId = $('#type_id_options').val(); } statusId = $.trim(self.$.find('.status_id .v').html()); input = self.findFactory(typeId, statusId, fieldName); } else if (fieldName === 'type_id'){ input = $('#' + fieldName + '_options').clone(true); // if the type changes the status dropdown has to be modified input.change(function(){ typeId = $(this).val(); statusId = $.trim(self.$.find('.status_id .v').html()); newInput = self.findFactory(typeId, statusId, 'status_id'); newInput = self.prepareInputFromFactory(newInput,fieldId,'status_id',fieldOrder,maxTabIndex); newInput = self.replaceStatusForNewType(input, newInput, $(this).parent().find('.status_id').val(), editor); }); } else { input = $('#' + fieldName + '_options').clone(true); } } else { input = $(document.createElement(fieldType)); } input = self.prepareInputFromFactory(input, fieldId, fieldName, fieldOrder, maxTabIndex); // Copy the value in the field to the input element input.val(fieldType === 'select' ? field.children('.v').first().text() : field.text()); // Add a date picker if field is a date field if (field.hasClass("date")) { input.datepicker({ changeMonth: true, changeYear: true, closeText: 'Close', dateFormat: 'yy-mm-dd', firstDay: 1, showOn: 'button', onClose: function () { $(this).focus(); }, selectOtherMonths: true, showAnim: '', showButtonPanel: true, showOtherMonths: true }); // Remove click-bindings from div - since leaving the edit modus removes the input // and creates a new one // Open the datepicker when you click on the div (before in edit-mode) field.unbind("click"); field.click(function(){input.datepicker("show");}); // So that we won't need a datepicker button to re-show it input.mouseup(function () { $(this).datepicker("show"); }); } // Record in the model's root element which input field had the last focus. We will // use this information inside RB.Model.refresh() to determine where to return the // focus after the element has been refreshed with info from the server. input.focus(function () { self.$.data('focus', $(this).attr('name')); }); input.blur(function () { self.$.data('focus', ''); }); $("