Installation du nouveau QBE ici
[auf_rh_dae.git] / src / qbe / django_qbe / static / django_qbe / js / qbe.diagram.js
1 qbe.Diagram = {};
2
3 (function($) {
4 $(document).ready(function() {
5 /**
6 * Default options for Diagram and jsPlumb
7 */
8 qbe.Diagram.Defaults = {};
9 qbe.Diagram.Defaults["foreign"] = {
10 label: null,
11 labelStyle: null,
12 paintStyle: {
13 strokeStyle: '#96D25C',
14 lineWidth: 2
15 },
16 backgroundPaintStyle: {
17 lineWidth: 4,
18 strokeStyle: '#70A249'
19 },
20 makeOverlays: function() {
21 return [
22 new jsPlumb.Overlays.PlainArrow({
23 foldback: 0,
24 fillStyle: '#96D25C',
25 strokeStyle: '#70A249',
26 location: 0.99,
27 width: 10,
28 length: 10})
29 ];
30 }
31 };
32 qbe.Diagram.Defaults["many"] = {
33 label: null,
34 labelStyle: {
35 fillStyle: "white",
36 padding: 0.25,
37 font: "12px sans-serif",
38 color: "#C55454",
39 borderStyle: "#C55454",
40 borderWidth: 3
41 },
42 paintStyle: {
43 strokeStyle: '#DB9292',
44 lineWidth: 2
45 },
46 backgroundPaintStyle: {
47 lineWidth: 4,
48 strokeStyle: '#C55454'
49 },
50 makeOverlays: function() {
51 return [
52 new jsPlumb.Overlays.PlainArrow({
53 foldback: 0,
54 fillStyle: '#DB9292',
55 strokeStyle: '#C55454',
56 location: 0.75,
57 width: 10,
58 length: 10}),
59 new jsPlumb.Overlays.PlainArrow({
60 foldback: 0,
61 fillStyle: '#DB9292',
62 strokeStyle: '#C55454',
63 location: 0.25,
64 width: 10,
65 length: 10})
66 ];
67 }
68 }
69
70 jsPlumb.Defaults.DragOptions = {cursor: 'pointer', zIndex: 2000};
71 jsPlumb.Defaults.Container = "qbeDiagramContainer";
72
73 /**
74 * Adds a new model box with its fields
75 */
76 qbe.Diagram.addBox = function (appName, modelName) {
77 var model, root, divBox, divTitle, fieldName, field, divField, divFields, divManies, primaries, countFields, anchorDelete;
78 primaries = [];
79 model = qbe.Models[appName][modelName];
80 root = $("#qbeDiagramContainer");
81 divBox = $("<DIV>");
82 divBox.attr("id", "qbeBox_"+ modelName);
83 divBox.css({
84 "left": (parseInt(Math.random() * 55 + 1) * 10) + "px",
85 "top": (parseInt(Math.random() * 25 + 1) * 10) + "px"
86 });
87 divBox.attr();
88 divBox.addClass("body");
89 divTitle = $("<DIV>");
90 divTitle.addClass("title");
91 qbe.Diagram.setLabel(divTitle, modelName, false);
92 anchorDelete = $("<A>");
93 anchorDelete.html("x");
94 anchorDelete.attr("href", "javascript:void(0);");
95 anchorDelete.addClass("inline-deletelink");
96 anchorDelete.click(function () {
97 $("#qbeModelAnchor_"+ appName +"\\\."+ modelName).click();
98 });
99 divTitle.append(anchorDelete);
100 divFields = $("<DIV>");
101 countFields = 0;
102 for(var key_num in model.fields) {
103 fieldName = model.fields[key_num][0];
104 field = model.fields[key_num][1];
105 divField = $("<DIV>");
106 divField.addClass("field");
107 qbe.Diagram.setLabel(divField, field.label, field.primary);
108 divField.attr("id", "qbeBoxField_"+ appName +"."+ modelName +"."+ fieldName);
109 if (field.type == "ForeignKey") {
110 divField.addClass("foreign");
111 divField.click(qbe.Diagram.addRelated);
112 divBox.prepend(divField);
113 } else if (field.type == "ManyToManyField") {
114 divField.addClass("many");
115 divField.click(qbe.Diagram.addRelated);
116 if (!divManies) {
117 divManies = $("<DIV>");
118 }
119 divManies.append(divField);
120 } else if (field.primary) {
121 divField.addClass("primary");
122 primaries.push(divField);
123 } else {
124 divFields.append(divField);
125 countFields++;
126 }
127 }
128 if (countFields < 5 && countFields > 0) {
129 divFields.addClass("noOverflow");
130 } else if (countFields > 0) {
131 divFields.addClass("fieldsContainer");
132 /*
133 // Uncomment to change the size of the div containing the regular
134 // fields no mouse over/out
135 divFields.mouseover(function() {
136 $(this).removeClass("fieldsContainer");
137 });
138 divFields.mouseout(function() {
139 $(this).addClass("fieldsContainer");
140 });
141 jsPlumb.repaint(["qbeBox_"+ modelName]);
142 */
143 }
144 if (divManies) {
145 divBox.append(divManies);
146 }
147 divBox.append(divFields);
148 for(divField in primaries) {
149 divBox.prepend(primaries[divField]);
150 }
151 divBox.prepend(divTitle);
152 root.append(divBox);
153 divBox.draggable({
154 handle: ".title",
155 grid: [10, 10],
156 stop: function (event, ui) {
157 var $this, position, left, top;
158 $this = $(this);
159 position = $this.position()
160 left = position.left;
161 if (position.left < 0) {
162 left = "0px";
163 }
164 if (position.top < 0) {
165 top = "0px";
166 }
167 $this.animate({left: left, top: top}, "fast", function() {
168 jsPlumb.repaint(["qbeBox_"+ modelName]);
169 });
170 }
171 });
172 };
173
174 /**
175 * Set the label fo the fields getting shorter and adding ellipsis
176 */
177 qbe.Diagram.setLabel = function (div, label, primary) {
178 div.html(label);
179 if (label.length > 18) {
180 if (primary) {
181 div.html(label.substr(0, 18) +"…");
182 } else if (label.length > 21) {
183 div.html(label.substr(0, 21) +"…");
184 }
185 div.attr("title", label);
186 div.attr("alt", label);
187 }
188 };
189
190 /**
191 * Create a relation between a element with id sourceId and targetId
192 * - sourceId.
193 * - sourceFieldName
194 * - targetId.
195 * - targetFieldName
196 * - label.
197 * - labelStyle.
198 * - paintStyle.
199 * - backgroundPaintStyle.
200 * - overlays.
201 */
202 qbe.Diagram.addRelation = function(sourceId, sourceField, targetId, targetField, label, labelStyle, paintStyle, backgroundPaintStyle, overlays) {
203 var mediumHeight;
204 mediumHeight = sourceField.css("height");
205 mediumHeight = parseInt(mediumHeight.substr(0, mediumHeight.length - 2)) / 2;
206 jsPlumb.connect({
207 scope: "qbeBox",
208 label: label,
209 labelStyle: labelStyle,
210 source: sourceId,
211 target: targetId,
212 endpoints: [
213 new jsPlumb.Endpoints.Dot({radius: 0}),
214 new jsPlumb.Endpoints.Dot({radius: 0})
215 ],
216 paintStyle: paintStyle,
217 backgroundPaintStyle: backgroundPaintStyle,
218 overlays: overlays,
219 anchors: [
220 jsPlumb.makeDynamicAnchor([
221 jsPlumb.makeAnchor(1, 0, 1, 0, 0, sourceField.position().top + mediumHeight + 4),
222 jsPlumb.makeAnchor(0, 0, -1, 0, 0, sourceField.position().top + mediumHeight + 4)
223 ]),
224 jsPlumb.makeDynamicAnchor([
225 jsPlumb.makeAnchor(0, 0, -1, 0, 0, targetField.position().top + mediumHeight + 4),
226 jsPlumb.makeAnchor(1, 0, 1, 0, 0, targetField.position().top + mediumHeight + 4)
227 ])
228 ]
229 });
230 qbe.CurrentRelations.push(sourceField.attr("id") +"~"+ targetField.attr("id"));
231 }
232
233 /**
234 * Add related many to many models through clicking in the field name
235 */
236 qbe.Diagram.addRelated = function (obj) {
237 var splits, appName, modelName, fieldName, field, target;
238 splits = this.id.split("qbeBoxField_")[1].split(".");
239 appName = splits[0];
240 modelName = splits[1];
241 fieldName = splits[2];
242 field = qbe.Models[appName][modelName].fields[fieldName];
243 target = field.target;
244 qbe.Core.addModule(target.name, target.model);
245 $("#qbeModelAnchor_"+ target.name +"\\\."+ target.model).click();
246 if (target.through && (!qbe.Models[target.through.name][target.through.model].is_auto)) {
247 qbe.Core.addModule(target.through.name, target.through.model);
248 $("#qbeModelAnchor_"+ target.through.name +"\\\."+ target.through.model).click();
249 }
250 $(".qbeCheckModels").change();
251 };
252
253 /**
254 * Returns a boolean value according to the relation between sourceId
255 * and targetId does exist or not
256 */
257 qbe.Diagram.hasConnection = function (sourceField, targetField) {
258 return (sourceField && targetField
259 && qbe.CurrentRelations.indexOf(sourceField.attr("id") +"~"+ targetField.attr("id")) >= 0);
260 };
261
262 /**
263 * Remove the box and all connections related to it
264 */
265 qbe.Diagram.removeBox = function (appName, modelName) {
266 $("#qbeBox_"+ modelName).remove();
267 };
268
269 /**
270 * Remove all connetions for the box identified by appName and modelName
271 */
272 qbe.Diagram.removeRelations = function (appName, modelName) {
273 var currentRelations, relation, relationsSplits, relationsLength, sourceSplits, sourceId, targetSplits, targetId;
274 currentRelations = [];
275 relationsLength = qbe.CurrentRelations.length;
276 for(var i=0; i<relationsLength; i++) {
277 relation = qbe.CurrentRelations[i];
278 if (relation.indexOf(appName +"."+ modelName) < 0) {
279 currentRelations.push(relation);
280 } else {
281 relationsSplit = relation.split("~");
282 source = relationsSplit[0];
283 sourceSplits = source.split("qbeBoxField_")[1].split(".");
284 sourceId = "qbeBox_"+ sourceSplits[1];
285 target = relationsSplit[1];
286 targetSplits = target.split("qbeBoxField_")[1].split(".");
287 targetId = "qbeBox_"+ targetSplits[1];
288 jsPlumb.detach(sourceId, targetId);
289 }
290 }
291 qbe.CurrentRelations = currentRelations;
292 jsPlumb.clearCache();
293 };
294
295 /**
296 * Save the positions of the all the boxes in a serialized way into a
297 * input type hidden
298 */
299 qbe.Diagram.saveBoxPositions = function () {
300 var positions, left, top, splits, appModel, modelName;
301 positions = [];
302 for(var i=0; i<qbe.CurrentModels.length; i++) {
303 appModel = qbe.CurrentModels[i];
304 splits = appModel.split(".");
305 modelName = splits[1];
306 left = $("#qbeBox_"+ modelName).css("left");
307 top = $("#qbeBox_"+ modelName).css("top");
308 positions.push(appModel +"@"+ left +";"+ top);
309 }
310 $("#id_form_positions").val(positions.join("|"));
311 };
312
313 /**
314 * Repaint the models and relations among them
315 */
316 qbe.Diagram.repaintAll = function () {
317 var appModel, splits;
318 for(var i=0; i<qbe.CurrentModels.length; i++) {
319 appModel = qbe.CurrentModels[i];
320 splits = appModel.split(".");
321 qbe.Diagram.removeRelations(splits[0], splits[1]);
322 }
323 qbe.Core.updateRelations();
324 };
325
326 });
327
328
329 /**
330 * Resize the diagram container height according to the resize event over
331 * the window
332 */
333 $(window).resize(function () {
334 var height;
335 height = $(window).height() - 140;
336 $("#qbeDiagramContainer").height(height);
337 $(".qbeModelList").height(height);
338 });
339
340 /**
341 * Unload jsPlumb
342 */
343 $(window).unload(function () {
344 jsPlumb.unload();
345 });
346
347 })(jQuery.noConflict());