1 /** 2 * Copyright 2008-Present actioncenters.org 3 * 4 * This file is part of actioncenters.org. 5 * 6 * Actioncenters.org is free software: you can redistribute it and/or modify 7 * it under the terms of the BSD License found in the LICENSE.txt file. 8 */ 9 10 /** @fileOverview Provides PSS utility functions. */ 11 12 /*global Ext, dojox, AC, actionCenterAPI */ 13 14 Ext.namespace('AC.pss'); 15 16 /** 17 * Default constructor. 18 * 19 * @class The empty/root renderer. This is the object that is responsible for rendering a component. 20 * @param componentConfiguration 21 * the component configuration 22 */ 23 AC.pss.EmptyRenderer = function (componentConfiguration) { 24 this.componentConfiguration = componentConfiguration; 25 if (this.componentConfiguration.getPropertyValue("openMultiple") !== null) { 26 this.multiInstanceComponent = (this.componentConfiguration.getPropertyValue("openMultiple") === 'Y'); 27 } else { 28 this.multiInstanceComponent = true; 29 } 30 this.reloading = false; 31 32 /** 33 * Gets the component configuration. 34 * 35 * @return the component configuration. 36 */ 37 this.getComponentConfiguration = function () { 38 return this.componentConfiguration; 39 }; 40 41 /** 42 * Handles user's 'send' action. 43 * 44 * @return void 45 */ 46 this.onSend = function () { 47 // do nothing here 48 }; 49 } 50 51 /** 52 * @class Component renderer. This class is responsible for rendering a component. 53 * @extends AC.pss.EmptyRenderer 54 */ 55 AC.pss.ComponentRenderer = Ext.extend(AC.pss.EmptyRenderer, 56 /** @lends AC.pss.ComponentRenderer */ 57 { 58 /** 59 * Default constructor. 60 * 61 * @param componentConfiguration 62 * the component configuration 63 */ 64 constructor: function (componentConfiguration) { 65 AC.pss.ComponentRenderer.superclass.constructor.call(this, componentConfiguration); 66 67 /** 68 * Handles user's 'send' action. If this component is configured to swap, this handler will invoke a swap. 69 * 70 * @return void 71 */ 72 this.onSend = function () { 73 if ("Y" === this.getComponentConfiguration().getPropertyValue('swapperMode')) { 74 this.swap(); 75 var container = this.subcomponentInstance.findByItemId('subcomponentContainer'); 76 if (container) { 77 container.fireEvent('swap'); 78 } 79 } 80 }; 81 }, 82 83 /** 84 * Destroys this component. 85 * 86 * @param superiorContributionId 87 * the superior contribution id 88 * @param launchPoint 89 * the launch point 90 * @return void 91 */ 92 destroyComponent: function (superiorContributionId, launchPoint) { 93 if (this.subcomponentInstance) { 94 this.subcomponentInstance.close(); 95 this.subcomponentInstance = null; 96 } 97 if (this.subscription) { 98 dojox.cometd.unsubscribe(this.subscription); 99 this.subscription = null; 100 } 101 }, 102 103 /** 104 * Renders this component. 105 * 106 * @param superiorContributionId 107 * the superior contribution id 108 * @param launchPoint 109 * The object that triggered or invoked the rendering of this component. There are times where it is necessary 110 * for a component to know information about where it was invoked from. This is accomplished by calling back to a 111 * method on the launchPoint. 112 * @return void 113 */ 114 renderComponent: function (superiorContributionId, launchPoint) { 115 this.windowId = superiorContributionId + launchPoint.id + this.getComponentConfiguration().getId(); 116 this.superiorContributionId = superiorContributionId; 117 if (!this.multiInstanceComponent && this.subcomponentInstance) { 118 //this.destroyComponent(); 119 this.reloading = true; 120 this.superiorRootContributionId = null; 121 } else if (Ext.WindowMgr.get(this.windowId)) { 122 Ext.WindowMgr.bringToFront(this.windowId); 123 //return; 124 } 125 this.launchPoint = launchPoint; 126 if ("Y" === this.getComponentConfiguration().getPropertyValue('swapperMode')) { 127 this.swap(); 128 } else { 129 this.renderIt(); 130 } 131 }, 132 133 /** 134 * Swaps the superior contribution for this component. This will cause the component to reload itself with a new superior contribution. 135 * 136 * @return void 137 */ 138 swap : function () { 139 if (this.beforeSwap) { 140 this.beforeSwap(); 141 } 142 if (this.subcomponentInstance) { 143 //this.destroyComponent(); 144 if (this.subscription) { 145 dojox.cometd.unsubscribe(this.subscription); 146 this.subscription = null; 147 } 148 this.reloading = true; 149 } 150 151 if (!this.superiorRootContributionId && this.launchPoint && this.launchPoint.getRootContributionId) { 152 this.superiorRootContributionId = this.launchPoint.getRootContributionId(); 153 } 154 if (this.superiorRootContributionId) { 155 actionCenterAPI.getSwapperParent(this.superiorRootContributionId, this.getComponentConfiguration().getId(), 156 this.superiorContributionId, this.getComponentConfiguration().getPropertyValue('subComponentId'), 157 this, this.swapCallback); 158 } else { 159 this.renderIt(); 160 } 161 }, 162 163 /** 164 * Callback function for swapping. This function registers the component to listen on a specific swapping channel 165 * so that the server can keep track of which clients are subscribed to which superior contributions. 166 * 167 * @param msg 168 * the message 169 * @return void 170 */ 171 swapCallback : function (msg) { 172 actionCenterAPI.startBatch(); 173 this.superiorContributionId = msg.data.swapperContributionId; 174 var channel = '/contributions/contribution/swapper/' + this.superiorContributionId; 175 this.subscription = dojox.cometd.subscribe(channel, this, function () { 176 // do nothing here.. this is a dummy callback method that should not get called because we don't intend to publish anything on the swapper channel 177 console.log('this should not happen'); 178 }); 179 actionCenterAPI.endBatch(); 180 181 // if this component has a parent and this component is configured to activate its parent 182 if (this.launchPoint && this.componentConfiguration.getParsedProperties().activeContributionMarker === 'Y') { // activate the new superior node's active contribution marker 183 this.launchPoint.root.cascade(function () { 184 if (this.contributionId === msg.data.swapperContributionId) { 185 this.ownerTree.selModel.activateNode(this); 186 } 187 }); 188 } 189 190 this.renderIt(); 191 }, 192 193 /** 194 * Renders this component. 195 * 196 * @return void 197 */ 198 renderIt : function () { 199 if (this.reloading) { 200 var subComponent = this.subcomponentInstance.items.items[0]; 201 subComponent.reload(this.superiorContributionId); 202 this.reloading = false; 203 } else { 204 AC.pss.Utility.renderIt( 205 this.superiorContributionId, 206 this.getComponentConfiguration().getId(), 207 null, 208 this, this.launchSubCompCallback, 209 this); 210 } 211 }, 212 213 /** 214 * Callback function invoked after renderIt(). This function creates a popup window and renders the subcomponent into it. 215 * 216 * @param subComponent 217 * the sub-component 218 * @return void 219 */ 220 launchSubCompCallback : function (subComponent) { 221 var windowTitle = this.getComponentConfiguration().getPropertyValue('name'); 222 if (Ext.WindowMgr.get(this.windowId)) { 223 Ext.WindowMgr.bringToFront(this.windowId); 224 return; 225 } 226 var popupHeight = this.getComponentConfiguration().getPropertyValue('popupHeight'); 227 var popupWidth = this.getComponentConfiguration().getPropertyValue('popupWidth'); 228 var browserDim = actionCenterUtility.getBrowserDimensions(); 229 this.subcomponentInstance = new Ext.Window({ 230 id: this.windowId, 231 itemId: 'subcomponentwindow', 232 layout: 'fit', 233 items: [subComponent], 234 title: windowTitle, 235 height: browserDim.height * parseInt(popupHeight, 10) / 100, 236 width: browserDim.width * parseInt(popupWidth, 10) / 100, 237 minHeight: 0, 238 minWidth: 0, 239 maximizable: true, 240 constrainHeader: true, 241 launchPoint: this.launchPoint, 242 componentRenderer: this, 243 destroy: function () { 244 if (this.launchPoint && this.launchPoint.onRenderedComponentDestroy) { 245 this.launchPoint.onRenderedComponentDestroy(); 246 } 247 Ext.Window.superclass.destroy.call(this); 248 if (this.componentRenderer.subscription) { 249 dojox.cometd.unsubscribe(this.componentRenderer.subscription); 250 this.componentRenderer.subscription = null; 251 } 252 this.componentRenderer.subcomponentInstance = null; 253 } 254 }).show(); 255 } 256 }); 257 258 /** 259 * Default constructor. 260 * 261 * @class Component controller. 262 * @param superiorContributionId 263 * the superior contribution id 264 * @param componentId 265 * the id of the component's configuration 266 * @param target 267 * the location to render this component 268 * @param callbackObject 269 * the callback object 270 * @param callback 271 * the function to call back once the component is created 272 * @param renderer 273 * the renderer that rendered this component 274 * @param subComponentRenderers 275 * an array of subcomponent renderers 276 */ 277 AC.pss.ComponentController = function (superiorContributionId, componentId, target, callbackObject, callback, renderer, subComponentRenderers) { 278 this.target = target; 279 this.superiorContribution = null; 280 this.renderer = renderer; 281 this.callback = callback; 282 this.callbackObject = callbackObject; 283 this.providedRenderers = subComponentRenderers; 284 285 /** 286 * Initiliazes this component controller when rendering the top-level component. 287 * 288 * @param msg 289 * the message 290 * @return void 291 */ 292 this.initialize = function (msg) { 293 this.renderer = new AC.pss.EmptyRenderer(new AC.data.Contribution(msg.data.component)); 294 this.superiorContribution = new AC.data.Contribution(msg.data.superiorContribution); 295 this.render(); 296 }; 297 298 /** 299 * Initializes the superior contribution. 300 * 301 * @param msg 302 * the message 303 * @return void 304 */ 305 this.initSuperiorContribution = function (msg) { 306 this.superiorContribution = new AC.data.Contribution(msg.data.contribution); 307 this.render(); 308 }; 309 310 /** 311 * Initializes the control. 312 * 313 * @param msg 314 * the message 315 * @return void 316 */ 317 this.initControl = function (msg) { 318 this.renderer = new AC.pss.EmptyRenderer(new AC.data.Contribution(msg.data.contribution)); 319 this.render(); 320 }; 321 322 /** 323 * Creates a component renderer. 324 * 325 * @param subComponentConfiguration 326 * the sub-component configuration 327 * @return the component renderer 328 */ 329 // Given a subComponentConfiguration see if there was a renderer passed in for it or create a new one 330 // if one was not passed in for it. 331 this.createRenderer = function (subComponentConfiguration) { 332 var returnValue = null; 333 if (this.providedRenderers) { 334 for (var i = 0; i < this.providedRenderers.length; i++) { 335 var providedRenderer = this.providedRenderers[i]; 336 if (providedRenderer.getComponentConfiguration().getId() === subComponentConfiguration.id) { 337 returnValue = providedRenderer; 338 break; 339 } 340 } 341 } 342 if (!returnValue) { 343 returnValue = new AC.pss.ComponentRenderer(new AC.data.Contribution(subComponentConfiguration)); 344 } 345 return returnValue; 346 }; 347 348 /** 349 * Renders this component. 350 * 351 * @return void 352 */ 353 this.render = function () { 354 if (!this.subComponentRenderers) { 355 this.subComponentRenderers = []; 356 if (this.renderer.getComponentConfiguration()._msg.subComponents) { 357 for (var i = 0; i < this.renderer.getComponentConfiguration()._msg.subComponents.length; i++) { 358 var subComponentConfiguration = this.renderer.getComponentConfiguration()._msg.subComponents[i]; 359 this.subComponentRenderers.push(this.createRenderer(subComponentConfiguration)); 360 } 361 } 362 } 363 var command = "var componentObject = new " + this.renderer.getComponentConfiguration().getPropertyValue("subType") + "(" + 364 "this.superiorContribution, " + 365 "this.renderer, " + 366 "this.subComponentRenderers, " + 367 "this.target);"; 368 eval(command); 369 370 if (this.callbackObject && this.callback) { 371 callback.call(this.callbackObject, componentObject.getPanel()); 372 } 373 }; 374 375 if (!this.renderer) { 376 if (!superiorContributionId) { 377 // this must be a control 378 actionCenterAPI.getContribution(componentId, this, this.initControl); 379 } else { 380 // this is a top level component 381 actionCenterAPI.getComponentConfiguration(superiorContributionId, componentId, this, this.initialize); 382 } 383 } else { 384 // this is a child component 385 actionCenterAPI.getContribution(superiorContributionId, this, this.initSuperiorContribution); 386 } 387 } 388 // The necessary cleanup on unload 389 window.onbeforeunload = function (e) { 390 AC.pss.Utility.endUserScreenSubscription(); 391 var windowItems = AC.pss.divViewportManager; 392 for (var i = windowItems.length - 1; i >= 0; i--) { 393 var windowItem = windowItems[i]; 394 try { 395 windowItem.destroy(); 396 } catch (err) { 397 // console.log("error occurred while destroying an item"); 398 } 399 } 400 }; 401 402 /** 403 * Default constructor. 404 * 405 * @class AC PSS utility 406 */ 407 AC.pss.Utility = { 408 /** 409 * Starts a listener for relationships of the specified user to the specified role and activity ids. 410 * 411 * @param roleUserRelationshipId 412 * the role user relationship id 413 * @param activityUserRelationshipId 414 * the activity user relationship id 415 * @return void 416 */ 417 startUserPageListener : function (roleUserRelationshipId, activityUserRelationshipId) { 418 actionCenterAPI.startBatch(); 419 var rolechannel = "/relationships/relationship/" + roleUserRelationshipId + "/delete"; 420 var activitychannel = "/relationships/relationship/" + activityUserRelationshipId + "/delete"; 421 dojox.cometd.subscribe(rolechannel, AC.pss.Utility, 'refreshPage'); 422 dojox.cometd.subscribe(activitychannel, AC.pss.Utility, 'refreshPage'); 423 actionCenterAPI.endBatch(); 424 }, 425 426 /** 427 * Callback function executed upon deletion of a user's role and activity relationships. 428 * 429 * @return void 430 */ 431 refreshPage : function () { 432 AC.pss.Utility.endUserScreenSubscription(); 433 location.reload(true); 434 }, 435 436 /** 437 * Starts a subscription so that the server can monitor when a user closes a window. 438 * 439 * @return void 440 */ 441 startUserScreenSubscription : function () { 442 var userScreenChannel = "/service/thumbprint/" + currentScreenId + "/" + actionCenterAPI.getUserId(); 443 // this subscription is only here so that the server can track when a user closes the page 444 // nothing should ever be pe published on this channel 445 AC.pss.Utility.userScreenSubscription = dojox.cometd.subscribe(userScreenChannel, AC.pss.Utility, 'doNothing'); 446 }, 447 448 /** 449 * Ends a subscription so that the server can monitor when a user closes a window. 450 * 451 * @return void 452 */ 453 endUserScreenSubscription : function () { 454 if (AC.pss.Utility.userScreenSubscription) { 455 dojox.cometd.unsubscribe(AC.pss.Utility.userScreenSubscription); 456 } 457 AC.pss.Utility.userScreenSubscription = null; 458 }, 459 460 /** 461 * Callback function. This should never be called but it needs to be here so that the User Screen 462 * subscription has a dummy callback. 463 * 464 * @return void 465 */ 466 doNothing : function () { 467 }, 468 469 /** 470 * Renders the specified component to the specified target location using the specified renderers. 471 * 472 * @param superiorContributionId 473 * the superior contribution id 474 * @param componentId 475 * the component id 476 * @param target 477 * the rendering target 478 * @param callbackObject 479 * the callback object 480 * @param callbackMethod 481 * the callback method 482 * @param renderer 483 * the component renderer 484 * @param subComponentRenderers 485 * the sub-component renderers 486 * @return void 487 */ 488 renderIt: function (superiorContributionId, componentId, target, callbackObject, callbackMethod, renderer, subComponentRenderers) { 489 var componentController = new AC.pss.ComponentController(superiorContributionId, componentId, target, callbackObject, callbackMethod, renderer, subComponentRenderers); 490 }, 491 492 /** 493 * Renders the specified tool as a button to the specified target location. 494 * 495 * @param config 496 * the configuration of the button 497 * 498 * @return void 499 */ 500 renderItAsButton: function (config) { 501 //initiate the button 502 var buttonIcon = config.icon; 503 var buttonLabel = config.buttonLabel; 504 var pssButton = new AC.pss.Button({ 505 buttonIcon: buttonIcon, 506 buttonLabel: buttonLabel, 507 handler: function(){ 508 if(this.popupWindow){ 509 this.popupWindow.show(); 510 } else { 511 var windowTitle = config.windowTitle; 512 var popupHeight = config.popupHeight; 513 var popupWidth = config.popupWidth; 514 var browserDim = actionCenterUtility.getBrowserDimensions(); 515 this.popupWindow = new AC.Window({ 516 title: windowTitle, 517 layout: 'fit', 518 height: browserDim.height * parseInt(popupHeight, 10) / 100, 519 width: browserDim.width * parseInt(popupWidth, 10) / 100 520 }); 521 AC.pss.Utility.renderIt(config.superiorContributionId,config.componentId,null,this,this.launchPopupWindow); 522 } 523 }, 524 launchPopupWindow: function(component){ 525 this.popupWindow.add(component); 526 this.popupWindow.doLayout(); 527 if(this.popupWindow.hidden){ 528 this.popupWindow.show(); 529 } 530 } 531 }); 532 533 var divConfig = { 534 renderTo: config.target, 535 layout: 'fit', 536 items: [pssButton] 537 }; 538 AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig)); 539 } 540 }; 541 542 543 //********************************************************************************************************************** 544 /** 545 * @class 546 * <p>A specialized container representing the viewable application area similar to the Ext.Viewport(the browser viewport).</p> 547 * <p>The DivViewport renders itself to the Dom element identified by the renderTo attribute, and is kept in the 548 * AC.pss.divViewportManager and resized as the browser resizes. 549 * We can have multiple DivViewports in a web page. However, each DivViewport can only contain a child item. 550 * @extends Ext.Container 551 * 552 * @constructor Default constructor that creates a new DivViewport 553 * @param {Object} config The config object 554 * @xtype divviewport 555 */ 556 Ext.ux.DivViewport = Ext.extend(Ext.Container, 557 /** @lends Ext.ux.DivViewport */ 558 { 559 /* 560 * Privatize config options which, if used, would interfere with the 561 * correct operation of the Viewport as the sole manager of the 562 * layout of the document body. 563 */ 564 /** 565 * @cfg {Mixed} applyTo @hide 566 */ 567 /** 568 * @cfg {Boolean} allowDomMove @hide 569 */ 570 /** 571 * @cfg {Boolean} hideParent @hide 572 */ 573 /** 574 * @cfg {Mixed} renderTo @hide 575 */ 576 /** 577 * @cfg {Boolean} hideParent @hide 578 */ 579 /** 580 * @cfg {Number} height @hide 581 */ 582 /** 583 * @cfg {Number} width @hide 584 */ 585 /** 586 * @cfg {Boolean} autoHeight @hide 587 */ 588 /** 589 * @cfg {Boolean} autoWidth @hide 590 */ 591 /** 592 * @cfg {Boolean} deferHeight @hide 593 */ 594 /** 595 * @cfg {Boolean} monitorResize @hide 596 */ 597 598 /** 599 * Initializes this component. 600 * 601 * @return void 602 */ 603 initComponent : function () { 604 Ext.ux.DivViewport.superclass.initComponent.call(this); 605 this.el = Ext.get(this.renderTo); 606 this.el.setHeight = Ext.emptyFn; 607 this.el.setWidth = Ext.emptyFn; 608 this.el.setSize = Ext.emptyFn; 609 this.el.dom.scroll = 'no'; 610 this.allowDomMove = false; 611 } 612 }); 613 Ext.reg('divviewport', Ext.ux.DivViewport); 614 615 616 //********************************************************************************************************************** 617 /** 618 * Array of DivViewports. This manager keeps track of all the DivViewports created. 619 * 620 * @default [] 621 */ 622 AC.pss.divViewportManager = []; 623 624 /** 625 * Handles browser resize events. 626 * 627 * @return void 628 */ 629 var fireResize = function () { 630 //a little trick,at first we have to reduce the size of the child item of the div viewport to 0 631 //so that the size of the div viewport can change according to the new size of the browser. 632 //If we don't do so, the div viewport minimum size will always be the size of its child item. 633 var i; 634 for (i = 0; i < AC.pss.divViewportManager.length; i++) { 635 AC.pss.divViewportManager[i].items.items[0].setSize(0, 0); 636 } 637 //after getting the new size, set the size of the child item to this new size. 638 for (i = 0; i < AC.pss.divViewportManager.length; i++) { 639 var w = AC.pss.divViewportManager[i].el.dom.clientWidth; 640 var h = AC.pss.divViewportManager[i].el.dom.clientHeight; 641 AC.pss.divViewportManager[i].items.items[0].setSize(w, h); 642 } 643 }; 644 645 //*********************************************** AC_Component ***************************************************************** 646 //This is a generic class for all the Components in the PSS that are built based on Extjs 647 //At the moment, we just copy and paste all the code from the AC_Outliner 648 //****************************************************************************************************************************** 649 650 //****************************** Outliner Explorer Grid Node **************************************** 651 actioncenter.outlinerExplorerGridNode = function (attributes) { 652 attributes = attributes || {}; 653 this.allowDropOnlyValidChildTypes = false; 654 this.dragOnlyFirstCell = true; 655 this.type = "AC_ComponentSuperior"; 656 actioncenter.outlinerExplorerGridNode.superclass.constructor.call(this, attributes); 657 this.pasteProfiles = null; 658 this.fontString = ''; 659 this.expanded = true; 660 var uiClass = actioncenter.outlinerExplorerGridNodeUI; 661 if (this.ui) { 662 this.ui.destroy(); 663 } 664 this.ui = new uiClass(this); 665 this.triggerEventRegistry = [];//the cache to contain the trigger events for each sub component 666 }; 667 668 Ext.extend(actioncenter.outlinerExplorerGridNode, actioncenter.standardTreeGridNode, 669 /** @lends actioncenter.outlinerExplorerGridNode */ 670 { 671 /** 672 * @override 673 * 674 * Invokes the sorting after finishing the initial load. 675 * 676 * @return void 677 */ 678 sortAfterLoad: function () { 679 //only sort the child nodes of the nodes other than the root node 680 //The child nodes of the root are already sorted at the outliner panel level 681 var root = this.getOwnerTree().root; 682 if (this !== root){ 683 actionCenterUtility.reorder(this); 684 } 685 }, 686 editNode: function (msg) { 687 var lock = actionCenterJSON.getMsgProperty(msg, 'data.contribution.lockedBy'); 688 this.toggleLockInfo(lock); 689 var newType = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type'); 690 if (this.type !== 'AC_ComponentSuperior' && this.type !== newType) { 691 this.type = newType; 692 var sm = this.getOwnerTree().getSelectionModel(); 693 sm.fireEvent('anchorchange', sm.tree, sm.anchoredNode); 694 this.cascade(function() { 695 this.setAttributes(); 696 return true; 697 }); 698 } 699 }, 700 701 /** 702 * Creates a child node. 703 * 704 * @param msg 705 * the message 706 * @return void 707 */ 708 createChild: function (msg) { 709 var id = actionCenterJSON.getMsgProperty(msg, 'data.contribution.id'); 710 var existingchild = this.findChild("contributionId", id); 711 var wsnode = null; 712 if (existingchild == null) { 713 var contributionType = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type'); 714 var nodeText = actionCenterJSON.getMsgProperty(msg, 'data.contribution.contributionProperties.name.value'); 715 var childTypeList = this.attributes.populationRules.getAllChildTypeList(); 716 var customIcon = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIcon'); 717 if (!customIcon || customIcon.length === 0) customIcon = 'Ext.BLANK_IMAGE_URL'; 718 var normalIconHeight = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIconHeight'); 719 if (!normalIconHeight || normalIconHeight.length === 0) normalIconHeight = ''; 720 var normalIconWidth = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIconWidth'); 721 if (!normalIconWidth || normalIconWidth.length === 0) normalIconWidth = ''; 722 var activeIcon = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIcon'); 723 if (!activeIcon || activeIcon.length === 0) activeIcon = 'Ext.BLANK_IMAGE_URL'; 724 var activeIconHeight = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIconHeight'); 725 if (!activeIconHeight || activeIconHeight.length === 0) activeIconHeight = ''; 726 var activeIconWidth = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIconWidth'); 727 if (!activeIconWidth || activeIconWidth.length === 0) activeIconWidth = ''; 728 var populationRuleId = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'id'); 729 if (populationRuleId == undefined) populationRuleId = ''; 730 var order = actionCenterJSON.getMsgProperty(msg, 'data.contribution.contributionProperties.AC_Order.value'); 731 var isValidType = this.attributes.populationRules.isValidChildType(this.type, contributionType); 732 wsnode = new actioncenter.outlinerExplorerGridNode({ 733 isInvalidType: !isValidType, 734 type: contributionType, 735 name: nodeText, 736 text: nodeText, 737 colstyles: 'x-treegrid-col-no-border', 738 cls:'AC_'+populationRuleId, 739 selectedCls:'AC_'+populationRuleId+'-selected', 740 overCls:'AC_'+populationRuleId+'-over', 741 over_selectedCls:'AC_'+populationRuleId+'-over_selected', 742 useCustomIcon: true, 743 customIcon: customIcon, 744 normalIcon: customIcon, 745 activeIcon: activeIcon, 746 iconWidth: this.attributes.iconWidth, 747 iconHeight: this.attributes.iconHeight, 748 normalWidth: normalIconWidth, 749 normalHeight: normalIconHeight, 750 activeWidth: activeIconWidth, 751 activeHeight: activeIconHeight, 752 contributionId: id, 753 populationRules: this.attributes.populationRules, 754 order: order, 755 contextMenu: [{cut: true}, 756 {copy: true}, 757 {pastebefore: true}, 758 {pasteafter: true}, 759 {pastesub: true}, 760 {del: true}], 761 listenProfiles: [{channelId : id, 762 childType : childTypeList, 763 updateSelf : true, 764 properties : [{key: 'AC_Order', method: 'editOrder'}, 765 {key: 'name', method: 'editText'}, 766 {key: 'icon', method: 'editIcon'}] 767 }], 768 treePanelId: 'outlinerPanel' + this.componentId 769 }); 770 window.actionCenterUtility.reorder(this, wsnode); 771 wsnode.subscribeAllChannels(); 772 } 773 return wsnode; 774 }, 775 776 /** 777 * Updates appropriate attributes for this contribution in its new location. 778 * 779 * @param contributionMsg 780 * the contribution message 781 */ 782 setAttributes: function (msg) { 783 if (msg) { 784 this.type = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type'); 785 } 786 787 this.attributes.customIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIcon'); 788 this.attributes.normalIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIcon'); 789 this.attributes.activeIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIcon'); 790 //change the node format to match its type 791 this.attributes.type = this.type; 792 var clsArray = [this.attributes.cls, this.attributes.selectedCls, this.attributes.overCls, this.attributes.over_selectedCls]; 793 if (this.ui){ 794 this.ui.removeClass(clsArray); 795 this.ui.removeCssClass(clsArray); 796 } 797 var populationRuleId = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'id'); 798 this.attributes.cls = 'AC_'+populationRuleId; 799 this.attributes.selectedCls = 'AC_'+populationRuleId+'-selected'; 800 this.attributes.overCls = 'AC_'+populationRuleId+'-over'; 801 this.attributes.over_selectedCls = 'AC_'+populationRuleId+'-over_selected'; 802 if (this.ui){ 803 this.ui.addClass(this.attributes.cls); 804 this.ui.addCssClass(this.attributes.cls); 805 } 806 //end of changing the node format 807 if (!this.attributes.customIcon || this.attributes.customIcon.length === 0) { 808 this.attributes.customIcon = 'Ext.BLANK_IMAGE_URL'; 809 } 810 if (!this.attributes.normalIcon || this.attributes.normalIcon.length === 0) { 811 this.attributes.normalIcon = 'Ext.BLANK_IMAGE_URL'; 812 } 813 if (!this.attributes.activeIcon || this.attributes.activeIcon.length === 0) { 814 this.attributes.activeIcon = 'Ext.BLANK_IMAGE_URL'; 815 } 816 this.attributes.normalIconWidth = 817 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIconWidth') 818 || this.attributes.iconWidth; 819 this.attributes.normalIconHeight = 820 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIconHeight') 821 || this.attributes.iconHeight; 822 this.attributes.activeIconWidth = 823 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIconWidth') 824 || this.attributes.iconWidth; 825 this.attributes.activeIconHeight = 826 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIconHeight') 827 || this.attributes.iconHeight; 828 this.attributes.isInvalidType = !this.attributes.populationRules.isValidChildType(this.parentNode.type, this.type); 829 if (this == this.ownerTree.selModel.activeNode) { 830 this.ui.onActiveChange(true); 831 } else { 832 this.ui.onActiveChange(false); 833 } 834 this.toggleInvalidIndicator(); 835 }, 836 837 /** 838 * Deletes a child node. 839 * 840 * @param msg 841 * the message 842 * 843 * @return void 844 */ 845 deleteChild: function (msg) { 846 if (!this.isMove(msg)) { 847 var childId = actionCenterJSON.getMsgProperty(msg,'data.contribution.id'); 848 849 var node = this.findChild('contributionId', childId); 850 if (node != null) { 851 //this.beforeDeleteChild(msg, node); 852 var sm = this.getOwnerTree().getSelectionModel(); 853 var isAnchoredNode; 854 if (sm.anchoredNode === node) { 855 isAnchoredNode = true; 856 } 857 node.cleanUp(); 858 this.removeChild(node); 859 if (node.counter) { 860 window.actionCenterUtility.reorderCounter(this); 861 } 862 if (isAnchoredNode) { 863 sm.fireEvent('iyo'); 864 } 865 } 866 } 867 return; 868 }, 869 870 handleSubComponentTrigger: function (event) { 871 for (var i=0; i < this.triggerEventRegistry.length;i++) { 872 var subCompTriggers = this.triggerEventRegistry[i]; 873 var triggerEvents = subCompTriggers.triggerEvents; 874 for (var j=0;j < triggerEvents.length;j++) { 875 if (triggerEvents[j] == event) { 876 var subCompCell = this.getCellObject(this.getOwnerTree(),this,subCompTriggers.subComponentCol); 877 subCompCell.launchSubCompWindow();//this is to launch the sub component window 878 break; 879 } 880 } 881 } 882 }, 883 884 /** 885 * Handles beforeremove events. 886 * 887 * @param tree 888 * the tree 889 * @param parentNode 890 * the parent node 891 * @param node 892 * the node 893 * @return true 894 */ 895 onBeforeremove: function (tree, parentNode, node) { 896 actioncenter.outlinerExplorerGridNode.superclass.onBeforeremove.call(this,tree, parentNode, node); 897 var tree = node.getOwnerTree(); 898 var sm = tree.selModel; 899 var cols = tree.columns; 900 var pcChildCol = null; 901 for(var i = 0;i<cols.length;i++){ 902 if (cols[i].renderer && cols[i].renderer.type == 'pcChildComponentRenderer'){ 903 pcChildCol = cols[i]; 904 break; 905 } 906 } 907 if (pcChildCol){ 908 if (sm.anchoredNode){ 909 var n = sm.anchoredNode; 910 var subCompCell = n.getCellObject(n.getOwnerTree(),n,pcChildCol); 911 subCompCell.launchSubCompWindow();//this is to launch the sub component window 912 } else { 913 //there is no nodes left in the outliner 914 pcChildCol.renderer.destroyComponent(); 915 } 916 } 917 } 918 }); 919 //****************************** Outliner Explorer Grid Node UI **************************************** 920 actioncenter.outlinerExplorerGridNodeUI = Ext.extend(Ext.ux.tree.ACTreeGridNodeUI, { 921 isDoubleClickEvent: false, 922 923 render: function (bulkRender) { 924 actioncenter.outlinerExplorerGridNodeUI.superclass.render.call(this, bulkRender); 925 this.addCssClass(this.node.attributes.cls); 926 }, 927 928 // private 929 //override 930 onSelectedChange : function (state, focusNotAllowed) { 931 actioncenter.outlinerExplorerGridNodeUI.superclass.onSelectedChange.call(this, state, focusNotAllowed); 932 // remove the over css classes 933 var clsArray = [this.node.attributes.overCls, this.node.attributes.over_selectedCls]; 934 var el = Ext.fly(this.elNode); 935 el.removeClass(clsArray); 936 this.removeCssClass(clsArray); 937 938 // then add the selected css class 939 if (state) { 940 this.addClass(this.node.attributes.selectedCls); 941 this.addCssClass(this.node.attributes.selectedCls); 942 }else{ 943 this.removeClass(this.node.attributes.selectedCls); 944 this.removeCssClass(this.node.attributes.selectedCls); 945 } 946 }, 947 948 onOver : function (e) { 949 actioncenter.outlinerExplorerGridNodeUI.superclass.onOver.call(this, e); 950 var cls; 951 if (this.node.isSelected()) { 952 cls = this.node.attributes.over_selectedCls; 953 } else { 954 cls = this.node.attributes.overCls; 955 } 956 this.addClass(cls); 957 this.addCssClass(cls); 958 }, 959 960 onOut : function (e) { 961 actioncenter.outlinerExplorerGridNodeUI.superclass.onOut.call(this, e); 962 var cls; 963 if (this.node.isSelected()) { 964 cls = this.node.attributes.over_selectedCls; 965 } else { 966 cls = this.node.attributes.overCls; 967 } 968 this.removeClass(cls); 969 this.removeCssClass(cls); 970 }, 971 972 addCssClass: function (cls) { 973 var el = Ext.fly(this.elNode); 974 var spanChildren = el.query('td span'); 975 for (var i = 0; i < spanChildren.length; i++) { 976 var childEl = Ext.fly(spanChildren[i]); 977 childEl.addClass(cls); 978 } 979 }, 980 981 removeCssClass: function (cls) { 982 var el = Ext.fly(this.elNode); 983 var spanChildren = el.query('td span'); 984 for (var i = 0; i < spanChildren.length; i++) { 985 var childEl = Ext.fly(spanChildren[i]); 986 childEl.removeClass(cls); 987 } 988 }, 989 990 /** 991 * Defines the double-click behavior. 992 * 993 * @param e 994 * the event 995 */ 996 onDblClick : function (e) { 997 e.stopEvent(); 998 this.isDoubleClickEvent = true; 999 this.node.handleSubComponentTrigger('dblclick'); 1000 }, 1001 /** 1002 * Defines the click behavior. 1003 * 1004 * @param e 1005 * the event 1006 */ 1007 onClick: function (e) { 1008 actioncenter.outlinerExplorerGridNodeUI.superclass.onClick.call(this,e); 1009 this.clickAction(); 1010 //this.node.handleSubComponentTrigger('click'); 1011 }, 1012 1013 clickAction: function () { 1014 this.isDoubleClickEvent = false; 1015 var obj = this; 1016 setTimeout(function () { 1017 if (!obj.isDoubleClickEvent) { 1018 obj.node.handleSubComponentTrigger('click'); 1019 } 1020 },500); 1021 } 1022 }); 1023 //********************************************************************************************************** 1024 //****************************** Outliner Subcomponent Grid Cell Object ************************************ 1025 Ext.ux.tree.ACOutlinerSubcomponentCell = function (row, col, treegrid, config) { 1026 Ext.ux.tree.ACOutlinerSubcomponentCell.superclass.constructor.call(this, row, col, treegrid, config); 1027 for (var i = 0; i < treegrid.ownerPanel.columns.length; i++) { 1028 var columnobj = treegrid.ownerPanel.columns[i]; 1029 if (columnobj.dataIndex === col) { 1030 this.superiorContributionId = row; 1031 this.renderer = columnobj.renderer; 1032 this.contribution = columnobj.renderer.getComponentConfiguration(); 1033 this.customIcon = columnobj.renderer.getComponentConfiguration().getPropertyValue('icon'); 1034 this.subType = columnobj.renderer.getComponentConfiguration().getPropertyValue('subType'); 1035 this.name = columnobj.name; 1036 this.displayHover = columnobj.renderer.getComponentConfiguration().getPropertyValue('name'); 1037 this.type = columnobj.type; 1038 return; 1039 } 1040 } 1041 }; 1042 1043 Ext.extend(Ext.ux.tree.ACOutlinerSubcomponentCell, Ext.ux.tree.ACTreeGridCell, { 1044 layout : 'anchor', 1045 anchored : true, 1046 type : 'AC_Component', 1047 populationRules : null, 1048 icon : Ext.BLANK_IMAGE_URL, 1049 afterRender: function () { 1050 Ext.ux.tree.ACOutlinerSubcomponentCell.superclass.afterRender.call(this); 1051 this.el.on({ 1052 scope: this, 1053 mouseover: this.onMouseOver, 1054 mouseout: this.onMouseOut, 1055 mouseup: this.onMouseUp, 1056 mousedown: this.onMouseDown 1057 }); 1058 if (!this.registered) { 1059 this.registered = true; 1060 } 1061 var emptyIconGUID = this.contribution.getPropertyValue("emptyIcon"); 1062 if (emptyIconGUID != null && emptyIconGUID.length > 0) { 1063 this.emptyIcon = AC.util.StandardIcons.getImageServlet() + emptyIconGUID; 1064 } else { 1065 this.emptyIcon = this.icon; 1066 } 1067 var filledIconGUID = this.contribution.getPropertyValue("filledIcon"); 1068 if (filledIconGUID != null && filledIconGUID.length > 0) { 1069 this.filledIcon = AC.util.StandardIcons.getImageServlet() + filledIconGUID; 1070 } else { 1071 this.filledIcon = this.icon; 1072 } 1073 if (this.contributionChildCounter && this.contributionChildCounter.count > 0) { 1074 this.icon = this.filledIcon; 1075 } else { 1076 this.icon = this.emptyIcon; 1077 } 1078 this.removeSubcomponentEl(); 1079 this.addSubcomponentEl(); 1080 this.triggerIcon = Ext.fly(this.el).child('.x-tree-trigger-icon'); 1081 this.newInfoMarkerImg = Ext.fly(this.el).child('.x-tree-infomarker'); 1082 Ext.QuickTips.getQuickTip().origAnchor = 'right'; 1083 Ext.QuickTips.register({ 1084 target: this.triggerIcon, 1085 text: this.getTipText(0,0), 1086 title: this.displayHover, 1087 anchor: 'right', 1088 trackMouse: true 1089 }); 1090 1091 //Send the trigger events that the row that contains this cell have to listen to 1092 // and response by launching the subcomponent 1093 var triggerEvents = this.contribution.getPropertyValue("triggerEvents"); 1094 if (triggerEvents && triggerEvents != '') { 1095 var triggerEventArray = triggerEvents.split('|~|'); 1096 this.row.triggerEventRegistry.push({subComponentCol:this.col,triggerEvents:triggerEventArray}); 1097 } 1098 1099 // actionCenterAPI.getPopulationRules(this.contribution.getId(), this, this.setPopulationRules); 1100 this.setPopulationRules(this.renderer.getComponentConfiguration()._msg.populationRules); 1101 }, 1102 getTipText: function (contributionsCount, newCount) { 1103 var tipText = "<br><div>Contributions: " + contributionsCount + "</div></br><div>New: " 1104 + newCount + "</div>"; 1105 return tipText; 1106 }, 1107 setPopulationRules: function (msg) { 1108 this.populationRules = msg; 1109 var populationRulesUtil = new AC.data.PopulationRulesParser(msg); 1110 this.contributionChildCounter = new AC.data.ContributionChildCounter(this.superiorContributionId, populationRulesUtil, this, this.updateCounter); 1111 var dropConvertToTypes = populationRulesUtil.getValidCastTypesOnTriggerDrop(); 1112 if (dropConvertToTypes) { 1113 this.drop = new Ext.dd.DropTarget(this.triggerImg, { 1114 // must be same as for tree 1115 ddGroup: this.ddGroup || "TreeDD", 1116 subCompentTagId: this.subCompentTagId, 1117 contributionId: this.row.contributionId, 1118 dropConvertToTypes: dropConvertToTypes, 1119 notifyEnter : function (dd, e, data) { 1120 return this.notifyOver(dd, e, data); 1121 }, 1122 notifyOver : function (dd, e, data) { 1123 if (!data) return this.dropNotAllowed; 1124 var dropNodes = data.nodes ? data.nodes : [data.node]; 1125 var isValid = true; 1126 for (var i=0; i < dropNodes.length; i++) { 1127 if (this.contributionId === dropNodes[i].contributionId) { 1128 isValid = false; 1129 } 1130 } 1131 if (isValid) 1132 return this.dropAllowed; 1133 else 1134 return this.dropNotAllowed; 1135 }, 1136 // what to do when user drops a node here 1137 notifyDrop:function (dd, e, node) { 1138 e.preventDefault(); 1139 e.stopEvent(); 1140 if (e.target.id != this._domRef.id) { 1141 var nodeEl = Ext.fly(e.target).parent('table'); 1142 if (nodeEl.id != this._domRef.id) { 1143 return false; 1144 } 1145 } 1146 for (var i=0; i < node.nodes.length; i++) { 1147 if (node.nodes[i].contributionId === this.contributionId) { 1148 return false; 1149 } 1150 } 1151 if (this.dropConvertToTypes.length == 1) { 1152 this.moveContribution(node, this.dropConvertToTypes[0]); 1153 } else { 1154 actionCenterUtility.choiceDialog(this.dropConvertToTypes, 'Select the type to convert to', this.contributionId+'selectType',node, this, this.moveContribution); 1155 } 1156 return true; 1157 }, // eo function notifyDrop 1158 moveContribution: function (node, type) { 1159 for (var i=0; i < node.nodes.length; i++) { 1160 actionCenterAPI.moveContribution2(node.nodes[i].contributionId, 1161 node.nodes[i].parentNode.contributionId, this.contributionId, 1162 'childof', null, null, type, node.nodes[i].addChannelRelationshipType); 1163 } 1164 } 1165 }); 1166 } 1167 }, 1168 addSubcomponentEl : function () { 1169 if (!this.subcomponentel) { 1170 this.subCompentTagId = Ext.id(); 1171 var lt = '<'; 1172 var gt = '>'; 1173 this.newInfoMarker = "<img style='text-align: center; display: float; width: 3px;' src='" + Ext.BLANK_IMAGE_URL + "' class='x-tree-infomarker'/>"; 1174 var subcomponentTag = "<table id=" + this.subCompentTagId + ">" 1175 + "<tr valign='center'>" 1176 + "<td width='3px' align='left'>" + this.newInfoMarker + "</td>" 1177 + "<td>" 1178 + "<img class='x-tree-trigger-icon' style='text-align: center; display: float' src='" + this.icon + "'/>"; 1179 + "</td>" 1180 + "</tr>" 1181 + "</table>"; 1182 this.subcomponentel = this.el.insertHtml('afterBegin',subcomponentTag,true); 1183 this.triggerImg = Ext.get(this.subCompentTagId); 1184 } 1185 }, 1186 removeSubcomponentEl : function () { 1187 if (this.subcomponentel) { 1188 this.subcomponentel.remove(); 1189 delete this.subcomponentel; 1190 this.subcomponentel = null; 1191 } 1192 while(this.el.dom.children.length > 0) { 1193 Ext.fly(this.el.dom.children[0]).remove(); 1194 } 1195 }, 1196 updateCounter : function () { 1197 var currentCount = this.contributionChildCounter.count; 1198 var currentNewCount = this.contributionChildCounter.newCount; 1199 var quickTip = Ext.QuickTips.getQuickTip(); 1200 var target = quickTip.targets[Ext.id(this.triggerIcon)]; 1201 target.text = this.getTipText(currentCount, currentNewCount); 1202 // set the appropriate trigger image 1203 if (currentCount > 0) { 1204 if (!this.hasChildren) { 1205 this.icon = this.filledIcon; 1206 this.triggerIcon.dom.src = this.icon; 1207 this.hasChildren = true; 1208 } 1209 } else if (this.hasChildren) { 1210 this.icon = this.emptyIcon; 1211 this.triggerIcon.dom.src = this.icon; 1212 this.hasChildren = false; 1213 } 1214 // set/remove new infomarker 1215 if (this.newInfoMarkerImg.hasClass('x-tree-infomarker-on') && currentNewCount === 0) { 1216 this.newInfoMarkerImg.removeClass('x-tree-infomarker-on'); 1217 } else if (!this.newInfoMarkerImg.hasClass('x-tree-infomarker-on') && currentNewCount > 0) { 1218 this.newInfoMarkerImg.addClass('x-tree-infomarker-on'); 1219 } 1220 }, 1221 onDblClick: function (e) { 1222 e.stopEvent(); 1223 }, 1224 onRightClick: function (e) { 1225 e.stopEvent(); 1226 }, 1227 onClick: function (e) { 1228 e.stopEvent(); 1229 this.launchSubCompWindow(); 1230 }, 1231 onMouseOver : function (e) { 1232 if (!this.disabled) { 1233 var internal = e.within(this.el, true); 1234 if (!internal) { 1235 if (this.triggerIcon) { 1236 this.triggerIcon.addClass('x-tree-trigger-icon-over'); 1237 } 1238 this.fireEvent('mouseover', this, e); 1239 } 1240 } 1241 }, 1242 // private 1243 onMouseOut : function (e) { 1244 if (this.triggerIcon ) { 1245 if (!this.triggerIcon.getRegion() || !this.triggerIcon.getRegion().contains(e.getPoint())) { 1246 this.triggerIcon.removeClass('x-tree-trigger-icon-over'); 1247 } 1248 } 1249 }, 1250 // private 1251 onMouseDown : function (e) { 1252 if (!this.disabled && e.button === 0) { 1253 if (this.triggerIcon) { 1254 this.triggerIcon.addClass('x-tree-trigger-icon-down'); 1255 } 1256 } 1257 }, 1258 // private 1259 onMouseUp : function (e) { 1260 if (this.triggerIcon) { 1261 this.triggerIcon.removeClass('x-tree-trigger-icon-down'); 1262 } 1263 }, 1264 launchSubCompWindow: function () { 1265 if (this.contribution.getPropertyValue('activeContributionMarker') === 'Y') { 1266 this.treegrid.selModel.activateNode(this.row); 1267 } 1268 this.renderer.renderComponent(this.superiorContributionId, this.treegrid); 1269 }, 1270 beforeDestroy : function () { 1271 if (this.actionCenterListener) { 1272 this.actionCenterListener.destroy(); 1273 } 1274 this.removeSubcomponentEl(); 1275 } 1276 }); 1277 actioncenter.tgrCellReg('acoutlinersubcomponentcell', Ext.ux.tree.ACOutlinerSubcomponentCell); 1278 1279 // Begin AC.pss.Component definition /////////////////////////////////////////////////////////////////////////////////// 1280 AC.pss.Component = function(superiorContribution, renderer, subComponentRenderers, target) { 1281 var component = renderer.getComponentConfiguration(); 1282 var componentId = component.getId(); 1283 var populationRulesUtil = new AC.data.PopulationRulesParser(component._msg.populationRules); 1284 var superiorContributionId = superiorContribution.getId(); 1285 var collapseUnspecifiedIcon = false; 1286 var lines = component.getPropertyValue("lines") === 'Y' ? true : false; 1287 var lineNumberEnable = component.getPropertyValue("lineNumbering") === 'Y' ? true : false; 1288 var openInputOnStartup = component.getPropertyValue("openInputOnStartup") === 'Y' ? true : false; 1289 var isHeaderVisible = component.getPropertyValue("isHeaderVisible") === 'Y' ? true : false; 1290 var contributionIconWidth = component.getPropertyValue("contributionIconWidth"); 1291 var contributionIconHeight = component.getPropertyValue("contributionIconHeight"); 1292 1293 //##################################### begin Header panel assembly ################################################ 1294 var headerLabel = new Ext.form.Label ({ 1295 id: 'headerLabel' + acGlobalDelimiter + componentId + superiorContributionId, 1296 staticTitle: true, 1297 superiorConId: superiorContributionId, 1298 contributionChildCounter: null, 1299 style: "color: " + component.getPropertyValue("headerTitleColor") 1300 + "; font-size: " + component.getPropertyValue("headerTitleFontSize") 1301 + "; font-family: " + component.getPropertyValue("headerTitleFont") 1302 + "; font-weight: bold; position: absolute; top: 4px; left: 4px;", 1303 onRender : function (ct, position) { 1304 var headerFormat = component.getPropertyValue("headerFormat"); 1305 if (headerFormat === 'customContent') { 1306 this.headerTitle = component.getPropertyValue("headerTitle"); 1307 this.text = component.getPropertyValue("headerTitle"); 1308 } 1309 else if (headerFormat === 'parentContributionTextWithoutFIBU') { 1310 if (renderer.launchPoint) { 1311 this.staticTitle = false; 1312 this.launchPoint = renderer.launchPoint; 1313 var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId); 1314 this.subscribeToUpdates(initHeaderObj.node); 1315 this.headerTitle = initHeaderObj.text; 1316 this.html = this.buildLabelHtml(initHeaderObj, false); 1317 } else { 1318 this.headerTitle = component.getPropertyValue("headerTitle"); 1319 this.text = component.getPropertyValue("headerTitle"); 1320 } 1321 } 1322 else if (headerFormat === 'parentContributionTextWithFIBU') { 1323 if (renderer.launchPoint) { 1324 this.staticTitle = false; 1325 this.launchPoint = renderer.launchPoint; 1326 var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId); 1327 this.subscribeToUpdates(initHeaderObj.node); 1328 this.headerTitle = initHeaderObj.text; 1329 this.html = this.buildLabelHtml(initHeaderObj, true); 1330 this.ownerCt.body.setStyle('background', ''); 1331 this.ownerCt.body.replaceClass("x-outliner-header", initHeaderObj.cls); 1332 } else { 1333 this.headerTitle = component.getPropertyValue("headerTitle"); 1334 this.text = component.getPropertyValue("headerTitle"); 1335 } 1336 } 1337 Ext.form.Label.prototype.onRender.apply(this, arguments); 1338 }, 1339 subscribeToUpdates: function(target, isReload) { 1340 if (isReload) { 1341 this.clearMons(); 1342 } 1343 this.mon(target, 'counterchange', this.updateLabel, this); 1344 this.mon(target, 'textchange', this.updateLabel, this); 1345 this.mon(target, 'iconchange', this.updateLabel, this); 1346 this.mon(target, 'nodedestroy', this.updateLabel, this); 1347 }, 1348 updateLabel : function (isReload) { 1349 var labelText = this.headerTitle + "<sup>" + " (" + this.contributionChildCounter.count + "/" + this.contributionChildCounter.newCount + ")" + "</sup>"; 1350 if (this.staticTitle) { 1351 this.setText(labelText, false); 1352 } else { 1353 var initHeaderObj; 1354 if (isReload === true) { 1355 initHeaderObj = { 1356 'icon' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', 1357 'text' : '', 1358 'cls' : '', 1359 'counter': '', 1360 'node' : '' 1361 }; 1362 } else { 1363 initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId); 1364 this.headerTitle = initHeaderObj.text; 1365 labelText = this.headerTitle + "<sup>" + " (" + this.contributionChildCounter.count + "/" + this.contributionChildCounter.newCount + ")" + "</sup>"; 1366 } 1367 1368 var newHtml; 1369 if ('parentContributionTextWithoutFIBU' === component.getPropertyValue("headerFormat")) { 1370 newHtml = this.buildLabelHtml(initHeaderObj, false); 1371 } else if ('parentContributionTextWithFIBU' === component.getPropertyValue("headerFormat")) { 1372 newHtml = this.buildLabelHtml(initHeaderObj, true); 1373 } 1374 this.setText(newHtml, false); 1375 } 1376 }, 1377 buildLabelHtml: function (initHeaderObj, useParentFIBU) { 1378 var newHtml = 1379 "<table width='100%' style='white-space: normal; " + (useParentFIBU ? "" : this.initialConfig.style) + "'>" 1380 + "<tbody><tr>" 1381 + "<td valign='top'>" 1382 + "<img height='" + (initHeaderObj.iconHeight || "18") + "px' " 1383 + "width='" + (initHeaderObj.iconWidth || "16") + "px' " 1384 + "unselectable='on' class='x-tree-node-icon x-tree-node-inline-icon' style='vertical-align: middle;" 1385 + (initHeaderObj.icon === undefined ? " display:none;" : "") + "' src='" + initHeaderObj.icon + "'>" 1386 + "<span class='x-treegrid-counter " + (useParentFIBU ? initHeaderObj.cls + "'" : "'") + ">" + initHeaderObj.counter + "</span>" 1387 + "</td>" 1388 + "<td width='100%'>" 1389 + "<span" + (useParentFIBU ? " class='" + initHeaderObj.cls + "'" : "") + ">" + this.headerTitle + "</span>" 1390 + "</td>" 1391 + "</tr></tbody>" 1392 + "</table>"; 1393 return newHtml; 1394 }, 1395 reload: function (newSuperiorConId) { 1396 this.superiorConId = newSuperiorConId; 1397 this.launchPoint = renderer.launchPoint; 1398 var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId); 1399 this.subscribeToUpdates(initHeaderObj.node, true); 1400 this.contributionChildCounter = new AC.data.ContributionChildCounter(this.superiorConId, this.contributionChildCounter._populationRulesUtil, this, this.updateLabel); 1401 this.updateLabel(); 1402 } 1403 }); 1404 1405 var backgroundColor = new Ext.Template('background: -moz-linear-gradient({start}, {stop});').apply({ 1406 start: component.getPropertyValue("headerPanelColorStart"), 1407 stop: component.getPropertyValue("headerPanelColorStop") 1408 }); 1409 var headerPanelHeight = parseInt(component.getPropertyValue("headerPanelHeight")); 1410 if ('percent' === component.getPropertyValue("headerPanelHeightUnit")) { 1411 headerPanelHeight += '%'; 1412 } 1413 1414 var headerPanel = new Ext.Panel({ // this panel is used to present the header 1415 id: 'header' + acGlobalDelimiter + componentId + superiorContributionId, 1416 region: 'north', 1417 title: 'Header', 1418 height: headerPanelHeight, 1419 header: false, 1420 bodyCssClass: 'x-outliner-header', 1421 bodyStyle: backgroundColor, 1422 margins: '2 2 1 2', 1423 autoScroll: true, 1424 items: [headerLabel] 1425 }); 1426 //##################################### end Header panel assembly ################################################## 1427 1428 //##################################### begin outliner/treegrid panel assembly ######################### 1429 var outlinerPanel = 1430 new Ext.Panel({ 1431 xtype: 'panel', 1432 header: false, 1433 layout: 'fit', 1434 id: 'outlinerPanel' + componentId + superiorContributionId, 1435 margins: '1 2 1 2', 1436 bodyStyle: 'border-bottom-width: 0px; -moz-border-radius-bottomleft: 0px; -moz-border-radius-bottomright: 0px; background-color: white; padding-top: 4px;', 1437 region: 'center', 1438 split: true, 1439 minWidth: 100, 1440 maxWidth: 350, 1441 hideBorders: true, 1442 width: 200, 1443 bbar: [ 1444 {xtype:'tbfill'}, 1445 {xtype: 'button', 1446 id: 'editbutton' + acGlobalDelimiter + componentId + superiorContributionId, 1447 tooltip: { 1448 text: 'Edit Contribution', 1449 anchor: 'right', 1450 trackMouse: true}, 1451 scale: 'small', 1452 width: 22, 1453 height: 16, 1454 icon: 'images/icn_edit_gray_16x16.png' 1455 }], 1456 populationRules: populationRulesUtil, 1457 subComponentRenderers: subComponentRenderers, 1458 buildBaseTreeNode : function () { 1459 if (component.getPropertyValue("superiorContributionOrder")) { 1460 this.order = component.getPropertyValue("superiorContributionOrder"); 1461 } else { 1462 this.order = superiorContribution.getPropertyValue("AC_Order"); 1463 } 1464 if (isHeaderVisible) { 1465 var headerLabel = this.ownerCt.findById('headerLabel' + acGlobalDelimiter + componentId + superiorContributionId); 1466 headerLabel.contributionChildCounter = new AC.data.ContributionChildCounter(superiorContributionId, this.populationRules, headerLabel, headerLabel.updateLabel); 1467 } 1468 this.ownerCt.contributionId = superiorContributionId; // for the scenarios, where a contribution is added but nothing is anchored 1469 this.createTreeGrid(superiorContributionId); 1470 this.add(this.maintreegrid); 1471 this.doLayout(); 1472 inputPanel.mon(inputPanel.getFormItem('place'), 'change', inputPanel.handleLocationChangeEvent, inputPanel); 1473 inputPanel.mon(inputPanel.getFormItem('type'), 'select', inputPanel.handleTypeChangeEvent, inputPanel); 1474 inputPanel.mon(inputPanel.getFormItem('name'), 'focus', textArea.handleOnFocus, textArea); 1475 inputPanel.mon(inputPanel.getFormItem('name'), 'blur', textArea.handleOnBlur, textArea); 1476 inputPanel.mon(inputPanel.getFormItem('collapsebutton'), 'click', inputPanel.collapse, inputPanel); 1477 inputPanel.mon(tagBar.getButton('sendbutton'), 'click', inputPanel.addContribution, inputPanel); 1478 inputPanel.mon(tagBar.getButton('updatebutton'), 'click', inputPanel.updateContribution, inputPanel); 1479 inputPanel.mon(tagBar.getButton('cancelbutton'), 'click', inputPanel.cancelEditContribution, inputPanel); 1480 inputPanel.mon(outlinerPanel.getButton('editbutton'), 'click', inputPanel.initiateEdit, inputPanel); 1481 }, 1482 reload: function (newSuperiorContributionId) { 1483 this.maintreegrid.destroy(); 1484 if (isHeaderVisible) { 1485 var headerLabel = this.ownerCt.findById('headerLabel' + acGlobalDelimiter + componentId + superiorContributionId); 1486 headerLabel.reload(newSuperiorContributionId); 1487 } 1488 this.ownerCt.contributionId = newSuperiorContributionId; 1489 this.createTreeGrid(newSuperiorContributionId); 1490 this.add(this.maintreegrid); 1491 this.doLayout(false, true); 1492 inputPanel.anchorNode = this.maintreegrid.selModel.anchoredNode; 1493 }, 1494 createTreeGrid : function (rootContributionId) { 1495 var outlinerExplorerRoot = new actioncenter.outlinerExplorerGridNode({ 1496 text: 'rootnode', 1497 leaf: false, 1498 validChildTypes: null, 1499 contributionId: rootContributionId, 1500 populationRules: this.populationRules, 1501 order: this.order, 1502 iconWidth: contributionIconWidth, 1503 iconHeight: contributionIconHeight, 1504 componentId: componentId, 1505 listenProfiles: [{channelId : rootContributionId, 1506 childType : this.populationRules.getAllChildTypeList(), 1507 updateSelf : true, 1508 properties : [{key: 'AC_Order', method: 'editOrder'}] 1509 }], 1510 expanded: true, 1511 treePanelId: 'outlinerPanel' + componentId + superiorContributionId 1512 }); 1513 1514 var crFactory = new AC.tree.grid.CellObjectFactory(); 1515 var allTypes = this.populationRules.getAllTypesList(); 1516 for (var i = 0; i < allTypes.length; i++) { 1517 crFactory.addWidget(['AC_Component', allTypes[i]], 'acoutlinersubcomponentcell'); 1518 } 1519 var objectManager = new AC.tree.grid.WidgetManager(crFactory); 1520 var columnFactory = [{ 1521 header: 'Name', 1522 dataIndex: 'name', 1523 headerType: 'constant', 1524 columnContent: 'text', 1525 align: 'center', 1526 //width: '100%', 1527 autoExpand: true, 1528 type: 'AC_User_Name', 1529 displayIcon: false, 1530 displayText: true, 1531 locked: true 1532 }]; 1533 for (var i = 0; i < this.subComponentRenderers.length; i++) { 1534 var subComponentRenderer = this.subComponentRenderers[i]; 1535 var emptyGUID = subComponentRenderer.getComponentConfiguration().getPropertyValue("emptyIcon"); 1536 var fullGUID = subComponentRenderer.getComponentConfiguration().getPropertyValue("filledIcon"); 1537 var showColumn = emptyGUID && emptyGUID.length > 0 || fullGUID && fullGUID.length > 0; 1538 columnFactory.push({ 1539 header: subComponentRenderer.getComponentConfiguration().getPropertyValue('name'), 1540 dataIndex: subComponentRenderer.getComponentConfiguration().getId(), 1541 align: 'center', 1542 width: showColumn ? 26 : 0, 1543 renderer: subComponentRenderer, 1544 type: 'AC_Component', 1545 headerType: 'constant', 1546 columnContent: 'object', 1547 childType: 'AC_Component', 1548 displayIcon: false, 1549 displayText: true 1550 }); 1551 } 1552 this.maintreegrid = new Ext.ux.tree.ACTreeGrid({ 1553 tableclass: '.x-treegrid-root-table-no-border', 1554 projectType: "AC_Library_Type", 1555 style: 'border:none;', 1556 //bodyStyle: 'background-color: white;', 1557 bodyCssClass: 'AC_'+ componentId, 1558 componentId: componentId, 1559 id: 'outlinerExplorer' + componentId + superiorContributionId, 1560 animate: true, 1561 vScrollBarVisible: true, 1562 containerScroll: true, 1563 rootVisible: false, 1564 lines: this.ownerCt.lines, 1565 root: outlinerExplorerRoot, 1566 objectManager: objectManager, 1567 cellObjectReference: null, 1568 enableDD: true, 1569 ddata: 'yeah', 1570 allowDrop: true, 1571 enableSort: false, 1572 enableHdMenu: false, 1573 enableColumnHide: false, 1574 hideHeaders: true, 1575 ownerPanel: this, 1576 columnFactory: columnFactory, 1577 contextMenu: [{paste: true}], 1578 keys: [ 1579 { 1580 key: 'c', 1581 ctrl: true, 1582 scope: this, 1583 stopEvent:true, 1584 fn: function (key, event) { 1585 this.maintreegrid.copyToClipboard(); 1586 } 1587 }, { 1588 key: 'x', 1589 ctrl: true, 1590 scope: this, 1591 stopEvent:true, 1592 fn: function (key, event) { 1593 this.maintreegrid.cutToClipboard(); 1594 } 1595 }, { 1596 key: 'v', 1597 ctrl: true, 1598 scope: this, 1599 stopEvent:true, 1600 fn: function (key, event) { 1601 this.maintreegrid.delegatePaste(); 1602 } 1603 }, { 1604 key: 46, 1605 scope: this, 1606 stopEvent:true, 1607 fn: function (key, event) { 1608 var selectedNodes = this.maintreegrid.getSelectionModel().getSelectedNodes(); 1609 if (selectedNodes && selectedNodes instanceof Array && selectedNodes.length > 0) { 1610 Ext.Msg.show({ 1611 title: 'Delete', 1612 msg: 'Are you sure you want to delete the selected item(s)?', 1613 buttons: Ext.Msg.YESNO, 1614 icon: Ext.MessageBox.QUESTION, 1615 fn: function (btn, text) { 1616 if (btn === 'yes') { 1617 actionCenterAPI.moveContributionToRecycleBin(selectedNodes); 1618 } 1619 } 1620 }); 1621 } 1622 } 1623 }, { 1624 key: 13, 1625 scope: this, 1626 fn: function (key, event) { 1627 var anchoredNode = this.maintreegrid.getSelectionModel().getAnchoredNode(); 1628 if (anchoredNode) { 1629 anchoredNode.handleSubComponentTrigger('enter'); 1630 } 1631 }, 1632 stopEvent: true 1633 }], 1634 onRenderedComponentDestroy: function () { 1635 this.getSelectionModel().getAnchoredNode().ui.anchor.focus(); 1636 }, 1637 getRootContributionId: function () { 1638 return this.root.contributionId; 1639 }, 1640 getSubComponentHeaderInfo: function (row) { 1641 var node = this.root.findChild('contributionId', row, true); 1642 var subComponentHeaderInfo = { 1643 'icon' : node.ui.iconNode.src, 1644 'iconHeight': node.ui.iconNode.height, 1645 'iconWidth' : node.ui.iconNode.width, 1646 'text' : node.attributes.name, 1647 'cls' : node.attributes.cls, 1648 'counter' : node.ui.counter, 1649 'node' : node 1650 }; 1651 return subComponentHeaderInfo; 1652 } 1653 }); 1654 this.maintreegrid.enableInfoMarker = true; 1655 this.maintreegrid.enableNewInfoMarker = true; 1656 this.maintreegrid.borderWidth = 0; 1657 this.maintreegrid.collapseUnspecifiedIcon = this.ownerCt.collapseUnspecifiedIcon; 1658 this.maintreegrid.enableLineNumbering = this.ownerCt.lineNumbering; 1659 inputPanel.mon(this.maintreegrid.getSelectionModel(), 'anchorchange', inputPanel.handleAnchorChange, inputPanel); 1660 inputPanel.mon(this.maintreegrid.getSelectionModel(), 'iyo', textArea.calcLocaterArrow, textArea); 1661 this.maintreegrid.mon(this.maintreegrid, 'aftertreeload', this.afterTreeLoad, this); 1662 outlinerExplorerRoot.subscribeAllChannels(); 1663 return this.maintreegrid; 1664 }, 1665 getButton: function (itemname) { 1666 var button = this.bottomToolbar.items.map[itemname + acGlobalDelimiter + componentId + superiorContributionId]; 1667 return button; 1668 }, 1669 afterTreeLoad : function () { 1670 if (this.maintreegrid.enableDefaultSort) { 1671 // default sort 1672 if (this.maintreegrid.treeGridSorter) { 1673 this.maintreegrid.root.sort(this.maintreegrid.treeGridSorter.defaultSortFn); 1674 } 1675 } else { 1676 // this will sort the child nodes of the root node according to the AC_Order property 1677 actionCenterUtility.reorder(this.maintreegrid.root); 1678 } 1679 var sm = this.maintreegrid.getSelectionModel(); 1680 // anchor and select the first new contribution or the first top-level contribution 1681 var firstNewCon = this.maintreegrid.root.findChildBy( 1682 function () { 1683 return (this.isNewContribution && this.isNewContribution === true); 1684 }, null, true); // depth-first search 1685 if (firstNewCon && this.maintreegrid.enableNewInfoMarker) { 1686 sm.anchorNode(firstNewCon, true); 1687 sm.select(firstNewCon); 1688 } else { 1689 if (this.maintreegrid.root.childNodes && this.maintreegrid.root.childNodes.length > 0) { 1690 sm.anchorNode(this.maintreegrid.root.childNodes[0], true); 1691 sm.select(this.maintreegrid.root.childNodes[0]); 1692 } 1693 } 1694 if (!inputPanel.collapsed) { 1695 inputPanel.onBodyResize(inputPanel.getWidth(), inputPanel.getHeight()); 1696 sm.clearSelections(); 1697 textArea.focus(false, true); 1698 } 1699 // trigger child of the pc shell, if there exists any 1700 for (var i = 0; i < this.subComponentRenderers.length; i++) { 1701 if (this.subComponentRenderers[i].type && 1702 this.subComponentRenderers[i].type === 'pcChildComponentRenderer') { 1703 var t = this.maintreegrid; 1704 var anchoredNode = t.selModel.anchoredNode; 1705 var childTriggerCell = anchoredNode.getCellObject(t, anchoredNode, t.columns[i + 1]); 1706 if (childTriggerCell) { 1707 childTriggerCell.launchSubCompWindow(); 1708 } 1709 break; 1710 } 1711 } 1712 tagBar.getButton('sendbutton').enable(); 1713 }, 1714 afterRender : function () { 1715 Ext.Panel.superclass.afterRender.call(this); 1716 if (!inputPanel.collapsed) { 1717 textArea.focus(true, 1000); 1718 } 1719 this.inputPanel = inputPanel; 1720 } 1721 }); 1722 //##################################### end outliner/treegrid panel assembly ########################### 1723 1724 1725 //##################################### begin input panel assembly ##################################### 1726 // build the "place" radio group and the input panel collapse trigger row 1727 var placeRadioGroup = new Ext.form.RadioGroup({ 1728 id: 'place' + acGlobalDelimiter + componentId + superiorContributionId, 1729 width: 230, 1730 fieldLabel: 'PLACE', 1731 columns: [70, 62, 57, 40], 1732 items: [{boxLabel: 'Append', id: 'append' + acGlobalDelimiter + componentId + superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Append', checked: true}, 1733 {boxLabel: 'Before', id: 'before' + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Before'}, 1734 {boxLabel: 'After', id: 'after' + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'After'}, 1735 {boxLabel: 'Sub', id: 'sub' + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Sub'}] 1736 }); 1737 var placePanel = new Ext.Panel({ 1738 layout: 'hbox', 1739 header: false, 1740 margins: '0 0 2 0', 1741 style: 'padding-left: 4px; padding-right: 4px', 1742 items: [ 1743 { xtype: 'panel', 1744 layout: 'form', 1745 items: [placeRadioGroup] 1746 }, { 1747 xtype: 'panel', 1748 layout: 'fit', 1749 flex: 1 1750 }, { 1751 xtype: 'iconbutton', 1752 id: 'collapsebutton' + acGlobalDelimiter + componentId+ superiorContributionId, 1753 scale: 'small', 1754 iconAlign: 'right', 1755 width: 16, 1756 icon: 'images/btn_showhide.png', 1757 tooltip: 'Hide the input panel' 1758 } 1759 ], 1760 id: 'placePanel' + acGlobalDelimiter + componentId+ superiorContributionId, 1761 afterRender: function () { 1762 Ext.Panel.superclass.afterRender.call(this); 1763 this.boxReady = true; 1764 this.setSize(this.width, this.height); 1765 if (this.x || this.y) { 1766 this.setPosition(this.x, this.y); 1767 } else if (this.pageX || this.pageY) { 1768 this.setPagePosition(this.pageX, this.pageY); 1769 } 1770 1771 if (this.layout) { 1772 if (typeof this.layout == 'string') { 1773 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); 1774 } 1775 this.setLayout(this.layout); 1776 1777 if (this.activeItem !== undefined) { 1778 var item = this.activeItem; 1779 delete this.activeItem; 1780 this.layout.setActiveItem(item); 1781 return; 1782 } 1783 } 1784 this.ownerCt.doLayout(); 1785 1786 // this block of code puts the underline below the radio group 1787 var radioGroupItem = inputPanel.getFormItem('place'); 1788 var formitemwrappernode = radioGroupItem.el.dom.parentNode.parentNode; 1789 formitemwrappernode.style.cssText="padding-bottom:-1px; border-bottom-style:solid; border-bottom-width:1px; border-color: #C4C4C4;"; 1790 } 1791 }); 1792 1793 // build the "type" combo box ////////////////////////////////////////////////////////////////////////// 1794 // create an ArrayStore that contains all of the fields (displaytext, value) for the combobox 1795 var dataList = []; 1796 var subordinates = populationRulesUtil.getSubordinatesOfType('AC_ComponentSuperior'); 1797 var defaultValue = ''; 1798 var defaultIcon = null; 1799 var defaultPrompt = ''; 1800 var subordinate; 1801 for (var i = 0; i < subordinates.length; i++) { 1802 subordinate = subordinates[i]; 1803 dataList.push([ 1804 subordinate.subordinate_type, 1805 subordinate.subordinate_type, 1806 AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16) 1807 ]); 1808 if (i === 0) { 1809 defaultValue = subordinate.subordinate_type; 1810 defaultIcon = AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16); 1811 defaultPrompt = subordinate.inputPrompt; 1812 } 1813 } 1814 var store = new Ext.data.ArrayStore({ 1815 id: 0, 1816 fields: ['selectValue', 'displayText', 'iconURL'], 1817 data: dataList 1818 }); 1819 1820 var typeCombo = new Ext.ux.form.IconCombo({ 1821 triggerAction: "all", 1822 store: store, 1823 mode: 'local', 1824 editable: false, 1825 style: 'border-right-width: 0px; background-image: none;', 1826 name: 'type' + acGlobalDelimiter + componentId, 1827 id: 'type' + acGlobalDelimiter + componentId+ superiorContributionId, 1828 valueField: 'selectValue', 1829 displayField: 'displayText', 1830 iconField: 'iconURL', 1831 value: defaultValue, 1832 lazyRender: true, 1833 width: 132, 1834 hideTrigger: false, 1835 minListWidth: 115, 1836 fieldLabel: 'TYPE', 1837 hideParent: true, 1838 hideMode: 'offsets', 1839 triggerClass: 'x-form-orange-trigger' 1840 }); 1841 // cause the drop down selection item list to be as wide as the widest item 1842 typeCombo.on("expand", function () { 1843 typeCombo.list.setStyle("width", "auto"); 1844 typeCombo.innerList.setStyle("width", "auto"); 1845 }, {single: true}); 1846 1847 var typePanel = new Ext.Panel({ 1848 layout: 'form', 1849 header: false, 1850 labelWidth: 42, 1851 margins: '0 0 2 0', 1852 style: 'padding-left: 4px; padding-right: 4px; padding-top: 2px;', 1853 items: [typeCombo], 1854 id: 'typePanel' + acGlobalDelimiter + componentId+ superiorContributionId, 1855 afterRender: function () { 1856 Ext.Panel.superclass.afterRender.call(this); 1857 if (!populationRulesUtil.hasAmbiguities()) { 1858 this.hide(); 1859 } 1860 } 1861 }); 1862 1863 // build the "contributionEntry" entry including the text area and info/add tags bar//////////////////// 1864 var textArea = new Ext.form.TextArea({ 1865 id: 'name' + acGlobalDelimiter + componentId+ superiorContributionId, 1866 value: defaultPrompt, 1867 defaultPrompt: defaultPrompt, 1868 allowBlank: false, 1869 style: 'border-color: white; background-image: none; overflow-y: auto;', 1870 columnWidth: 1.0, 1871 selectOnFocus: true, 1872 enableKeyEvents: true, 1873 beginEdit: false,//a new property used to indicate the editing starts in the text area 1874 outlinerPanel: outlinerPanel, 1875 cursorStart: 0, 1876 cursorEnd: 0, 1877 afterRender: function () { 1878 Ext.form.TextArea.superclass.afterRender.call(this); 1879 this.el.on({ 1880 scope: this, 1881 mouseup: this.onMouseUp, 1882 mousedown: this.onMouseDown 1883 }); 1884 this.mon(this.ownerCt.body,'click',this.ownerCt.onClick,this.ownerCt); 1885 this.mon(this.ownerCt,'bodyresize',this.onOwnerCtResize,this); 1886 this.addClass('x-form-textarea-prompt'); 1887 }, 1888 1889 onOwnerCtResize: function(){ 1890 this.setHeight(this.ownerCt.getHeight()-8); 1891 }, 1892 1893 onMouseDown: function(e) { 1894 if (!this.isDirty()) { 1895 this.selectText(0, 0); 1896 } 1897 }, 1898 onMouseUp: function(e) { 1899 if (!this.isDirty()) { 1900 this.selectText(0, 0); 1901 } 1902 }, 1903 handleOnFocus: function (e) { 1904 if (this.isDirty()) { 1905 this.selectText(this.cursorStart, this.cursorEnd); 1906 this.addClass('x-form-textarea-on-focus'); 1907 } else { 1908 this.selectText(0, 0); 1909 } 1910 this.calcLocaterArrow(); 1911 }, 1912 1913 calcLocaterArrow: function () { 1914 //get tree ref for arrow marker 1915 var curranchor = outlinerPanel.maintreegrid.getSelectionModel().getAnchoredNode(); 1916 var horiznode; 1917 var placement = this.ownerCt.ownerCt.ownerCt.ownerCt.getFormItem('place').getValue().inputValue; 1918 if (placement === 'Sub') { 1919 placement = 'append'; 1920 horiznode = curranchor; 1921 if (curranchor) { 1922 if (curranchor.lastChild) { 1923 curranchor = curranchor.lastChild; 1924 } 1925 } 1926 } else if (placement === 'Append') { 1927 placement = 'below'; 1928 horiznode = curranchor; 1929 if (curranchor) { 1930 curranchor = curranchor.parentNode.lastChild; 1931 while (curranchor.isExpanded() && curranchor.hasChildNodes()) { 1932 curranchor = curranchor.lastChild; 1933 } 1934 } 1935 } else if (placement === 'After') { 1936 placement = 'below'; 1937 horiznode = curranchor; 1938 if (curranchor) { 1939 while (curranchor.isExpanded() && curranchor.hasChildNodes()) { 1940 curranchor = curranchor.lastChild; 1941 } 1942 } 1943 } else { 1944 placement = 'above'; 1945 horiznode = curranchor; 1946 } 1947 outlinerPanel.maintreegrid.placeLocaterArrow(curranchor, horiznode, placement); 1948 }, 1949 handleOnBlur: function (txtArea) { 1950 if (this.getValue() === '') { 1951 this.cursorStart = 0; 1952 this.cursorEnd = 0; 1953 this.setValue(this.defaultPrompt); 1954 this.addClass('x-form-textarea-prompt'); 1955 } else { 1956 if (Ext.isIE) { 1957 var bookmark = document.selection.createRange().getBookmark(); 1958 var selection = this.el.dom.createTextRange(); 1959 selection.moveToBookmark(bookmark); 1960 1961 var before = this.el.dom.createTextRange(); 1962 before.collapse(true); 1963 before.setEndPoint("EndToStart", selection); 1964 1965 var selLength = selection.text.length; 1966 1967 this.cursorStart = before.text.length; 1968 this.cursorEnd = this.cursorStart + selLength; 1969 } else { 1970 this.cursorStart = this.el.dom.selectionStart; 1971 this.cursorEnd = this.el.dom.selectionEnd; 1972 } 1973 } 1974 this.removeClass('x-form-textarea-on-focus'); 1975 outlinerPanel.maintreegrid.removeLocaterArrow(); 1976 }, 1977 onKeyPress : function(e) { // overrides Ext.form.TextField.onKeyPress 1978 if (!this.isDirty() && (this.getValue() === this.defaultPrompt)) { 1979 this.beginEdit = true; 1980 this.setValue(''); 1981 this.removeClass('x-form-textarea-prompt'); 1982 this.addClass('x-form-textarea-on-focus'); 1983 } 1984 if (e.getKey() === e.F9 && e.charCode !== e.F9 && !tagBar.getButton('sendbutton').hidden) { 1985 inputPanel.addContribution(); 1986 this.removeClass('x-form-textarea-on-focus'); 1987 } 1988 this.fireEvent('keypress', this, e); 1989 }, 1990 processValue: function(value) { // overrides Ext.form.TextField.processValue 1991 if (!this.beginEdit && this.getValue() === '') { 1992 this.removeClass('x-form-textarea-on-focus'); 1993 if (this.defaultPrompt !== ''){ 1994 this.setValue(this.defaultPrompt); 1995 } 1996 this.addClass('x-form-textarea-prompt'); 1997 this.selectText(0, 0); 1998 } 1999 this.beginEdit = false; 2000 return value; 2001 } 2002 }); 2003 2004 var contributionEntry = new Ext.Panel({ 2005 layout: 'column', 2006 header: false, 2007 style: 'background-color:white; padding-top: 4px;', 2008 items: [ 2009 { 2010 xtype: 'label', text: '.', width: 8, style: 'color:white;' 2011 }, { 2012 xtype: 'iconbutton', 2013 id: 'entryicon' + acGlobalDelimiter + componentId+ superiorContributionId, 2014 scale: 'small', 2015 iconAlign: 'right', 2016 width: 16, 2017 icon: defaultIcon 2018 }, { 2019 xtype: 'label', text: '.', width: 5, style: 'color:white;' 2020 }, textArea 2021 ], 2022 onClick:function(e){ 2023 var target = e.getTarget(); 2024 if (target !== textArea.el.dom){ 2025 textArea.handleOnFocus(); 2026 } 2027 } 2028 }); 2029 2030 var tagBar = new Ext.Panel({ 2031 region:'south', 2032 layout: 'column', 2033 header: false, 2034 style: 'padding-bottom: 0px; margin-bottom: 0px;', 2035 height: 29, 2036 getButton: function (itemname) { 2037 var formItem = this.items.map[itemname + acGlobalDelimiter + componentId+ superiorContributionId]; 2038 return formItem; 2039 }, 2040 items: [ 2041 { 2042 xtype: 'styledbutton', 2043 text: 'SEND', 2044 buttonClass: 'small orange standard', 2045 id: 'sendbutton' + acGlobalDelimiter + componentId+ superiorContributionId, 2046 style: 'margin-left: 4px; margin-right: 4px; margin-bottom: 4px', 2047 hideMode: 'offsets', 2048 width: 60 2049 }, { 2050 xtype: 'styledbutton', 2051 id: 'updatebutton' + acGlobalDelimiter + componentId+ superiorContributionId, 2052 buttonClass: 'small orange standard', 2053 style: 'margin-left: 4px; margin-bottom: 4px', 2054 text: 'UPDATE', 2055 hideMode: 'offsets', 2056 hidden: true, 2057 width: 60 2058 }, { 2059 xtype: 'styledbutton', 2060 buttonClass: 'small orange standard', 2061 style: 'margin-left: 4px; margin-right: 4px; margin-bottom: 4px', 2062 id: 'cancelbutton' + acGlobalDelimiter + componentId+ superiorContributionId, 2063 text: 'CANCEL', 2064 hideMode: 'offsets', 2065 hidden: true, 2066 width: 60 2067 } 2068 ] 2069 }); 2070 2071 var inputPanelHeight = parseInt(component.getPropertyValue("inputPanelHeight")); 2072 if ('percent' === component.getPropertyValue("inputPanelHeightUnit")) { 2073 inputPanelHeight += '%'; 2074 } 2075 var inputPanel = 2076 new Ext.Panel({// this panel is used to present the layouts chosen 2077 anchorNode: null, 2078 region: 'south', 2079 height: inputPanelHeight, 2080 minHeight: 100, 2081 margins: '1 2 2 2', 2082 cmargins: '1 2 2 2', 2083 split: true, 2084 collapsible: true, 2085 titleCollapse: true, 2086 floatable: false, 2087 collapsed: !openInputOnStartup, 2088 header: false, 2089 collapsedTitle: component.getPropertyValue("collapsedTitle"), 2090 collapsedTitleColor: component.getPropertyValue("collapsedTitleColor"), 2091 collapsedTitleFontFamily: component.getPropertyValue("collapsedTitleFontFamily"), 2092 collapsedTitleFontSize: component.getPropertyValue("collapsedTitleFontSize"), 2093 collapsedTooltip: component.getPropertyValue("collapsedTitle"), 2094 layout: 'fit', 2095 id: 'inputPanel' + acGlobalDelimiter + componentId+ superiorContributionId, 2096 editMode: false, 2097 contributionarea: contributionEntry, 2098 textarearef: textArea, 2099 renderer: renderer, 2100 items: [{ 2101 xtype: 'form', 2102 frame: true, 2103 labelWidth: 42, 2104 items: [ 2105 placePanel, 2106 typePanel, 2107 { 2108 xtype: 'panel', 2109 id: 'contributionEntrytagBar' + acGlobalDelimiter + componentId+ superiorContributionId, 2110 cls: 'x-panel-body-orange', 2111 width: '99%', 2112 style: 'padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 1px;', 2113 items: [contributionEntry, tagBar] 2114 } 2115 ] 2116 }], 2117 listeners:{ 2118 'afterRender':function(){ 2119 this.mon(this.el,'click',this.onClick,this); 2120 }, 2121 'expand': function(panel){ 2122 var outputPanel = this.ownerCt.outlinerPanel; 2123 var t = outputPanel.maintreegrid; 2124 var sm = t.selModel; 2125 sm.clearSelections(); 2126 this.textarearef.handleOnFocus(); 2127 } 2128 }, 2129 onClick:function(e){ 2130 var outputPanel = this.ownerCt.outlinerPanel; 2131 var t = outputPanel.maintreegrid; 2132 var sm = t.selModel; 2133 sm.clearSelections(); 2134 }, 2135 onBodyResize: function (w, h) { 2136 this.fireEvent('bodyresize', this, w, h); 2137 if (h !== undefined) { 2138 var typePanel = this.getFormItem('typePanel'); 2139 var typePanelHt = 0; 2140 if ((typePanel.rendered && !typePanel.isVisible()) || 2141 (!typePanel.rendered && !populationRulesUtil.hasAmbiguities())) { 2142 typePanelHt = 28; 2143 } 2144 if (placePanel && placePanel.rendered) { 2145 // placePanel is not visible on the first render 2146 placePanel.doLayout(false, true); 2147 } 2148 if (!this.editMode) { 2149 this.contributionarea.setHeight(h - 108 + typePanelHt); 2150 } else { 2151 this.contributionarea.setHeight(h - 77 + typePanelHt); 2152 } 2153 } 2154 }, 2155 2156 getFormItem: function (itemname) { 2157 var formItem = this.findById(itemname + acGlobalDelimiter + componentId+ superiorContributionId); 2158 return formItem; 2159 }, 2160 addContribution : function () { 2161 var inputTxt = this.getFormItem('name').getValue(); 2162 //var matches = inputTxt.match(''+this.getFormItem('name').defaultPrompt+''); 2163 var match = false; 2164 if (inputTxt === this.getFormItem('name').defaultPrompt){ 2165 match = true; 2166 } 2167 if (inputTxt !== '' && !match) { // if the entered text is not the same as the input prompt 2168 var afterContributionId = null; 2169 var beforeContributionId = null; 2170 var superiorContributionId = null; 2171 var superiorContributionType = null; 2172 if (!this.anchorNode) { 2173 superiorContributionId = this.ownerCt.contributionId; 2174 superiorContributionType = 'AC_ComponentSuperior'; 2175 } else { 2176 switch(this.getFormItem('place').getValue().inputValue) { 2177 case 'Append': 2178 superiorContributionId = this.anchorNode.parentNode.contributionId; 2179 superiorContributionType = this.anchorNode.parentNode.type; 2180 break; 2181 case 'Before': 2182 superiorContributionId = this.anchorNode.parentNode.contributionId; 2183 superiorContributionType = this.anchorNode.parentNode.type; 2184 beforeContributionId = this.anchorNode.contributionId; 2185 break; 2186 case 'After': 2187 superiorContributionId = this.anchorNode.parentNode.contributionId; 2188 superiorContributionType = this.anchorNode.parentNode.type; 2189 afterContributionId = this.anchorNode.contributionId; 2190 break; 2191 case 'Sub': 2192 superiorContributionId = this.anchorNode.contributionId; 2193 superiorContributionType = this.anchorNode.type; 2194 break; 2195 } 2196 } 2197 var subordinateContributionType = this.getFormItem('type').getValue(); 2198 var relationshipType = populationRulesUtil.getRelationshipTypeFor(subordinateContributionType, superiorContributionType); 2199 2200 actionCenterAPI.addRelationship(superiorContributionId, null, relationshipType, afterContributionId, 2201 beforeContributionId, subordinateContributionType, {name: inputTxt}, this, this.anchorNewContribution); 2202 } 2203 this.handleTypeChange(true); 2204 renderer.onSend(); 2205 }, 2206 initiateEdit: function () { 2207 if (this.anchorNode) { 2208 this.editContributionId = this.anchorNode.contributionId; 2209 actionCenterAPI.lockContribution(this.editContributionId, this, this.editContribution); 2210 } 2211 }, 2212 editContribution: function (msg) { 2213 var result = actionCenterJSON.getMsgProperty(msg, 'data.result'); 2214 if (result === 'success') { 2215 this.editMode = true; 2216 if (this.collapsed) { 2217 this.expand(false); 2218 } 2219 if (this.textarearef.disabled) { 2220 this.textarearef.setDisabled(false); 2221 } 2222 this.getFormItem('placePanel').hide(); 2223 2224 var typeItem = this.getFormItem('type'); 2225 var subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.parentNode.type); 2226 var isTypePickerEnabled = subordinates.length > 1 || this.anchorNode.attributes.isInvalidType; 2227 if (!isTypePickerEnabled) { 2228 this.getFormItem('typePanel').hide(); 2229 } else if (!this.getFormItem('typePanel').isVisible()) { 2230 this.getFormItem('typePanel').show(); 2231 } 2232 this.onBodyResize(this.getWidth(), this.getHeight()); 2233 2234 var subordinate; 2235 var dataList = []; 2236 for (var i = 0; i < subordinates.length; i++) { 2237 subordinate = subordinates[i]; 2238 dataList.push([ 2239 subordinate.subordinate_type, 2240 subordinate.subordinate_type, 2241 AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16) 2242 ]); 2243 } 2244 if (this.anchorNode.attributes.isInvalidType) { // add the invalid type to the type-picker 2245 var iconId = populationRulesUtil.getRuleProperty(this.anchorNode.type, null, 'normalIcon'); 2246 dataList.push([this.anchorNode.type, this.anchorNode.type, AC.util.StandardIcons.getImageURL(iconId, true, 16)]); 2247 } 2248 var store = new Ext.data.ArrayStore({ 2249 id: 0, 2250 fields: ['selectValue', 'displayText', 'iconURL'], 2251 data: dataList 2252 }); 2253 typeItem.bindStore(store); 2254 typeItem.setValue(this.anchorNode.type); 2255 this.getFormItem('name').setValue(this.anchorNode.attributes.name); 2256 this.getFormItem('name').removeClass('x-form-textarea-prompt'); 2257 var iconURL = this.anchorNode.attributes.icon; 2258 if (iconURL.indexOf("scale=16") === -1) { 2259 iconURL = iconURL + '&' + 'scale=16'; 2260 } 2261 this.getFormItem('entryicon').setIcon(iconURL); 2262 tagBar.getButton('sendbutton').hide(); 2263 tagBar.getButton('updatebutton').show(); 2264 tagBar.getButton('cancelbutton').show(); 2265 this.getFormItem('name').focus(true); 2266 this.ownerCt.items.items[1].getButton('editbutton').disable(); 2267 } 2268 }, 2269 updateContribution: function () { 2270 var contributionProperties = {name: this.getFormItem('name').getValue()}; 2271 var newType = this.getFormItem('type').getValue(); 2272 actionCenterAPI.editContribution(this.editContributionId, contributionProperties, null, null, null, true, newType); 2273 this.editMode = false; 2274 this.cancelEditContribution(); 2275 }, 2276 cancelEditContribution: function () { 2277 if (this.editMode) { 2278 actionCenterAPI.unlockContribution(this.editContributionId); 2279 this.editMode = false; 2280 } 2281 this.editContributionId = null; 2282 this.getFormItem('placePanel').show(); 2283 if (populationRulesUtil.hasAmbiguities()) { 2284 this.getFormItem('typePanel').show(); 2285 } else { 2286 this.getFormItem('typePanel').hide(); 2287 } 2288 this.collapse(false); 2289 tagBar.getButton('updatebutton').hide(); 2290 tagBar.getButton('cancelbutton').hide(); 2291 tagBar.getButton('sendbutton').show(); 2292 this.expand(false); 2293 this.handleTypeChange(true); 2294 this.handleAnchorChange(outlinerPanel.maintreegrid, this.anchorNode); 2295 this.ownerCt.items.items[1].getButton('editbutton').enable(); 2296 }, 2297 handleAnchorChange: function (treeGrid, anchorNode) { 2298 this.anchorNode = anchorNode; 2299 if (this.anchorNode === null) { 2300 return; 2301 } 2302 var locRadioGroup = this.getFormItem('place'); 2303 var previousValue = locRadioGroup.getValue().inputValue; 2304 var allowSiblings = populationRulesUtil.hasSubordinatesOfType(this.anchorNode.parentNode.type); 2305 var allowSub = populationRulesUtil.hasSubordinatesOfType(this.anchorNode.type); 2306 locRadioGroup.items.map['sub' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSub); 2307 locRadioGroup.items.map['sub' + acGlobalDelimiter + componentId+ superiorContributionId].setVisible(allowSub); 2308 locRadioGroup.items.map['append' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings); 2309 locRadioGroup.items.map['before' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings); 2310 locRadioGroup.items.map['after' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings); 2311 var allDisabled = false; 2312 if (!allowSiblings) { 2313 locRadioGroup.setValue('Sub'); 2314 if (locRadioGroup.items.map['sub' + acGlobalDelimiter + componentId+ superiorContributionId].disabled) { 2315 allDisabled = true; 2316 } 2317 } else if (previousValue === 'Sub') { 2318 locRadioGroup.setValue('Append'); 2319 } 2320 this.textarearef.setDisabled(!allowSiblings && !allowSub); 2321 this.handleLocationChange(true); 2322 }, 2323 handleLocationChange: function (keepFocus) { 2324 if (!this.anchorNode || this.editMode) { 2325 this.getFormItem('name').focus(); 2326 return; 2327 } 2328 var placeValue = this.getFormItem('place').getValue().inputValue; 2329 var subordinates = []; 2330 if ("Append" === placeValue || "Before" === placeValue || "After" === placeValue) { 2331 subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.parentNode.type); 2332 } else if ("Sub" === placeValue) { 2333 subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.type); 2334 } 2335 var dataList = []; 2336 var defaultType = ''; 2337 var txtArea = this.getFormItem('name'); 2338 var typeItem = this.getFormItem('type'); 2339 var prevType = typeItem.getValue(); 2340 var prevPrompt = txtArea.defaultPrompt; 2341 var subordinate; 2342 for (var i = 0; i < subordinates.length; i++) { 2343 subordinate = subordinates[i]; 2344 dataList.push([ 2345 subordinate.subordinate_type, 2346 subordinate.subordinate_type, 2347 AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16) 2348 ]); 2349 if (i === 0) { 2350 defaultType = subordinate.subordinate_type; 2351 txtArea.defaultPrompt = subordinate.inputPrompt; 2352 } 2353 if (prevType === subordinate.subordinate_type) { // remember previously selected values 2354 defaultType = prevType; 2355 txtArea.defaultPrompt = prevPrompt; 2356 } 2357 } 2358 var store = new Ext.data.ArrayStore({ 2359 id: 0, 2360 fields: ['selectValue', 'displayText', 'iconURL'], 2361 data: dataList 2362 }); 2363 typeItem.bindStore(store); 2364 if (!this.anchorNode.attributes.isInvalidType && ("Before" === placeValue || "After" === placeValue)) { 2365 typeItem.setValue(this.anchorNode.type); 2366 } else { 2367 typeItem.setValue(defaultType); 2368 } 2369 typeItem.qtip = typeItem.getValue(); 2370 if (this.anchorNode.ui.anchor === document.activeElement){ 2371 this.handleTypeChange(false, true); 2372 } else { 2373 this.handleTypeChange(false, keepFocus); 2374 } 2375 }, 2376 2377 /** 2378 * handling the "change" event in the "place" radiogroup 2379 * 2380 * @param radiogroup 2381 * the radiogroup 2382 * @param checkedRadio 2383 * the radio button that is checked in the radiogroup 2384 */ 2385 handleLocationChangeEvent: function(radiogroup, checkedRadio){ 2386 this.handleLocationChange(false); 2387 }, 2388 /** 2389 * Updates the icon and the input prompt in response to type changes. 2390 * 2391 * @param resetInput 2392 * a boolean to indicate if the old content of the text area should be replaced by the input prompt 2393 * @param keepFocus 2394 * a boolean to indicate whether to return the focus to the text area in the input panel. 2395 */ 2396 handleTypeChange: function (resetInput, keepFocus) { 2397 var iconURL = this.getFormItem('type').getIconURL(); 2398 if (iconURL.indexOf("scale=16") === -1) { 2399 iconURL = iconURL + '&' + 'scale=16'; 2400 } 2401 this.getFormItem('entryicon').setIcon(iconURL); 2402 2403 var txtArea = this.getFormItem('name'); 2404 var selectedType = this.getFormItem('type').getValue(); 2405 var newPrompt = populationRulesUtil.getRuleProperty(selectedType, null, 'inputPrompt'); 2406 if (newPrompt === null){ 2407 newPrompt = ''; 2408 } 2409 txtArea.defaultPrompt = newPrompt; 2410 if (resetInput === true) { 2411 txtArea.setValue(newPrompt); 2412 txtArea.addClass('x-form-textarea-prompt'); 2413 txtArea.removeClass('x-form-textarea-on-focus'); 2414 txtArea.originalValue = newPrompt; 2415 txtArea.selectText(0, 0); 2416 } else { 2417 if (keepFocus) { 2418 if (!txtArea.disabled && !txtArea.isDirty()) { 2419 txtArea.setValue(newPrompt); 2420 txtArea.addClass('x-form-textarea-prompt'); 2421 txtArea.originalValue = newPrompt; 2422 } 2423 } else { 2424 if (txtArea.isDirty()) { 2425 txtArea.selectText(txtArea.cursorStart, txtArea.cursorEnd); 2426 txtArea.focus(false, true); 2427 } else { 2428 txtArea.setValue(newPrompt); 2429 txtArea.addClass('x-form-textarea-prompt'); 2430 txtArea.originalValue = newPrompt; 2431 txtArea.selectText(0, 0); 2432 txtArea.focus(false, true); 2433 } 2434 } 2435 } 2436 }, 2437 2438 /** 2439 * handling the "select" event in the "type" combobox 2440 * 2441 * @param combo 2442 * the combobox 2443 * @param record 2444 * the record of the combobox 2445 * @param index 2446 * the index of the item selected in the combobox 2447 */ 2448 handleTypeChangeEvent: function(combo, record, index){ 2449 this.handleTypeChange(false, false); 2450 }, 2451 2452 anchorNewContribution: function (msg) { 2453 var newConId = msg.data.subordinateContributionId; 2454 var outputPanel = this.ownerCt.outlinerPanel; 2455 var t = outputPanel.maintreegrid; 2456 var sm = t.selModel; 2457 var rootNode = t.root; 2458 2459 var inputPanelInFocus, inputPanelEl = this.getFormItem('name').el; 2460 if (inputPanelEl.dom == document.activeElement) { 2461 inputPanelInFocus = true; 2462 } else { 2463 inputPanelInFocus = false; 2464 } 2465 2466 rootNode.cascade(function () { 2467 if (this.contributionId === newConId) { 2468 if (inputPanelInFocus) { 2469 t.innerBody.scrollChildIntoView(this.ui.elNode); 2470 sm.clearSelections(); 2471 sm.anchorNode(this, true); 2472 return false; 2473 } else { 2474 t.innerBody.scrollChildIntoView(this.ui.elNode); 2475 sm.clearSelections(); 2476 sm.anchorNode(this); 2477 return false; 2478 } 2479 } 2480 return true; 2481 }); 2482 2483 // if this contribution is the only one inside the parent of a PC shell, trigger the child 2484 if (rootNode.childNodes.length === 1) { 2485 for (var i = 0; i < outputPanel.subComponentRenderers.length; i++) { 2486 if (outputPanel.subComponentRenderers[i].type && 2487 outputPanel.subComponentRenderers[i].type === 'pcChildComponentRenderer') { 2488 var anchoredNode = sm.anchoredNode; 2489 var childTriggerCell = anchoredNode.getCellObject(t, anchoredNode, t.columns[i + 1]); 2490 if (childTriggerCell) { 2491 childTriggerCell.launchSubCompWindow(); 2492 // return cursor to parent's input panel? 2493 } 2494 break; 2495 } 2496 } 2497 } 2498 2499 // for IYO 2500 var txtArea = this.getFormItem('name'); 2501 var task = new Ext.util.DelayedTask(txtArea.calcLocaterArrow, txtArea); 2502 task.delay(10); 2503 } 2504 }); 2505 //####################################### end input panel assembly ##################################### 2506 2507 //####################################### outliner border panel ######################################## 2508 var outlinerBorderPanel = new Ext.Panel({ 2509 header: false, 2510 title: 'Outliner', 2511 layout: 'border', 2512 itemId: 'subcomponentContainer', 2513 superiorId: null, 2514 componentId: null, 2515 ctCls: 'x-panel-noborder', 2516 bodyStyle: 'background-color: white;', 2517 bodyBorder: false, 2518 collapseUnspecifiedIcon: collapseUnspecifiedIcon, 2519 lines: lines, 2520 lineNumbering: lineNumberEnable, 2521 outlinerPanel: outlinerPanel, 2522 items: isHeaderVisible ? [headerPanel, outlinerPanel, inputPanel] : [outlinerPanel, inputPanel], 2523 afterRender: function () { 2524 Ext.BoxComponent.superclass.afterRender.call(this); 2525 this.boxReady = true; 2526 this.setSize(this.width, this.height); 2527 if (this.x || this.y) { 2528 this.setPosition(this.x, this.y); 2529 } else if (this.pageX || this.pageY) { 2530 this.setPagePosition(this.pageX, this.pageY); 2531 } 2532 2533 if (this.layout) { 2534 if (typeof this.layout == 'string') { 2535 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); 2536 } 2537 this.setLayout(this.layout); 2538 2539 if (this.activeItem !== undefined) { 2540 var item = this.activeItem; 2541 delete this.activeItem; 2542 this.layout.setActiveItem(item); 2543 return; 2544 } 2545 } 2546 this.ownerCt.doLayout(); 2547 if (this.actionCenterListener == null) { 2548 this.actionCenterListener = new ActionCenterListener(); 2549 } 2550 actionCenterAPI.startBatch(); 2551 this.outlinerPanel.buildBaseTreeNode(); 2552 actionCenterUtility.startClientMessageListener(); 2553 actionCenterAPI.endBatch(); 2554 }, 2555 destroy: function () { 2556 if (inputPanel.editMode) { 2557 inputPanel.updateContribution(); 2558 } else { 2559 var txt = inputPanel.getFormItem('name').getValue(); 2560 var match = false; 2561 if (txt === inputPanel.getFormItem('name').defaultPrompt){ 2562 match = true; 2563 } 2564 //var matches = txt.match(inputPanel.getFormItem('name').defaultPrompt); 2565 if (!match && txt != "") { 2566 inputPanel.addContribution(); 2567 } 2568 } 2569 Ext.Panel.superclass.destroy.apply(this, arguments); 2570 }, 2571 reload: function (newSuperiorContributionId) { 2572 outlinerPanel.reload(newSuperiorContributionId); 2573 }, 2574 busyEl: null, 2575 listeners: { 2576 'swap': function () { 2577 tagBar.getButton('sendbutton').disable(); 2578 if (!this.busyEl) { 2579 // create an indicator indicating that the system is swapping 2580 this.busyEl = Ext.fly(inputPanel.el).createChild({ 2581 html: 'Swapping...' 2582 }); 2583 this.busyEl.addClass('loading-indicator'); 2584 this.busyEl.setStyle('z-index', '15000'); 2585 this.busyEl.setVisible(true); 2586 } 2587 2588 var task = new Ext.util.DelayedTask(function() { 2589 if (this.busyEl) { 2590 Ext.destroy(this.busyEl); // remove the busy indicator 2591 this.busyEl = null; 2592 } 2593 }, this); 2594 task.delay(250); // display the busy indicator for quarter of a second 2595 } 2596 } 2597 }); 2598 //####################################### end outliner border panel #################################### 2599 2600 outlinerBorderPanel.superiorId = superiorContributionId; 2601 outlinerBorderPanel.componentId = componentId; 2602 var outlinerFitPanel = new Ext.Panel({// outermost panel of an outliner 2603 layout: 'fit', 2604 bodyStyle: 'background-color: white;', 2605 items: [outlinerBorderPanel], 2606 reload: function(newSuperiorContributionId) { 2607 outlinerBorderPanel.reload(newSuperiorContributionId); 2608 } 2609 }); 2610 outlinerBorderPanel.doLayout(); 2611 outlinerFitPanel.doLayout(); 2612 this.getPanel = function () { 2613 return outlinerFitPanel; 2614 } 2615 2616 if (target && target.length > 0) { 2617 var divConfig = {}; 2618 divConfig.renderTo = target; 2619 divConfig.layout = 'fit'; 2620 divConfig.items = [outlinerFitPanel]; 2621 AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig)); 2622 } 2623 }; 2624 2625 // Begin AC.pss.Button definition /////////////////////////////////////////////////////////////////// 2626 /** 2627 * Default constructor. 2628 * 2629 * @class The generic class for the Button of the PSS. 2630 * These buttons do not have minimum size and have their text and icon configurable. 2631 * 2632 * @extends Ext.Container 2633 * 2634 */ 2635 AC.pss.Button = Ext.extend(Ext.Container,{ 2636 layout:'hbox', 2637 layoutConfig: { 2638 align: 'stretch' 2639 }, 2640 bodyBorder: false, 2641 2642 /** 2643 * @config buttonIcon 2644 * the id used to specify the icon for this button. 2645 * 2646 * @default null 2647 */ 2648 buttonIcon: null, 2649 /** 2650 * @config buttonLabel 2651 * the label for this button. 2652 * 2653 * @default null 2654 */ 2655 buttonLabel: null, 2656 /** 2657 * initialize the button. 2658 * 2659 * @return void 2660 */ 2661 initComponent: function(){ 2662 var img, txt; 2663 var buttonIcon = this.initialConfig.buttonIcon; 2664 var buttonLabel = this.initialConfig.buttonLabel; 2665 2666 if ((buttonIcon != null) && (buttonIcon.length > 5)) { 2667 img = AC.util.StandardIcons.getImageServlet() + buttonIcon +'&scale=16'; 2668 } else { 2669 img = ''; 2670 } 2671 2672 if (buttonLabel !== null) { 2673 txt = buttonLabel; 2674 } else { 2675 txt = ''; 2676 } 2677 this.items = new Ext.Button({ 2678 flex: 1, 2679 icon: img, 2680 text: txt, 2681 scope: this, 2682 handler: function(){ 2683 this.handler(); 2684 } 2685 }); 2686 AC.pss.Button.superclass.initComponent.call(this); 2687 }, 2688 /** 2689 * initialize the control in the PSS. 2690 * 2691 * @return void 2692 */ 2693 handler: function(){ 2694 2695 } 2696 }); 2697 ///////////////////////////////////////////////////////////////////////////////////////////////////// 2698 2699 // Begin AC.pss.Control definition ////////////////////////////////////////////////////////////////// 2700 /** 2701 * Default constructor. 2702 * 2703 * @class The generic class for the Control of the PSS. 2704 * 2705 * @param componentId 2706 * 2707 * @param renderer 2708 * 2709 * @param subrenderer 2710 * 2711 * @param target 2712 * 2713 */ 2714 AC.pss.Control = function (componentId, renderer, subrenderer, target) { 2715 this.componentId = componentId; 2716 this.renderer = renderer; 2717 this.subrenderer = subrenderer; 2718 this.target = target; 2719 this.configuration = renderer.getComponentConfiguration(); 2720 this.initComponent(); 2721 }; 2722 2723 AC.pss.Control.prototype = { 2724 /** 2725 * Check whether the control is set up in "display as button"(isPopup = true) or not. 2726 * 2727 * @default null 2728 */ 2729 isPopup: null, 2730 2731 /** 2732 * The pop up window of this control. 2733 * 2734 * @default null 2735 */ 2736 subComponentWindow: null, 2737 2738 /** 2739 * The title of the pop up window of this control. 2740 * 2741 * @default null 2742 */ 2743 windowTitle: null, 2744 2745 /** 2746 * Initialize the control in the PSS. 2747 * 2748 * @return void 2749 */ 2750 initComponent: function() { 2751 this.windowTitle = this.configuration.getPropertyValue('windowTitle'); 2752 if (this.isPopup === null) { 2753 this.isPopup = this.configuration.getPropertyValue("isPopup") === 'Y' ? true : false; 2754 } 2755 var content; 2756 var control = this.getControlPanel(); 2757 if (this.isPopup){ 2758 if (control){ 2759 this.initSubComponentWindow(control); 2760 } 2761 content = this.initButton(); 2762 } else { 2763 content = control; 2764 } 2765 var divConfig = { 2766 renderTo: this.target, 2767 layout: 'fit', 2768 items: [content] 2769 }; 2770 AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig)); 2771 }, 2772 2773 /** 2774 * The handler for the button when the button is clicked. 2775 * 2776 * @return void 2777 */ 2778 initButton: function() { 2779 var buttonIcon = this.configuration.getPropertyValue('icon'); 2780 var buttonLabel = this.configuration.getPropertyValue('buttonLabel'); 2781 var pssButton = new AC.pss.Button({ 2782 buttonIcon: buttonIcon, 2783 buttonLabel: buttonLabel, 2784 controlObj: this, 2785 handler: function() { 2786 this.controlObj.buttonHandler(); 2787 } 2788 }); 2789 return pssButton; 2790 }, 2791 2792 /** 2793 * The handler for the button when the button is clicked. It will display the pop up window by default 2794 * 2795 * @return void 2796 */ 2797 buttonHandler: function() { 2798 if (this.subComponentWindow) { 2799 this.subComponentWindow.show(); 2800 } 2801 }, 2802 2803 /** 2804 * Initialize the pop up window for the "Display as button" mode. The content of the control will be 2805 * attached to this window as a child item 2806 * @param {Object} control 2807 * the content of the control 2808 * @return void 2809 */ 2810 initSubComponentWindow: function(control){ 2811 var popupHeight = this.configuration.getPropertyValue('popupHeight'); 2812 var popupWidth = this.configuration.getPropertyValue('popupWidth'); 2813 var browserDim = actionCenterUtility.getBrowserDimensions(); 2814 this.subComponentWindow = new AC.Window({ 2815 title: this.windowTitle ? this.windowTitle : '', 2816 layout: 'fit', 2817 height: browserDim.height * parseInt(popupHeight, 10) / 100, 2818 width: browserDim.width * parseInt(popupWidth, 10) / 100, 2819 items: [control] 2820 }); 2821 }, 2822 2823 /** 2824 * Get the content of the control. This function is to be overidden in the subclasses 2825 * 2826 * @return {Object} control 2827 */ 2828 getControlPanel: function() { 2829 2830 } 2831 }; 2832 2833