/* * Copyright (c) Perforce Software, Inc. 1997-2016 * Licensed Materials - All Rights Reserved. */ function TextField(psheet, parent, name, text) { this.psheet = psheet; this.name = name; this.text = text; this.initText = text; this.labelId = "textfield_"+name; this.rootId = this.labelId+"root"; this.inputId = this.labelId+"input"; this.createTextField(parent); this.changeListeners = new IlvListenerList(); } TextField.regularStyleClass = "textfield"; TextField.highlightedStyleClass = "textfield-highlighted"; TextField.changedStyleClass = "textfield-changed"; TextField.errorStyleClass = "textfield-error"; TextField.prototype.getName = function() { return this.name; }; TextField.prototype.getText = function() { return this.getLabelText(); }; TextField.prototype.createTextField = function (parent) { parentNode = document.getElementById(parent); this.parent = parentNode; parentNode.innerHTML = "<span id='"+this.rootId+"'><span id='"+this.labelId+"' class='"+TextField.regularStyleClass+"'>"+this.text+"</span></span>"; this.label = document.getElementById(this.labelId); this.root = document.getElementById(this.rootId); var textfield = this; this.label.onmouseover = function () { if (textfield) { if (textfield.hasError()) this.className=TextField.errorStyleClass; else if (textfield.hasChanged()) this.className=TextField.changedStyleClass; else this.className=TextField.highlightedStyleClass; } }; this.label.onmouseout = function () { if (textfield) { if (textfield.hasError()) this.className=TextField.errorStyleClass; else if (textfield.hasChanged()) this.className=TextField.changedStyleClass; else this.className=TextField.regularStyleClass; } }; parentNode.onclick = function () { textfield.psheet.setSelected(this); textfield.showInput(); }; }; TextField.prototype.addChangeListener = function(listener) { this.changeListeners.addListener(listener); }; TextField.prototype.removeChangerListener = function(listener) { this.changeListeners.removeListener(listener); }; TextField.prototype.changed = function(oldText, newText) { this.setError(false); this.textChanged = true; this.setLabelText(newText); this.text = newText; this.label.className=TextField.changedStyleClass; this.changeListeners.notify(this, oldText, newText); }; TextField.prototype.revert = function() { this.text = this.initText; this.textError = false; this.setLabelText(this.text); this.textChanged = false; this.label.className=TextField.regularStyleClass; }; TextField.prototype.showInput = function () { this.parentClickSave = this.parent.onclick; this.parent.onclick = null; this.parent.className = PropertySheet.ValueCellEditing; var label = this.label; var root = this.root; var input; var text = this.getLabelText(); input = document.createElement('input'); input.id = this.inputId; input.style.display = "none"; input.type = "text"; input.name = "textbox"; input.value = text; input.autoComplete = "off"; root.appendChild(input); var textfield = this; input.onblur = function() {textfield.onBlur();}; input.onkeypress = function(e) {textfield.onKeyPress(e);}; input.className=TextField.regularStyleClass; label.style.display="none"; input.size = input.value.length == 0 ? 8 : input.value.length; this.oldText = input.value; input.style.display="inline"; input.select(); try { input.focus(); } catch (e) { } }; TextField.prototype.hasChanged = function() { return this.textChanged; }; TextField.prototype.hasError = function() { return this.textError; }; TextField.prototype.setError = function(value) { if (value) { this.textError = true; this.label.className = TextField.errorStyleClass; } else { this.textError = false; this.label.className = TextField.regularStyleClass; } } TextField.prototype.onBlur = function() { var input = document.getElementById(this.inputId); this.hideInput(); var text = input.value; if (this.oldText != text) { this.changed(this.oldText, text); } }; TextField.prototype.setLabelText = function(text) { var label = this.label; if (label) { if(label.innerText) { label.innerText = text; } else { var txt = label.childNodes[0]; if (!txt) { txt = document.createTextNode(text); label.appendChild(txt); } else { txt.data = text; } } } }; TextField.prototype.getLabelText = function() { var label = this.label; if (label) { if (label.innerText) { return label.innerText; } else { var txt = label.childNodes[0]; if (!txt) { return ""; } else { return txt.data; } } } return null; }; TextField.prototype.hideInput = function() { var label = this.label; var input = document.getElementById(this.inputId); var root = this.root; this.parent.className = PropertySheet.ValueCell; if(root.removeChild) root.removeChild(input); else input.style.display="none"; label.style.display="inline"; this.parent.onclick = this.parentClickSave; }; TextField.prototype.onKeyPress = function(e) { var input = document.getElementById(this.inputId); var keyCode; if (e) keyCode = e.keyCode; else keyCode = event.keyCode; if (keyCode==13) { input.onblur(); return false; } else if (keyCode==27) { input.value = this.oldText; return false; } return true; }; function PropertySheet (ref, spanId) { this.ref = ref; this.spanId = spanId; this.tableId = this.spanId + "_table"; this.commitId = this.tableId + "_commit"; this.deletedProperties = []; this.addedProperties = []; } PropertySheet.Table = "psheet"; PropertySheet.TitleCell = "psheet-cell-title"; PropertySheet.NameCell = "psheet-cell"; PropertySheet.ValueCell = "psheet-cell-value"; PropertySheet.CellSelected = "psheet-cell-selected"; PropertySheet.Text = "psheet-text"; PropertySheet.prototype.setAbsoluteId = function (id) { this.absoluteId = id; }; PropertySheet.prototype.setView = function (view) { this.view = view; this.updateSelectionManager(); }; PropertySheet.prototype.getView = function () { return this.view; }; PropertySheet.prototype.setComponent = function (component) { this.component = component; this.updateSelectionManager(); } PropertySheet.prototype.getComponent = function () { return this.component; }; PropertySheet.prototype.updateSelectionManager = function () { if (this.view != null && this.component != null) { if (this.component == "table") { this.setSelectionManager(this.view.getTableView().getSelectionManager()); } else if (this.component == "sheet") { this.setSelectionManager(this.view.getSheetView().getSelectionManager()); } } } PropertySheet.prototype.setSelectionManager = function (selectionManager) { this.selectionManager = selectionManager; var psheet = this; selectionManager.addSelectionChangedListener( function(selection) { psheet.displayPropertySheet(selection); } ); }; PropertySheet.prototype.addProperty = function () { var table = document.getElementById(this.tableId); if (table) { var name = prompt(jviews.messages.demo.ganttFacelet.propertySheet.enterNameOfNewProperty, ""); if (name) { var found = false; var length = this.deletedProperties.length; for(var i=0; i<length && !found; i++) { var prop = this.deletedProperties[i]; if (prop == name) { found = true; } } if (found) { //remove the property from the list this.deletedProperties.splice(i-1, 1); //show the deleted property var selectedNameCell = document.getElementById("name_"+name); var tr = selectedNameCell.parentNode; if (IlvBrowserInfo.instance.ie5up) { tr.style.display = "block"; } else { tr.style.display = "table-row"; } } else { if (this.textfields[name]) { alert(jviews.messages.demo.ganttFacelet.propertySheet.propertyExistsError); return; } this.addedProperties[this.addedProperties.length] = name; var names = []; for(var i in this.textfields){ names[names.length] = this.textfields[i].getName(); } names = names.concat([name]).sort(); var length = names.length; var found = false; for(var i=0; i<length && !found; i++) { if (names[i] == name) { found = true; } } var tr =table.insertRow(i); var td = document.createElement("td"); td.className = PropertySheet.NameCell; td.id= "name_"+name; td.appendChild(document.createTextNode(name)); td.onclick = function () { psheet.setSelected(this); }; tr.appendChild(td); td = document.createElement("td"); td.id = "value_"+name; td.className = PropertySheet.ValueCell; tr.appendChild(td); this.textfields[name] = new TextField(this, td.id, name, ""); var psheet = this; this.textfields[name].addChangeListener(function () {psheet.showCommitButtons();}); this.textfields[name].setError(false); this.textfields[name].textChanged = true; this.showCommitButtons(); } } } }; PropertySheet.prototype.removeProperty = function () { if (this.selectedProperty) { this.deletedProperties[this.deletedProperties.length] = this.selectedProperty; var selectedNameCell = document.getElementById("name_"+this.selectedProperty); var tr = selectedNameCell.parentNode; tr.style.display = "none"; this.showCommitButtons(); } }; PropertySheet.prototype.setSelected = function (cell) { var oldSelectedNameCell = document.getElementById("name_"+this.selectedProperty); if (oldSelectedNameCell) { oldSelectedNameCell.className = PropertySheet.NameCell; } if (cell) { var property = cell.id.substring(cell.id.indexOf("_")+1, cell.id.length); this.selectedProperty = property; if (property) { this.selectedTextField = this.textfields[property]; var selectedNameCell = document.getElementById("name_"+this.selectedProperty); selectedNameCell.className = PropertySheet.CellSelected; } } else { this.selectedProperty = null; this.selectedTextField = null; } }; PropertySheet.prototype.displayPropertySheet = function (selection) { this.selection = selection; this.selectedProperty = null; this.deletedProperties = []; this.addedProperties = []; var p = ""; try { if (selection.length == 1) { var oldId = this.selectionId; this.selectionId = selection[0].getObjectID(); p = "<table border='0' cellspacing='0' cellpadding='0'><tr><td>"; p += "<table class='"+PropertySheet.Table+"' id='"+this.tableId+"'>"; p += "<tr>"; p += "<td colspan='2' class='"+PropertySheet.TitleCell+"'>"; p+="<table width='100%' border='0' cellspacing='0' cellpadding='0'><tr><td class='"+PropertySheet.Text+"' style='font-weight:bold'>"+jviews.messages.demo.ganttFacelet.propertySheet.dataProperties+"</td>"; p += "<td align='right' class='"+PropertySheet.Text+"' id='addProperty' style='cursor:pointer'><span>+</span></td>"; p += "<td align='right' class='"+PropertySheet.Text+"' id='removeProperty' style='cursor:pointer'><span>x</span></td></tr></table></td>"; p += "</tr>"; var names = selection[0].getObjectPropertyNames().sort(); var length = names.length; var type = selection[0].getObjectType(); for(var i=0; i<length; i++){ var name = names[i]; p += "<tr>"; p += "<td class='"+PropertySheet.NameCell+"' id='name_"+name+"'>" + name + "</td>"; p += "<td class='"+PropertySheet.ValueCell+"' id='value_"+name+"'></td>"; p += "</tr>"; } p +="</table>"; p += "</td></tr><tr><td>"; p +="<span id='"+this.commitId+"' style='display:none;'></span>"; p += "</td></tr></table>"; var span = document.getElementById(this.spanId); span.innerHTML = p; var addButton = document.getElementById("addProperty"); var removeButton = document.getElementById("removeProperty"); var psheet = this; addButton.onclick = function() { psheet.addProperty(); }; removeButton.onclick = function () { psheet.removeProperty(); }; //create textfields this.commitButtonsShown = false; var oldtf = this.textfields; this.textfields = []; for(var i=0; i<length; i++){ var name = names[i]; var value = this.format(type, name, selection[0].getObjectProperty(name)); var nameCell = document.getElementById("name_"+name); nameCell.onclick = function () { psheet.setSelected(this); }; var tf = new TextField(this, "value_"+name, name, value); var commit; // previously errored on same object? Let's give a chance to retry // so keep old value if (oldId == this.selectionId && oldtf && oldtf[name] && oldtf[name].hasError()) { tf.changed(value, oldtf[name].text); tf.setError(true); commit = true; } tf.addChangeListener(function () {psheet.showCommitButtons();}); this.textfields[name] = tf; } this.createCommitButtons(); // we have some pending errors let's show commit button if (commit) this.showCommitButtons(); } else { var span = document.getElementById(this.spanId); span.innerHTML = ""; } } catch (e) { alert(jviews.messages.demo.ganttFacelet.propertySheet.errorOccuredDuringRefresh+ e.toString()); } }; PropertySheet.prototype.showCommitButtons = function () { var span = document.getElementById(this.commitId); span.style.display = "block"; var okId = this.tableId + "_ok"; var ok = document.getElementById(okId); ok.focus(); }; PropertySheet.prototype.hideCommitButtons = function () { var span = document.getElementById(this.commitId); span.style.display = "none"; }; PropertySheet.prototype.createCommitButtons = function () { var span = document.getElementById(this.commitId); var okId = this.tableId + "_ok"; var koId = this.tableId + "_ko"; var p = "<input type='button' id='"+okId+"' autocomplete='off' class='psheet-text' value='"+jviews.messages.demo.ganttFacelet.propertySheet.commitBtn+"' />"; p += "<input type='button' id='"+koId+"' autocomplete='off' class='psheet-text' value='"+jviews.messages.demo.ganttFacelet.propertySheet.cancelBtn+"' />"; span.innerHTML = p; var ok = document.getElementById(okId); var psheet = this; ok.onmouseup = function () { psheet.commitChanges(); }; ok.onkeypress = function(e) { var keyCode; if (e) { keyCode = e.keyCode; } else { keyCode = event.keyCode; } if (keyCode==13) { this.onmouseup(); return false; } return true; }; var ko = document.getElementById(koId); ko.onmouseup = function () { psheet.cancelChanges(); }; ko.onkeypress = function(e) { var keyCode; if (e) { keyCode = e.keyCode; } else { keyCode = event.keyCode; } if (keyCode==13) { this.onmouseup(); return false; } return true; }; }; PropertySheet.prototype.cancelChanges = function () { for(var i in this.textfields){ var tf = this.textfields[i]; if (tf.hasChanged()) { tf.revert(); } if (tf.hasError()) { tf.setError(false); } } var length = this.deletedProperties.length; for (var i=0; i<length; i++) { var p = this.deletedProperties[i]; var selectedNameCell = document.getElementById("name_"+p); var tr = selectedNameCell.parentNode; if (IlvBrowserInfo.instance.ie5up) { tr.style.display = "block"; } else { tr.style.display = "table-row"; } } length = this.addedProperties.length; for (i=0; i<length; i++) { p = this.addedProperties[i]; selectedNameCell = document.getElementById("name_"+p); if(selectedNameCell) { tr = selectedNameCell.parentNode; tr.parentNode.removeChild(tr); } } this.addedProperties = []; this.deletedProperties = []; this.hideCommitButtons(); }; PropertySheet.prototype.commitChanges = function () { var nbChanges = 0; var type = this.selection[0].getObjectType(); for(var i in this.textfields){ var tf = this.textfields[i]; if (tf.hasChanged()) { nbChanges++; var value = this.parse(type, tf.getName(), tf.getText()) this.selection[0].setObjectProperty(tf.getName(), value); } } var length = this.deletedProperties.length; for (var i=0; i<length; i++) { var p = this.deletedProperties[i]; this.selection[0].setObjectProperty(p, null); nbChanges++; } if (nbChanges > 0) { this.selectionManager.psheet = this; this.selectionManager.commitSelectionProperties(true, error_handler); } }; function error_handler(errors) { var psheet = this.psheet; // in any case erase flags for (var i in psheet.textfields) { var tf = psheet.textfields[i]; if (tf.hasChanged()) { tf.textChanged = false; // no more change tf.label.className=TextField.regularStyleClass; tf.setError(false); } } // are there any errors? if (errors && errors.length > 0) { // simple case we just got one selected object => one possible error object // look for all failing properties var propertyNames = errors[0].getObjectPropertyNames(); for (var i = 0; i < propertyNames.length; i++) { var tf = psheet.textfields[propertyNames[i]]; tf.textChanged = true; tf.setError(true); // was that a delete property? Let's show it again if (psheet.deletedProperties) { var length = psheet.deletedProperties.length; for (var j = 0; j < length; j++) { var p = psheet.deletedProperties[j]; if (p == propertyNames[i]) { var selectedNameCell = document.getElementById("name_"+p); var tr = selectedNameCell.parentNode; if (IlvBrowserInfo.instance.ie5up) { tr.style.display = "block"; } else { tr.style.display = "table-row"; } psheet.deletedProperties.splice(j, 1); break; } } } } } } /** * Formats a marshalled property value to a representation suitable for display. * This is the inverse operation of <code>format</code>. * The following should hold true: * <ul> * <li><code>value == parse(type, name, format(type, name, value))</code></li> * <li><code>x == format(type, name, parse(type, name, x))</code></li> * </ul> * Note that in some cases, such as with numbers and dates, accuracy is * lost when formatting. * * @param type Type of the object containing the property. * @param name Name of the property. * @param value Value of the property. */ PropertySheet.prototype.format = function(type, name, value) { if (type=="activity" && (name == "endTime" || name == "startTime")) { return this.formatDate(value); } return value; } /** * Parses a display value and returns the corresponding marshalled value. * This is the inverse operation of <code>format</code>. * The following should hold true: * <ul> * <li><code>value == parse(type, name, format(type, name, value))</code></li> * <li><code>x == format(type, name, parse(type, name, x))</code></li> * </ul> * Note that in some cases, such as with numbers and dates, accuracy is * lost when formatting. * * @param type Type of the object. * @param name Name of the property. * @param value Value of the property. */ PropertySheet.prototype.parse = function(type, name, value) { if (type=="activity" && (name == "endTime" || name == "startTime")) { return this.parseDate(value); } return value; } /** * Formats a marshalled representation of a date into a formatted string * suitable for display. * * @param value A <code>string</code> value representing the number of * milliseconds since the Unix epoch. * @return A formatted <code>string</code> representation of the date, or an * empty string when <i>date</i> is <code>null</code>. */ PropertySheet.prototype.formatDate = function(value) { return value == null ? null :value; } /** * Parses an string representation of a date and returns the corresponding * marshalled representation. * * @param value A <code>string</code> value representing a formatted date. * @return A <code>string</code> representing the number of milliseconds since * the Unix epoch or <code>null</code> when <i>value</i> is an empty * string. */ PropertySheet.prototype.parseDate = function(value) { return value == "" ? null :value; }