1 /* 2 * Copyright (C) 2008-2009 WaveMaker Software, Inc. 3 * 4 * This file is part of the WaveMaker Client Runtime. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 dojo.provide("wm.base.components.LiveView"); 19 dojo.require("wm.base.Component"); 20 dojo.require('wm.base.lib.data'); 21 22 // View related utitlities 23 wm.getViewField = function(inTypeSchema, inPropName) { 24 if (inTypeSchema) { 25 var propInfo = wm.typeManager.getPropertyInfoFromSchema(inTypeSchema, inPropName); 26 return { 27 caption: wm.capitalize(inPropName.split(".").pop()), 28 sortable: true, 29 dataIndex: inPropName, 30 type: propInfo.type, 31 displayType: wm.getPrimitiveDisplayType(propInfo.type), 32 required: propInfo.required, 33 readonly: dojo.indexOf(propInfo.noChange, "read") >= 0, 34 includeLists: true, 35 includeForms: true 36 }; 37 } 38 } 39 40 wm.getDefaultView = function(inTypeName, inPropertyPath) { 41 inPropertyPath = inPropertyPath || ""; 42 var 43 v = [], tm = wm.typeManager, 44 schema = tm.getTypeSchema(inTypeName), 45 propSchema = inPropertyPath ? tm.getTypeSchema(tm.getPropertyInfoFromSchema(schema, inPropertyPath).type) : schema, 46 fields = wm.typeManager.getSimplePropNames(propSchema); 47 wm.forEach(fields, function(f) { 48 v.push(wm.getViewField(schema, (inPropertyPath ? inPropertyPath + "." : "") + f)); 49 }); 50 return v; 51 } 52 53 /** 54 Component that provides information about live service, datatype, 55 related objects, and field information. 56 @name wm.LiveView 57 @class 58 @extends wm.Component 59 */ 60 dojo.declare("wm.LiveView", wm.Component, { 61 /** @lends wm.LiveView.prototype */ 62 /** Name of the service on which this view operates. */ 63 service: "", 64 /** Fully qualified data type we operate on. */ 65 dataType: "", 66 /** Fields to fetch */ 67 related: [], 68 /** Fields to display */ 69 view: [], 70 constructor: function() { 71 this.related = []; 72 this.view = []; 73 }, 74 init: function() { 75 this.inherited(arguments); 76 this.setDataType(this.dataType); 77 }, 78 loaded: function() { 79 this.inherited(arguments); 80 this.viewChanged(); 81 }, 82 viewChanged: function() { 83 dojo.publish(this.getRuntimeId() + "-viewChanged", [this.getId()]); 84 }, 85 createDefaultView: function() { 86 this.setFields(this.related || [], wm.getDefaultView(this.dataType)); 87 }, 88 setFields: function(inRelated, inView) { 89 this.related = inRelated; 90 this._sortView(inView); 91 this.view = inView; 92 }, 93 getFieldIndex: function(inField) { 94 var di = dojo.isObject(inField) ? inField.dataIndex : inField; 95 for (var i=0, view=this.view, f; f=view[i]; i++) 96 if (f.dataIndex == di) 97 return i; 98 return -1; 99 }, 100 hasField: function(inField) { 101 return (this.getFieldIndex(inField) > -1); 102 }, 103 getRelatedIndex: function(inRelated) { 104 for (var i=0, related=this.related, r; r=related[i]; i++) 105 if (r == inRelated) 106 return i; 107 return -1; 108 }, 109 hasRelated: function(inRelated) { 110 return (this.getRelatedIndex(inRelated) > -1); 111 }, 112 addField: function(inField) { 113 var f = inField && wm.getViewField(wm.typeManager.getTypeSchema(this.dataType), inField); 114 if (f && !this.hasField(f)) { 115 this.view.push(f) 116 this._sortView(this.view); 117 } 118 return f; 119 }, 120 removeField: function(inField) { 121 var i = this.getFieldIndex(inField); 122 if (i > -1) 123 this.view.splice(i, 1); 124 }, 125 addRelated: function(inRelated) { 126 if (inRelated && !this.hasRelated(inRelated)) { 127 this.related.push(inRelated); 128 this.addRelatedDefaultView(inRelated); 129 } 130 }, 131 removeRelated: function(inRelated) { 132 var i = this.getRelatedIndex(inRelated); 133 if (i > -1) 134 this.related.splice(i, 1); 135 }, 136 addRelatedDefaultView: function(inRelated) { 137 var relatedFields = wm.getDefaultView(this.dataType, inRelated); 138 dojo.forEach(relatedFields, function(f) { 139 if (!this.hasField(f)) 140 this.view.push(f); 141 }, this); 142 this._sortView(); 143 }, 144 145 _sortView: function(inView) { 146 if (dojo.isArray(inView)) { 147 var t = this.dataType; 148 // sort view by order or alpha place property chain 149 inView.sort(function(a, b) { 150 // if either has order, compare by order 151 if (wm.isNumber(a.order) || wm.isNumber(b.order)) { 152 return wm.compareNumbers(a.order, b.order); 153 // otherwise compare by "shallowest" or alpha 154 } else { 155 a = a.dataIndex; 156 b = b.dataIndex; 157 var al = a.split(".").length, bl = b.split(".").length; 158 return al == bl ? wm.data.compare(a, b) : wm.compareNumbers(al, bl); 159 } 160 }); 161 } 162 }, 163 _copyView: function(inView) { 164 var view = []; 165 for (var i=0, v; (v=inView[i]); i++) 166 view.push(dojo.mixin({}, v)); 167 return view; 168 }, 169 getViewById: function(inLiveViewId) { 170 if (inLiveViewId instanceof wm.LiveView) 171 return inLiveViewId; 172 else if (inLiveViewId) 173 return this.getRoot().app.getValueById(inLiveViewId); 174 }, 175 copyLiveView: function(inLiveView) { 176 var lv = this.getViewById(inLiveView); 177 if (lv) { 178 this.setService(lv.service); 179 this.setDataType(lv.dataType); 180 var v = this._copyView(lv.view); 181 this.setFields(lv.related, v); 182 } else 183 this.clearView(); 184 }, 185 clearView: function() { 186 this.setService(""); 187 this.setDataType(""); 188 this.setFields([], []); 189 }, 190 setService: function(inService) { 191 this.service = inService; 192 }, 193 //$ Set the dataType for the dataView. This is a type that supports crud operations. 194 setDataType: function(inType) { 195 var t = this.dataType; 196 this.dataType = inType; 197 if (t != this.dataType) 198 this.dataTypeChanged(); 199 if (this._defaultView) 200 this.createDefaultView(); 201 }, 202 dataTypeChanged: function() { 203 // FIXME: we need to do something smart here. changing the datatype should probably zot 204 // the view info and may need to inform things bound to this and/or update. 205 this.related = []; 206 this.view = []; 207 }, 208 hasRelatedProp: function(inRelatedProp) { 209 for (var i=0, related=this.related, r; (r=related[i]); i++) 210 if (r == inRelatedProp) 211 return true; 212 }, 213 getListView: function(inPropPath) { 214 var schema = wm.typeManager.getTypeSchema(this.getSubType(inPropPath)); 215 return dojo.filter(this.getSubView(inPropPath), function(v) { 216 return !wm.typeManager.isPropInList(schema, v.dataIndex); 217 }) 218 }, 219 // get the type of a property path from our dataType 220 getSubType: function(inPropPath) { 221 if (inPropPath) { 222 var schema = wm.typeManager.getTypeSchema(this.dataType); 223 return (schema && (wm.typeManager.getPropertyInfoFromSchema(schema, inPropPath) || 0).type) || this.dataType; 224 } else 225 return this.dataType; 226 }, 227 // get a related list starting at inPropPath 228 getSubRelated: function(inPropPath) { 229 inPropPath = inPropPath ? inPropPath + "." : ""; 230 if (inPropPath) { 231 var list = [], l = inPropPath.length; 232 dojo.forEach(this.related, function(r) { 233 if (r.indexOf(inPropPath) == 0) 234 list.push(r.substring(l)); 235 }); 236 return list; 237 } else 238 return this.related; 239 }, 240 // get a view starting at inPropPath 241 getSubView: function(inPropPath) { 242 inPropPath = inPropPath ? inPropPath + "." : ""; 243 var view = this._copyView(this.view); 244 if (inPropPath) { 245 var list = [], l = inPropPath.length; 246 dojo.forEach(view, function(v) { 247 if (v.dataIndex.indexOf(inPropPath) == 0) { 248 v.dataIndex = v.dataIndex.substring(l); 249 list.push(v); 250 } 251 }); 252 return list; 253 } else 254 return view; 255 } 256 }); 257 258 wm.Object.extendSchema(wm.LiveView, { 259 related: { ignore: 1, writeonly: 1 }, 260 view: { ignore: 1, writeonly: 1 }, 261 service: { ignore: 1, writeonly: 1 }, 262 dataType: {ignore: 1, writeonly: 1} 263 }); 264