All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartclient.debug.public.sc.client.widgets.Portal.js Maven / Gradle / Ivy

The newest version!
/*
 * Isomorphic SmartClient
 * Version SC_SNAPSHOT-2011-08-08 (2011-08-08)
 * Copyright(c) 1998 and beyond Isomorphic Software, Inc. All rights reserved.
 * "SmartClient" is a trademark of Isomorphic Software, Inc.
 *
 * [email protected]
 *
 * http://smartclient.com/license
 */



// Portlet
// ---------------------------------------------------------------------------------------

//> @class Portlet
// Custom subclass of Window configured to be embedded within a PortalLayout.
// @visibility external
// @treeLocation Client Reference/Layout/PortalLayout
//<
isc.defineClass("Portlet", "Window").addProperties({
    showShadow:false,
    
    // enable predefined component animation
    animateMinimize:true,

    // Window is draggable with "outline" appearance by default.
    // "target" is the solid appearance.
    dragAppearance:"outline",
    
    //>@attr portlet.canDrop (boolean : true : IRW)
    // Portlets have canDrop set to true to enable drag/drop reposition within the portalLayout
    // @visibility external
    //<
    canDrop:true,
    
    //>@attr portlet.minHeight (Number : 60 : IRW)
    // Specifies a minimum height for the Portlet. The height of rows within a +link{PortaLayout}
    // will be adjusted to take into account the minHeight of all the Portlets in that row.
    // @see Canvas.minHeight
    // @visibility external
    //<
    minHeight: 60,

    setMinHeight : function (height) {
        this.minHeight = height;
        if (this.portalRow) this.portalRow._applyMinHeight();
    },

    //>@attr portlet.rowHeight (Number or String : null : IRW)
    // If you set the rowHeight of a Portlet before adding it to a +link{PortalLayout}, then
    // the height will be used when creating the new row. If adding the Portlet
    // to an existing row (or dragging it there), the Portlet's rowHeight will be used if 
    // the row's height has not already been specified. However, if you 
    // set the rowHeight of a Portlet after adding it to the PortalLayout, then the height
    // of the entire row will always be adjusted to match.
    // 

// You can also just specify +link{Canvas.height,height} when initializing a Portlet, and it // will be applied to the rowHeight when added to a PortalLayout. However, changing the Portlet's // height after initialization will not affect the row. //

// Note that getting the rowHeight will indicate the rowHeight specified for this Portlet, // not the actual height of the row it is in. // @visibility external //< // Also see the code in portalRow.addPortlets to see how the rowHeight and _userHeight are applied there. // Note that we do not keep track of changes to the real row's height -- we are only responding // to explicitly setting rowHeight on the portlet. Tracking the real row's height may sometimes make some // sense, but the user's intentions aren't necessarily easy to model -- for instance, the user may have // shrunk a row but want the portlet to automatically expand if dragged to an empty column. setRowHeight : function (height) { this.rowHeight = height; if (this.portalRow) this.portalRow.setHeight(height); }, // resize from any edge resizeFrom: null, // customize the appearance and order of the controls in the window header // (could do this in load_skin.js instead) showMaximizeButton: true, headerControls:["headerLabel", "minimizeButton", "maximizeButton", "closeButton"], // show either a shadow, or translucency, when dragging a portlet // (could do both at the same time, but these are not visually compatible effects) //showDragShadow:true, dragOpacity:30, //>@attr portlet.showCloseConfirmationMessage (boolean : true : IRW) // If true, +link{closeConfirmationMessage} will be displayed before portlets are closed // @visibility external //< showCloseConfirmationMessage:true, //>@attr portlet.closeConfirmationMessage (string : "Close portlet?" : IRW) // Confirmation message to show the user when closing portlets if // +link{showCloseConfirmationMessage} is true. // @visibility external // @group i18nMessages //< closeConfirmationMessage:"Close portlet?", //>@attr portlet.destroyOnClose (boolean : false : IRW) // Whether to call +link{Canvas.destroy,destroy()} when closing the Portlet. // @visibility external //< //>@method portlet.closeClick() // closeClick overridden to show +link{portlet.closeConfirmationMessage} to the user before // removing the portlet from the PortalLayout via +link{portalLayout.removePortlet()} // @visibility external //< closeClick : function () { if (this.showCloseConfirmationMessage) { isc.confirm(this.closeConfirmationMessage, {target:this, methodName:"confirmedClosePortlet"}); } else { this.confirmedClosePortlet(true); } }, confirmedClosePortlet : function (value) { if (!value) return; // If we have an editContext, we'll do the removal from there whether or not // we are in editMode if (this.editContext && this.editNode) { this.editContext.removeNode(this.editNode); } else { if (this.portalRow) { this.portalRow.removePortlets(this); } else { this.clear(); } } if (this.destroyOnClose) this.markForDestroy(); }, maximize : function () { var width = this.getVisibleWidth(), height = this.getVisibleHeight(), pageLeft = this.getPageLeft(), pageTop = this.getPageTop() ; this._portletPlaceholder = isc.Canvas.create({ width: this.getVisibleWidth(), height: this.getVisibleHeight(), minHeight: this.getMinHeight(), _portlet: this }); this.masterLayout = this.parentElement; this.masterLayout.portletMaximizing = true; this.masterLayout.replaceMember(this, this._portletPlaceholder, false); this.masterLayout.portletMaximizing = false; // maximize to the dashboard container, not whole window this.setWidth(width); this.setHeight(height); this.moveTo(pageLeft, pageTop); this.bringToFront(); this.draw(); this.delayCall("doMaximize"); }, completeRestore : function () { this.Super("completeRestore", arguments); this.masterLayout.portletMaximizing = true; this.masterLayout.replaceMember(this._portletPlaceholder, this); this.masterLayout.portletMaximizing = false; this._portletPlaceholder._portlet = null; this._portletPlaceholder.destroy(); delete this._portletPlaceholder; delete this.masterLayout; }, doMaximize : function () { this.Super("maximize", arguments); } }); // provides a menu for adding a remove columns isc.defineClass("PortalColumnHeader", "HLayout").addProperties({ height: 20, noResizer: true, border:"1px solid #CCCCCC", // allow dragging by the header canDragReposition: true, initWidget : function () { this.Super("initWidget", arguments); // header drags the portalColumn this.dragTarget = this.creator; this.addMember(isc.LayoutSpacer.create()); this.menu = this.getMenuConstructor().create({ width: 150, portalColumn: this.creator, data: [{ title: "Remove Column", click: "menu.portalColumn.removeSelf()", // Don't offer to remove the last column. enableIf: function (target, menu, item) { return menu.portalColumn.portalLayout.getMembers().length > 1; } },{ title: "Add Column", click: "menu.portalColumn.addNewColumn()" }] }); this.addMember(isc.MenuButton.create({ title: "Column Properties", width: 150, menu: this.menu })); this.addMember(isc.LayoutSpacer.create()); } }); // Manages horizontal vs vertical drag and drop such that a drop to the sides is a drop within // this PortalRow and a drop above or below is a drop within the parent, before or after this // PortalRow. // Created whenever a drop occurs in a PortalColumn (even if it's the first drop). // Note that you can drop just about anything on a PortalRow -- it will be wrapped in a Portlet // if necessary. isc.defineClass("PortalRow", "Layout").addProperties({ defaultResizeBars : "marked", vertical : false, overflow: "hidden", // leave some space between portlets layoutMargin: 3, // enable drop handling canAcceptDrop:true, // change appearance of drag placeholder and drop indicator dropLineThickness:2, dropLineProperties:{backgroundColor:"blue"}, // Will accept a portlets attribute and add it (or them, if an array) to the portalRow initWidget : function () { this.Super("initWidget", arguments); if (this.portlets) this.addPortlets(this.portlets); this.portlets = null; }, // number of pixels you have to be within the left or right border of a portlet for us to // show a drop to the left or right of this portlet. If not within this margin, drop is // indicated above or below instead. hDropOffset: 15, isHDrop : function () { var dropPosition = this.getDropPosition(); var dropOverTarget = this.getMember(dropPosition == 0 ? 0 : dropPosition - 1); if (!dropOverTarget.containsEvent() && dropPosition < this.members.length) { dropOverTarget = this.getMember(dropPosition); } var targetOffsetX = dropOverTarget.getOffsetX(); if (targetOffsetX < this.hDropOffset || targetOffsetX > dropOverTarget.getVisibleWidth() - this.hDropOffset) { return true; } else { return false; } }, // We pass through the drop if it is a PortalColumn, since it doesn't make sense to drop // a PortalColumn on a PortalRow -- the PortalLayout will handle it. isPortalColumnDrop : function () { var dragTarget = this.ns.EH.dragTarget; var type = dragTarget.getDragType(); if (type == "PortalColumn") return true; //>EditMode if (dragTarget.isA("Palette")) { var data = dragTarget.getDragData(), component = (isc.isAn.Array(data) ? data[0] : data); if (component.className == "PortalColumn" || component.type == "PortalColumn") return true; } //EditMode if (this.handleDroppedEditNode) dropComponent = this.handleDroppedEditNode(dropComponent, dropPosition); //EditMode if (this.editContext && this.editNode) this.editContext.removeNode(this.editNode); //EditMode // If we have an editContext and we aren't coming from addPortlets, then we check // whether the portlets have an editNode ... if so, we should add it if (this.editContext && !this._addingPortlets && !this.portletMaximizing) { for (var i = 0; i < portlets.length; i++) { var portlet = portlets[i]; if (portlet.editNode) { this.editContext.addNode(portlet.editNode, this.editNode, index + i, null, true); } } } //EditMode // We keep track of whether we're calling addMembers from here in order to know whether // to check for editNodes. The assumption is that if we're calling from here, we have // already dealt with editNodes appropriately. //EditMode // If we have an editContext, then we check whether we got here via // removePortlets. If we did, then we assume that the code has done // the right thing re: editContext. If not, then we're probably doing // a drag & drop from Layout.js, so we should remove the component if (self.editContext && portlet.editNode && !self._removingPortlets) { // Note that we skip live removal, since we'll have just done that self.editContext.removeNode(portlet.editNode, true); } //EditMode // We keep track of whether we are calling removeMembers from here in order // to know whether to check for editNodes. The assumption is that if we are // calling from here, we have already done the appropriate thing with any // editNodes. //EditMode if (dragTarget.isA("Palette")) { var data = dragTarget.getDragData(), component = (isc.isAn.Array(data) ? data[0] : data); if (component.className == "PortalColumn" || component.type == "PortalColumn") return true; } //EditMode if (this.handleDroppedEditNode) dropComponent = this.handleDroppedEditNode(dropComponent, dropPosition); // 0) { var allNumeric = sizes.map(function (size) { return isc.isA.Number(size); }).and(); if (allNumeric) { var totalNumericSizes = sizes.sum(); if (totalNumericSizes < totalSize) { sizes[sizes.length - 1] = "*"; } } } return this.Super("applyStretchResizePolicy", arguments); } }); // Vertical layout based container rendered within a PortalLayout. // PortalColumns are automatically constructed by the PortalLayout class and will not typically // be directly instantiated. // // The only reason to expose this would be to allow customization of appearance - and it makes // more sense to do that via attributes on the PortalLayout itself. // --------------------------------------------------------------------------------------- // Offers Drag and drop creation of Portlets, where a new PortalRow is created to manage the // portlet. isc.defineClass("PortalColumn", "Layout").addProperties({ vertical:true, layoutMargin: 3, // Can drag the PortalColumn, but it does not handle drops ... the PortalColumnBody // manages that. dragAppearance: "outline", canAcceptDrop: false, canDrop: true, dragType: "PortalColumn", // This one should not change heights ... overflow: "hidden", // The columnHeader is handled as an AutoChild showColumnHeader: true, columnHeaderConstructor: "PortalColumnHeader", columnHeaderDefaults: { title: "Column" }, // Make showColumnHeader updatable setShowColumnHeader : function (show) { if (show) { if (this.showColumnHeader) return; this.showColumnHeader = show; this.addAutoChild("columnHeader", {autoParent: "none"}); this.addMember(this.columnHeader, 0); } else { if (!this.showColumnHeader) return; this.showColumnHeader = show; this.removeMember(this.columnHeader); } }, // The scrollContainer helps to manage scrolling the rowLayoutContainer. Without it, // the problem is that overflow: auto on the PortalColumnBody triggers a re-layout // of the parent, which we don't want ... this cuts it out. scrollContainerConstructor: "Canvas", scrollContainerDefaults: { overflow: "auto" }, // The rowLayout is where the actual rows go ... this avoids having to // continually adjust the code for whether the columnHeader is // showing or not. // // These Autochild settings are referenced in PortalLayout as well, since that is where they // are exposed as an API. Changing rowLayoutDefaults there will also change it // here, but that is fine, since people should be using changeDefaults() anyway. The // settings are then copied dynamically from PortalLayout when it creates columns. rowLayoutConstructor: "PortalColumnBody", rowLayoutDefaults: { autoParent: "scrollContainer" }, // Will accept a portalRows attribute, containing portalRows to insert, // or properties to be used to construct them. initWidget : function () { this.Super("initWidget", arguments); this.addAutoChild("columnHeader"); this.addAutoChild("scrollContainer"); this.addAutoChild("rowLayout"); this.setCanResizeRows(this.canResizeRows); if (this.portalRows) this.addPortalRows(this.portalRows); this.portalRows = null; }, addNewColumn : function () { this.portalLayout.addColumnAfter(this); }, removeSelf : function () { this.portalLayout.removeColumn(this.portalLayout.getMemberNumber(this)); }, // See comment on rowLayoutConstructor re: the reference in PortalLayout rowConstructor: "PortalRow", // Creates rows via AutoChild logic, or modifies existing rows // to prepare them to be added to the column. Note that rowConstructor, // rowDefaults and rowProperties will have been copied from the portalLayout. makePortalRow : function (props) { if (props == null) props = {}; var dynamicProperties = { portalLayout: this.portalLayout, portalColumn: this }; var portalRow; if (isc.isA.PortalRow(props)) { // If we're given an already created PortalRow, then use setProperties // to add the dynamicProperties. props.setProperties(dynamicProperties); portalRow = props; } else { // Otherwise, construct it as an autoChild isc.addProperties(props, dynamicProperties); portalRow = this.createAutoChild("row", props); } return portalRow; }, setCanResizeRows : function (canResize) { this.canResizeRows = canResize; // Using "all" instead of "middle" so that we can adjust the overall size ... // see comment on PortalColumnBody.applyStretchResizePolicy. this.rowLayout.setDefaultResizeBars(canResize ? "all" : "none"); }, addPortalRows : function (rows, position) { if (!isc.isAn.Array(rows)) rows = [rows]; var self = this; rows = rows.map(function (row) { return self.makePortalRow(row); }); this.rowLayout.addMembers(rows, position); }, addPortalRow : function (row, position) { this.addPortalRows(row, position); }, removePortalRows : function (rows) { this.rowLayout.removeMembers(rows); }, removePortalRow : function (row) { this.removePortalRows(row); }, getPortalRows : function () { return this.rowLayout.getMembers(); }, getPortalRowNumber : function (id) { return this.rowLayout.getMemberNumber(id); }, getPortalRow : function (rowID) { return this.rowLayout.getMember(rowID); }, // Returns flat list of portlets getPortlets : function () { var portlets = []; this.getPortalRows().map(function (row) { portlets.addList(row.getPortlets()); }); return portlets; }, // Returns portlets in array of arrays, corresponding to rows getPortletArray : function () { return this.getPortalRows().map(function (row) { return row.getPortlets(); }); }, getPortlet : function (id) { var rows = this.getPortalRows(); for (var x = 0; x < rows.length; x++) { var portlet = rows[x].getPortlet(id); if (portlet) return portlet; } return null; }, // Adds portlets, auto-wrapping them in rows addPortlets : function (portlets, position) { if (!isc.isAn.Array(portlets)) portlets = [portlets]; var self = this; var rows = portlets.map(function(portlet) { return self.makePortalRow({ portlets: portlet }); }); this.addPortalRows(rows, position); }, addPortlet : function (portlet, position) { this.addPortlets(portlet, position); }, addPortletToExistingRow : function (portlet, rowNum, rowOffset) { var rows = this.rowLayout.getMembers(); if (rows == null || rows.length <= rowNum) { if (this.editContext && this.editNode && portlet.editNode) { this.addNode(portlet.editNode, this.editNode, rows.length); } else { this.addPortlet(portlet, rows.length); } } else { var portalRow = this.rowLayout.getMember(rowNum); if (portalRow.editContext && portalRow.editNode && portlet.editNode) { portalRow.editContext.addNode(portlet.editNode, portalRow.editNode, rowOffset); } else { portalRow.addPortlets(portlet, rowOffset); } } } }); //> @class PortalLayout // A PortalLayout is a special subclass of Layout designed to display +link{Portlet} windows. // A PortalLayout displays Portlets in columns and supports drag-drop interaction for moving // Portlets around within the PortalLayout. Portlets may be drag-reordered within columns, dragged // into other columns, or dragged next to other Portlets to sit next to them horizontally // within a column. // // @visibility external // @treeLocation Client Reference/Layout //< isc.defineClass("PortalLayout", "Layout").addProperties({ vertical:false, // Allow the column widths to scroll if necessary overflow: "auto", //> @attr portalLayout.numColumns (integer : 2 : IR) // Initial number of columns to show in this PortalLayout. Note that after initialization // columns should be added / removed via +link{addColumn()} and +link{removeColumn}. // @visibility external //< // Note that numColumns is ignored on initialization if the portalColumns attribute is supplied ... // in that case, the columns are initialized from that attribute instead. Also, see // addedToEditContext for manipulation of the numColumns in defaults/initData -- we set it to // zero there because the columns will get their own editNodes (since they need to contain things) numColumns:2, //> @method portalLayout.getNumColumns() // Returns the current number of columns displayed in this PortalLayout. // @return numColumns (Integer) // @visibility external //< // Overridden to return this.getMembers.length. Will have been set up at initialization time. getNumColumns : function () { return this.getMembers().length; }, //> @attr portalLayout.showColumnMenus (boolean : true : IRW) // Should a menu be shown within each column with options to add / remove columns? // @visibility external //< showColumnMenus:true, //> @method portalLayout.setShowColumnMenus() // Sets +link{showColumnMenus} and updates existing columns to reflect the new setting. // @param showMenus (boolean) Whether to show column menus // @visibility external //< setShowColumnMenus : function (show) { if (this.showColumnMenus == show) return; this.showColumnMenus = show; this.getPortalColumns().map(function (column) { column.setShowColumnHeader(show); }); }, //> @attr portalLayout.columnBorder (string : "1px solid gray" : IRW) // Border to show around columns in this PortalLayout // @visibility external //< columnBorder:"1px solid gray", //> @method portalLayout.setColumnBorder() // Sets the columnBorder for to the specified value and updates any drawn columns to reflect // this. // @param columnBorder (string) New border to show around columns // @visibility external //< setColumnBorder : function (columnBorder) { this.columnBorder = columnBorder; var members = this.members || []; for (var i = 0; i < members.length; i++) { members[i].setBorder(columnBorder); } }, //> @attr portalLayout.canResizeColumns (boolean : false : IRW) // Are columns in this portalLayout drag-resizeable? // @visibility external //< canResizeColumns:false, //> @method portalLayout.setCanResizeColumns() // Set whether columns in this portalLayout are drag-resizable, and update any // drawn columns to reflect this. // @param canResize (Boolean) Whether columns are drag-resizable // @visibility external //< setCanResizeColumns : function (resizeColumns) { this.canResizeColumns = resizeColumns; // Using "all" instead of "middle" so that we can change the overal size ... // see comment on PortalLayout.applyStretchResizePolicy this.setDefaultResizeBars(resizeColumns ? "all" : "none"); }, //> @attr portalLayout.canResizeRows (boolean : false : IRW) // Should vertical drag-resize of portlets within columns be allowed? // @visibility external //< // Can resize rows since we want to resize the entire row of portlets probably canResizeRows:false, //> @method portalLayout.setCanResizeRows() // Set whether vertical drag-resize of portlets within columns is allowed, and // update any drawn columns to reflect this. // @param canResize (Boolean) Whether drag-resize of portlets within columns is allowed // @visibility external //< setCanResizeRows : function (resizeRows) { this.canResizeRows = resizeRows; this.getPortalColumns().map(function (column) { column.setCanResizeRows(resizeRows); }); }, // This allows drag/drop reordering within the portal layout canAcceptDrop: true, dropTypes: ["PortalColumn"], // change appearance of drag placeholder and drop indicator dropLineThickness:2, dropLineProperties:{backgroundColor:"blue"}, initWidget : function () { this.Super("initWidget", arguments); this.setCanResizeColumns(this.canResizeColumns); if (this.portalColumns) { this.addPortalColumns(this.portalColumns); this.portalColumns = null; } else { if (this.numColumns) { for (var x = 0; x < this.numColumns; x++) { this.addColumn(); } } } }, //> @method portalLayout.getDropPortlet() // This method is called when the user drops components into the rows or columns of this // PortalLayout. //

// Overriding this method allows you to modify drop behaviour when creating or reordering // portlets via drag & drop. You can return the dragTarget for the standard behavior, // or null to cancel the drop. //

// Otherwise, return the component you want to be dropped (as for +link{layout.getDropComponent}). // You will generally want to return a +link{Portlet} or subclass. However, you can return // any +link{Canvas}, and it will automatically be wrapped in a Portlet if necessary. // @param dragTarget (Canvas) drag target // @param colNum (int) indicates which column the portlet is being dropped on. // @param rowNum (int) indicates the row number being dropped on. // @param [dropPosition] (int) Drop position within an existing row. If the dropPosition // is null, then that means that a new row will be created. // @return (Canvas) drop-component or custom Portlet to embed in the portalLayout. Returning // null will cancel the drop. // @visibility external //< // This is called from portalColumnBody.getDropComponent and portalRow.getDropComponent. // Note that return type is documented as Canvas but overrides would probably // always return a Portlet. getDropPortlet : function (dragTarget, colNum, rowNum, dropPosition) { return dragTarget; }, //> @attr portalLayout.row (AutoChild : null : A) // Automatically generated +link{HLayout} used to create rows of +link{Portlet,Portlets} via // +link{Class.createAutoChild,createAutoChild()}. Since this is an +link{AutoChild}, you can use // rowDefaults and rowProperties to customize the rows. //

// Rows are created inside +link{rowLayout,rowLayouts}, which in turn are inside +link{column,columns}. // @see portalLayout.column // @see portalLayout.rowLayout // @visibility external //< // Note that the actual call to createAutoChild is in PortalColumn. We expose the property // here instead because we're trying to avoid exposing PortalColumn and PortalRow. rowConstructor: isc.PortalColumn.getInstanceProperty("rowConstructor"), //> @attr portalLayout.rowLayout (AutoChild : null : A) // Automatically generated +link{VLayout} used to create columns of +link{Portlet,Portlets} via // +link{Class.createAutoChild,createAutoChild()}. Since this is an +link{AutoChild}, you can use // rowLayoutDefaults and rowLayoutProperties to customize the layout used to contain the rows. //

// The rowLayout is the actual container for +link{row,rows} of +link{Portlet,Portlets}. See +link{column,column} for // the column as a whole, which may include a menu as well (depending on +link{showColumnMenus,showColumnMenus}). // If you want to style the columns as a whole, // use columnDefaults or columnProperties, but if you want to style the layout that actually contains the // rows, use rowLayoutDefaults or rowLayoutProperties. // @see portalLayout.rowLayout // @see portalLayout.row // @visibility external //< // Note that the actual call to addAutoChild is in PortalColumn. We expose teh property // here instead because we're trying to avoid exposing PortalColumn and PortalRow. rowLayoutConstructor: isc.PortalColumn.getInstanceProperty("rowLayoutConstructor"), rowLayoutDefaults: isc.PortalColumn.getInstanceProperty("rowLayoutDefaults"), //> @attr portalLayout.column (AutoChild : null : A) // Automatically generated +link{VLayout} used to create columns of +link{Portlet,Portlets} via // +link{Class.createAutoChild,createAutoChild()}. Since this is an +link{AutoChild}, you can use // columnDefaults and columnProperties to customize the columns. //

// The column includes a menu, if +link{showColumnMenus,showColumnMenus} is true, and a +link{rowLayout,rowLayout} which // actually contains the +link{row,rows}. Therefore, if you want to style the columns as a whole, // use columnDefaults or columnProperties, but if you want to style the layout that contains the // rows, use rowLayoutDefaults or rowLayoutProperties. // @see portalLayout.rowLayout // @see portalLayout.row // @visibility external //< columnConstructor: "PortalColumn", // Make columns using autoChild logic, or apply this PortalLayout's // settings to an existing PortalColumn. Note that we copy rowConstructor etc. in order // to pass the AutoChild logic down for rows. makePortalColumn : function (props) { if (props == null) props = {}; var dynamicProperties = { portalLayout: this, showColumnHeader: this.showColumnMenus, border: this.columnBorder, canResizeRows: this.canResizeRows, rowConstructor: this.rowConstructor, rowDefaults: this.rowDefaults, rowProperties: this.rowProperties, rowLayoutConstructor: this.rowLayoutConstructor, rowLayoutDefaults: this.rowLayoutDefaults, rowLayoutProperties: this.rowLayoutProperties } var portalColumn; if (isc.isA.PortalColumn(props)) { // If we're given an already created PortalColumn, then use setProperties // to make it conform to the PortalLayout settings here. props.setProperties(dynamicProperties); portalColumn = props; } else { // Otherwise, construct it as an autoChild isc.addProperties(props, dynamicProperties); portalColumn = this.createAutoChild("column", props); } return portalColumn; }, // Apply portalColumn logic when adding PoralColumns as members. This allows smoother interaction // with existing drag and drop code in Layout.js, since that code ultimately calls // addMembers and removeMembers addMembers : function (columns, index) { if (!isc.isAn.Array(columns)) columns = [columns]; var self = this; columns = columns.map(function (column) { return self.makePortalColumn(column); }); this.Super("addMembers", arguments); //>EditMode // If we have an editContext and we aren't coming from addPortalColumns, then we check // whether the columns have an editNode ... if so, we should add it if (this.editContext && !this._addingPortalColumns) { for (var i = 0; i < columns.length; i++) { var column = columns[i]; if (column.editNode) { this.editContext.addNode(column.editNode, this.editNode, index + i, null, true); } } } //EditMode // If we have an editContext, then we check whether we got here via // removePortalColumns. If we did, then we assume that the code has done // the right thing re: editContext. If not, then we're probably doing // a drag & drop from Layout.js, so we should remove the component if (this.editContext && !this._removingPortalColumns) { if (!isc.isAn.Array(portalColumns)) portalColumns = [portalColumns]; var self = this; portalColumns.map(function (column) { if (column.editNode) { // Note that we skip live removal, since we'll have just done that self.editContext.removeNode(column.editNode, true); } }); } // @method portalLayout.addColumn() // Adds a new portal column to this layout at the specified position // @param index (integer) target position for the new column // @visibility external //< addColumn : function (index) { //>EditMode // PortalLayout is a little special with respect to EditMode, since the // whole purpose of PortalLayout is to be editable ... thus, it makes // more sense to integrate the editing code here, rather than relying // on separate code in EditMode.js. For instance, it makes more sense // to rely on the standard PortalLayout interface for adding columns, // rather than forcing the user to drag a column from a palette. // // Thus, when adding a Column, we note whether there is an edit context // around and, if so, ask it to do it. That will also eventually run // through addPortalColumn, given the standard sequence of events. //EditMode // This is a bit hackish to generate nice ID's in cases where we // will soon be put into an editContext // @method portalLayout.removeColumn() // Removes the specified column from this layout. // All portlets displayed within this column will be destroyed when the column is removed. // @param index (integer) column number to remove // @visibility external //< removeColumn : function (index) { var column = this.members[index]; if (column != null) { if (this.editContext && column.editNode) { this.editContext.removeNode(column.editNode); } else { column.destroy(); } } }, // addColumnAfter is used by the header menus shown within columns if appropriate addColumnAfter : function (portalColumn) { var targetIndex = this.getMemberNumber(portalColumn) + 1; this.addColumn(targetIndex); }, //>@method portalLayout.getPortlets() // Returns a flat array of all the +link{Portlet,Portlets} in this PortalLayout. // @return portlets (Array of Portlet) // @visibility external // @see getPortletArray() //< getPortlets : function () { var portlets = []; this.getPortalColumns().map(function (column) { portlets.addList(column.getPortlets()); }); return portlets; }, //>@method portalLayout.getPortletArray() // Returns a multi-level array of the +link{Portlet,Portlets} in this PortalLayout, // where the first level corresponds to columns, the second to rows, and the third // to Portlets within rows. // @return portlets (Array of Array of Array of Portlet) // @visibility external // @see getPortlets() //< getPortletArray : function () { return this.getPortalColumns().map(function (column) { return column.getPortletArray(); }); }, //>@method portalLayout.addPortlet() // Adds a +link{Portlet} instance to this portalLayout in the specified position. // @param portlet (Portlet) Portlet to add to this layout. // @param [colNum] (integer) Column in which the Portlet should be added. If unspecified, // defaults to zero. // @param [rowNum] (integer) Row within the column for the Portlet. // @param [rowOffset] (integer) Offset within the row. If you specify a // rowOffset, then the Portlet will be added to the existing row. If not, then a new row // will be created at rowNum. // @visibility external //< //>EditMode in EditMode users can drag/drop from paletteNodes to add portlets to columns. // This will never run through this method so this is not a valid override point to catch every // newly added portlet //@method portalLayout.setColumnWidth() // Sets the width of a column in the PortalLayout. // @param colNumber (Integer) Which column's width to set. // @param width (Number or String) How wide to make the column // @see Canvas.setWidth() // @visibility external //< setColumnWidth : function (columnNumber, width) { var column = this.getPortalColumn(columnNumber); if (!column) return; // This automatically adjusts the editNode if present if (column.editContext && column.editNode) { column.editContext.setNodeProperties(column.editNode, { width: width }); } else { column.setWidth(width); } }, //>@method portalLayout.getColumnWidth() // Gets the width of a column in the PortalLayout. // @param colNumber (Integer) Which column's width to get // @return width (Number) // @see Canvas.getWidth() // @visibility external //< getColumnWidth : function (columnNumber) { var column = this.getPortalColumn(columnNumber); if (column) { return column.getWidth(); } else { return null; } }, getPortalColumns : function () { return this.getMembers(); }, getPortalColumn : function (columnID) { return this.getMember(columnID); }, getPortalColumnNumber : function (columnID) { return this.getMemberNumber(columnID); }, getColumn : function (colNum) { return this.getPortalColumn(colNum); }, //>@method portalLayout.removePortlet() // Removes a +link{Portlet} which is currently rendered in this PortalLayout. // Portlet will not be destroyed by default - if this is desired the calling code should // do this explicitly. // @param portlet (Portlet) portlet to remove // @visibility external //< //>EditMode We *DO* auto-destroy portlets on closeclick in editMode if they were dragged in // from a paletteNode // 0) { var allNumeric = sizes.map(function (size) { return isc.isA.Number(size); }).and(); if (allNumeric) { var totalNumericSizes = sizes.sum(); if (totalNumericSizes < totalSize) { sizes[sizes.length - 1] = "*"; } } } return this.Super("applyStretchResizePolicy", arguments); } });





© 2015 - 2024 Weber Informatics LLC | Privacy Policy