Installation de la version modifié de QBE dans src/
[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(fieldName in model.fields) {
103 field = model.fields[fieldName];
104 divField = $("<DIV>");
105 divField.addClass("field");
106 qbe.Diagram.setLabel(divField, field.label, field.primary);
107 divField.attr("id", "qbeBoxField_"+ appName +"."+ modelName +"."+ fieldName);
108 if (field.type == "ForeignKey") {
109 divField.addClass("foreign");
110 divField.click(qbe.Diagram.addRelated);
111 divBox.prepend(divField);
112 } else if (field.type == "ManyToManyField") {
113 divField.addClass("many");
114 divField.click(qbe.Diagram.addRelated);
115 if (!divManies) {
116 divManies = $("<DIV>");
117 }
118 divManies.append(divField);
119 } else if (field.primary) {
120 divField.addClass("primary");
121 primaries.push(divField);
122 } else {
123 divFields.append(divField);
124 countFields++;
125 }
126 }
127 if (countFields < 5 && countFields > 0) {
128 divFields.addClass("noOverflow");
129 } else if (countFields > 0) {
130 divFields.addClass("fieldsContainer");
131 /*
132 // Uncomment to change the size of the div containing the regular
133 // fields no mouse over/out
134 divFields.mouseover(function() {
135 $(this).removeClass("fieldsContainer");
136 });
137 divFields.mouseout(function() {
138 $(this).addClass("fieldsContainer");
139 });
140 jsPlumb.repaint(["qbeBox_"+ modelName]);
141 */
142 }
143 if (divManies) {
144 divBox.append(divManies);
145 }
146 divBox.append(divFields);
147 for(divField in primaries) {
148 divBox.prepend(primaries[divField]);
149 }
150 divBox.prepend(divTitle);
151 root.append(divBox);
152 divBox.draggable({
153 handle: ".title",
154 grid: [10, 10],
155 stop: function (event, ui) {
156 var $this, position, left, top;
157 $this = $(this);
158 position = $this.position()
159 left = position.left;
160 if (position.left < 0) {
161 left = "0px";
162 }
163 if (position.top < 0) {
164 top = "0px";
165 }
166 $this.animate({left: left, top: top}, "fast", function() {
167 jsPlumb.repaint(["qbeBox_"+ modelName]);
168 });
169 }
170 });
171 };
172
173 /**
174 * Set the label fo the fields getting shorter and adding ellipsis
175 */
176 qbe.Diagram.setLabel = function (div, label, primary) {
177 div.html(label);
178 if (label.length > 18) {
179 if (primary) {
180 div.html(label.substr(0, 18) +"…");
181 } else if (label.length > 21) {
182 div.html(label.substr(0, 21) +"…");
183 }
184 div.attr("title", label);
185 div.attr("alt", label);
186 }
187 };
188
189 /**
190 * Create a relation between a element with id sourceId and targetId
191 * - sourceId.
192 * - sourceFieldName
193 * - targetId.
194 * - targetFieldName
195 * - label.
196 * - labelStyle.
197 * - paintStyle.
198 * - backgroundPaintStyle.
199 * - overlays.
200 */
201 qbe.Diagram.addRelation = function(sourceId, sourceField, targetId, targetField, label, labelStyle, paintStyle, backgroundPaintStyle, overlays) {
202 var mediumHeight;
203 mediumHeight = sourceField.css("height");
204 mediumHeight = parseInt(mediumHeight.substr(0, mediumHeight.length - 2)) / 2;
205 jsPlumb.connect({
206 scope: "qbeBox",
207 label: label,
208 labelStyle: labelStyle,
209 source: sourceId,
210 target: targetId,
211 endpoints: [
212 new jsPlumb.Endpoints.Dot({radius: 0}),
213 new jsPlumb.Endpoints.Dot({radius: 0})
214 ],
215 paintStyle: paintStyle,
216 backgroundPaintStyle: backgroundPaintStyle,
217 overlays: overlays,
218 anchors: [
219 jsPlumb.makeDynamicAnchor([
220 jsPlumb.makeAnchor(1, 0, 1, 0, 0, sourceField.position().top + mediumHeight + 4),
221 jsPlumb.makeAnchor(0, 0, -1, 0, 0, sourceField.position().top + mediumHeight + 4)
222 ]),
223 jsPlumb.makeDynamicAnchor([
224 jsPlumb.makeAnchor(0, 0, -1, 0, 0, targetField.position().top + mediumHeight + 4),
225 jsPlumb.makeAnchor(1, 0, 1, 0, 0, targetField.position().top + mediumHeight + 4)
226 ])
227 ]
228 });
229 qbe.CurrentRelations.push(sourceField.attr("id") +"~"+ targetField.attr("id"));
230 }
231
232 /**
233 * Add related many to many models through clicking in the field name
234 */
235 qbe.Diagram.addRelated = function (obj) {
236 var splits, appName, modelName, fieldName, field, target;
237 splits = this.id.split("qbeBoxField_")[1].split(".");
238 appName = splits[0];
239 modelName = splits[1];
240 fieldName = splits[2];
241 field = qbe.Models[appName][modelName].fields[fieldName];
242 target = field.target;
243 qbe.Core.addModule(target.name, target.model);
244 $("#qbeModelAnchor_"+ target.name +"\\\."+ target.model).click();
245 if (target.through && (!qbe.Models[target.through.name][target.through.model].is_auto)) {
246 qbe.Core.addModule(target.through.name, target.through.model);
247 $("#qbeModelAnchor_"+ target.through.name +"\\\."+ target.through.model).click();
248 }
249 $(".qbeCheckModels").change();
250 };
251
252 /**
253 * Returns a boolean value according to the relation between sourceId
254 * and targetId does exist or not
255 */
256 qbe.Diagram.hasConnection = function (sourceField, targetField) {
257 return (sourceField && targetField
258 && qbe.CurrentRelations.indexOf(sourceField.attr("id") +"~"+ targetField.attr("id")) >= 0);
259 };
260
261 /**
262 * Remove the box and all connections related to it
263 */
264 qbe.Diagram.removeBox = function (appName, modelName) {
265 $("#qbeBox_"+ modelName).remove();
266 };
267
268 /**
269 * Remove all connetions for the box identified by appName and modelName
270 */
271 qbe.Diagram.removeRelations = function (appName, modelName) {
272 var currentRelations, relation, relationsSplits, relationsLength, sourceSplits, sourceId, targetSplits, targetId;
273 currentRelations = [];
274 relationsLength = qbe.CurrentRelations.length;
275 for(var i=0; i<relationsLength; i++) {
276 relation = qbe.CurrentRelations[i];
277 if (relation.indexOf(appName +"."+ modelName) < 0) {
278 currentRelations.push(relation);
279 } else {
280 relationsSplit = relation.split("~");
281 source = relationsSplit[0];
282 sourceSplits = source.split("qbeBoxField_")[1].split(".");
283 sourceId = "qbeBox_"+ sourceSplits[1];
284 target = relationsSplit[1];
285 targetSplits = target.split("qbeBoxField_")[1].split(".");
286 targetId = "qbeBox_"+ targetSplits[1];
287 jsPlumb.detach(sourceId, targetId);
288 }
289 }
290 qbe.CurrentRelations = currentRelations;
291 jsPlumb.clearCache();
292 };
293
294 /**
295 * Save the positions of the all the boxes in a serialized way into a
296 * input type hidden
297 */
298 qbe.Diagram.saveBoxPositions = function () {
299 var positions, left, top, splits, appModel, modelName;
300 positions = [];
301 for(var i=0; i<qbe.CurrentModels.length; i++) {
302 appModel = qbe.CurrentModels[i];
303 splits = appModel.split(".");
304 modelName = splits[1];
305 left = $("#qbeBox_"+ modelName).css("left");
306 top = $("#qbeBox_"+ modelName).css("top");
307 positions.push(appModel +"@"+ left +";"+ top);
308 }
309 $("#id_form_positions").val(positions.join("|"));
310 };
311
312 /**
313 * Repaint the models and relations among them
314 */
315 qbe.Diagram.repaintAll = function () {
316 var appModel, splits;
317 for(var i=0; i<qbe.CurrentModels.length; i++) {
318 appModel = qbe.CurrentModels[i];
319 splits = appModel.split(".");
320 qbe.Diagram.removeRelations(splits[0], splits[1]);
321 }
322 qbe.Core.updateRelations();
323 };
324
325 });
326
327
328 /**
329 * Resize the diagram container height according to the resize event over
330 * the window
331 */
332 $(window).resize(function () {
333 var height;
334 height = $(window).height() - 140;
335 $("#qbeDiagramContainer").height(height);
336 $(".qbeModelList").height(height);
337 });
338
339 /**
340 * Unload jsPlumb
341 */
342 $(window).unload(function () {
343 jsPlumb.unload();
344 });
345
346 })(jQuery.noConflict());