From 69694b7ac010a3ee08ec50ee74869335fb5dc846 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Thu, 12 Apr 2007 01:41:14 +0000 Subject: [PATCH] Merged V2.0 to HEAD 5456: (From WCM_DEPLOY) There were many pure conflicts on license headers, one conflict due to CR-LF and some other smaller issues to resolve: ----------------------------------------- Resolved (line endings not cr-lf): root\projects\repository\config\alfresco\public-services-context.xml Reverted: root\projects\web-client\source\web\images\icons\ajax_anim.gif Reverted or Resolved (License text conflicts): svn revert root\projects\jndi-client\source\java\org\alfresco\jndi\JndiTest.java svn resolved root\projects\jndi-client\source\java\org\alfresco\jndi\AVMFileDirContext.java svn revert root\projects\jndi-client\source\java\org\alfresco\jndi\AVMBulkLoader.java svn revert root\projects\jndi-client\source\java\org\alfresco\filter\CacheControlFilter.java svn revert root\projects\jndi-client\source\java\org\alfresco\filter\CacheControlFilterInfoBean.java svn revert -R root\projects\catalina-virtual\source\java\org\alfresco\mbeans svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\context\AVMStandardContext.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\loader\AVMWebappClassLoader.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\loader\AVMWebappLoader.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\host\AVMResourceBinding.java svn resolved root\projects\catalina-virtual\source\java\org\alfresco\catalina\host\AVMHostConfig.java - why the change in method naming convention? svn resolved root\projects\catalina-virtual\source\java\org\alfresco\catalina\host\AVMHost.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\host\DefaultAVMResourceBinding.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\valve\AVMUrlValveTest.java svn resolved root\projects\catalina-virtual\source\java\org\alfresco\catalina\valve\AVMUrlValve.java svn revert root\projects\catalina-virtual\source\java\org\alfresco\catalina\host\AVMHostMatch.java Modified: root\projects\web-client\source\java\org\alfresco\web\ui\wcm\component\UIDeployWebsite.java (Kevin to check line 330) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5484 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/messages/webclient.properties | 27 + config/alfresco/web-client-config-dialogs.xml | 15 + .../alfresco/web-client-config-properties.xml | 1 + config/alfresco/web-client-config-wcm.xml | 14 + .../handlers/CopyToWebProjectHandler.java | 2 +- .../alfresco/web/bean/wcm/AVMBrowseBean.java | 77 +- .../alfresco/web/bean/wcm/AVMConstants.java | 248 ++- .../web/bean/wcm/CreateFormWizard.java | 3 +- .../web/bean/wcm/CreateWebsiteWizard.java | 39 +- .../web/bean/wcm/DeploySnapshotDialog.java | 243 +++ .../web/bean/wcm/DeploymentMonitor.java | 199 +++ .../web/bean/wcm/DeploymentProgressBean.java | 96 ++ .../web/bean/wcm/EditWebsiteWizard.java | 15 +- .../web/bean/wcm/MonitorDeploymentDialog.java | 104 ++ .../bean/wcm/ViewDeploymentReportDialog.java | 96 ++ .../web/forms/FreeMarkerRenderingEngine.java | 35 + .../alfresco/web/forms/RenderingEngine.java | 10 + .../forms/RenderingEngineTemplateImpl.java | 67 +- .../java/org/alfresco/web/forms/XMLUtil.java | 52 +- .../web/forms/XSLTRenderingEngine.java | 125 +- .../web/forms/xforms/Schema2XForms.java | 239 +-- .../alfresco/web/forms/xforms/SchemaUtil.java | 90 +- .../alfresco/web/forms/xforms/XFormsBean.java | 2 +- .../web/forms/xforms/XFormsProcessor.java | 49 +- .../org/alfresco/web/ui/common/Utils.java | 1 + .../common/converter/MultiValueConverter.java | 2 +- .../ui/common/tag/MultiValueConverterTag.java | 55 + .../web/ui/wcm/component/UIDeployWebsite.java | 494 ++++++ .../ui/wcm/component/UIDeploymentReports.java | 311 ++++ .../ui/wcm/component/UISandboxSnapshots.java | 139 +- .../web/ui/wcm/tag/DeployWebsiteTag.java | 126 ++ .../web/ui/wcm/tag/DeploymentReportsTag.java | 84 + .../xforms/customer-tests/grumpy.burton.1.xsd | 17 + .../user-registration/user-registration.xsd | 118 ++ .../attribute-group-test.xsd | 30 + .../no-elements-test.xsd | 18 + .../readonly-and-default-values-test.xsd | 78 + .../include-test-data-dictionary.ftl | 1 + .../include-test-data-dictionary.xsl | 10 + .../include-test-webapp.ftl | 1 + .../include-test-webapp.xsl | 10 + .../rendering-engine-test/include-test.ftl | 11 + .../rendering-engine-test/include-test.xsd | 23 + .../rendering-engine-test/include-test.xsl | 31 + .../simple-test/components-test.xsd | 2 +- .../unit-tests/simple-test/textarea-test.xsd | 42 + .../textarea-test/textarea-test.xsd | 20 - .../textarea-test/textarea-test.xsl | 135 -- source/web/WEB-INF/alfresco.tld | 10 + source/web/WEB-INF/faces-config-beans.xml | 64 + .../web/WEB-INF/faces-config-navigation.xml | 6 +- source/web/WEB-INF/faces-config-wcm.xml | 9 + source/web/WEB-INF/wcm.tld | 85 + source/web/css/main.css | 34 + source/web/images/icons/deploy.gif | Bin 0 -> 598 bytes source/web/images/icons/deploy_failed.gif | Bin 0 -> 374 bytes source/web/images/icons/deploy_large.gif | Bin 0 -> 1366 bytes source/web/images/icons/deploy_server.gif | Bin 0 -> 583 bytes .../web/images/icons/deploy_server_large.gif | Bin 0 -> 1346 bytes source/web/images/icons/deploy_successful.gif | Bin 0 -> 394 bytes source/web/images/icons/deployment_report.gif | Bin 0 -> 622 bytes .../images/icons/deployment_report_large.gif | Bin 0 -> 1472 bytes source/web/images/parts/deploy_panel_bg.gif | Bin 0 -> 263 bytes source/web/images/parts/deploy_panel_end.gif | Bin 0 -> 694 bytes .../images/parts/deploy_panel_separator.gif | Bin 0 -> 194 bytes .../web/images/parts/deploy_panel_start.gif | Bin 0 -> 468 bytes source/web/images/parts/innerwhite_01.gif | Bin 0 -> 60 bytes source/web/images/parts/innerwhite_02.gif | Bin 0 -> 55 bytes source/web/images/parts/innerwhite_03.gif | Bin 0 -> 60 bytes source/web/images/parts/innerwhite_04.gif | Bin 0 -> 57 bytes source/web/images/parts/innerwhite_06.gif | Bin 0 -> 56 bytes source/web/images/parts/innerwhite_07.gif | Bin 0 -> 60 bytes source/web/images/parts/innerwhite_08.gif | Bin 0 -> 55 bytes source/web/images/parts/innerwhite_09.gif | Bin 0 -> 64 bytes source/web/jsp/wcm/browse-website.jsp | 22 +- .../jsp/wcm/create-form-wizard/details.jsp | 14 +- .../jsp/wcm/create-website-wizard/details.jsp | 29 + source/web/jsp/wcm/deploy.jsp | 36 + source/web/jsp/wcm/deployment-report.jsp | 44 + source/web/jsp/wcm/monitor-deployment.jsp | 36 + .../web/jsp/wcm/output-path-pattern-help.jsp | 2 +- source/web/jsp/wcm/tiny_mce_image_dialog.jsp | 189 +++ source/web/jsp/wcm/tiny_mce_link_dialog.jsp | 187 +++ source/web/scripts/ajax/ajax_helper.js | 150 ++ source/web/scripts/ajax/file_picker_widget.js | 703 ++++++++ source/web/scripts/ajax/xforms.js | 1478 ++++++----------- 86 files changed, 5283 insertions(+), 1422 deletions(-) create mode 100644 source/java/org/alfresco/web/bean/wcm/DeploySnapshotDialog.java create mode 100644 source/java/org/alfresco/web/bean/wcm/DeploymentMonitor.java create mode 100644 source/java/org/alfresco/web/bean/wcm/DeploymentProgressBean.java create mode 100644 source/java/org/alfresco/web/bean/wcm/MonitorDeploymentDialog.java create mode 100644 source/java/org/alfresco/web/bean/wcm/ViewDeploymentReportDialog.java create mode 100644 source/java/org/alfresco/web/ui/common/tag/MultiValueConverterTag.java create mode 100644 source/java/org/alfresco/web/ui/wcm/component/UIDeployWebsite.java create mode 100644 source/java/org/alfresco/web/ui/wcm/component/UIDeploymentReports.java create mode 100644 source/java/org/alfresco/web/ui/wcm/tag/DeployWebsiteTag.java create mode 100644 source/java/org/alfresco/web/ui/wcm/tag/DeploymentReportsTag.java create mode 100644 source/test-resources/xforms/customer-tests/grumpy.burton.1.xsd create mode 100644 source/test-resources/xforms/demos/user-registration/user-registration.xsd create mode 100644 source/test-resources/xforms/unit-tests/interesting-schema-test/attribute-group-test.xsd create mode 100644 source/test-resources/xforms/unit-tests/interesting-schema-test/no-elements-test.xsd create mode 100644 source/test-resources/xforms/unit-tests/interesting-schema-test/readonly-and-default-values-test.xsd create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.ftl create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.xsl create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.ftl create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.xsl create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.ftl create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsd create mode 100644 source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsl create mode 100644 source/test-resources/xforms/unit-tests/simple-test/textarea-test.xsd delete mode 100644 source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsd delete mode 100644 source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsl create mode 100644 source/web/images/icons/deploy.gif create mode 100644 source/web/images/icons/deploy_failed.gif create mode 100644 source/web/images/icons/deploy_large.gif create mode 100644 source/web/images/icons/deploy_server.gif create mode 100644 source/web/images/icons/deploy_server_large.gif create mode 100644 source/web/images/icons/deploy_successful.gif create mode 100644 source/web/images/icons/deployment_report.gif create mode 100644 source/web/images/icons/deployment_report_large.gif create mode 100644 source/web/images/parts/deploy_panel_bg.gif create mode 100644 source/web/images/parts/deploy_panel_end.gif create mode 100644 source/web/images/parts/deploy_panel_separator.gif create mode 100644 source/web/images/parts/deploy_panel_start.gif create mode 100644 source/web/images/parts/innerwhite_01.gif create mode 100644 source/web/images/parts/innerwhite_02.gif create mode 100644 source/web/images/parts/innerwhite_03.gif create mode 100644 source/web/images/parts/innerwhite_04.gif create mode 100644 source/web/images/parts/innerwhite_06.gif create mode 100644 source/web/images/parts/innerwhite_07.gif create mode 100644 source/web/images/parts/innerwhite_08.gif create mode 100644 source/web/images/parts/innerwhite_09.gif create mode 100644 source/web/jsp/wcm/deploy.jsp create mode 100644 source/web/jsp/wcm/deployment-report.jsp create mode 100644 source/web/jsp/wcm/monitor-deployment.jsp create mode 100644 source/web/jsp/wcm/tiny_mce_image_dialog.jsp create mode 100644 source/web/jsp/wcm/tiny_mce_link_dialog.jsp create mode 100644 source/web/scripts/ajax/ajax_helper.js create mode 100644 source/web/scripts/ajax/file_picker_widget.js diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 2b45acddf2..bc08093ea8 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -669,6 +669,7 @@ create_form_form_details_step_title=Step One - Web Form Details create_form_form_details_desc=Enter information about the web form you want to create. create_form_form_details_step1_desc=Select XML schema to use create_form_form_details_step2_desc=Specify details for new form. +create_form_form_details_no_elements_in_schema=This schema does not contain any element declarations. A schema must contain at least one element declaration in order to generate a form. create_form_form_details_no_schema_selected= create_form_configure_rendering_engine_templates_title=Configure Templates create_form_configure_rendering_engine_templates_step_title=Step Two - Configure Templates @@ -847,6 +848,7 @@ website_details=Web Project Details create_website_step1_title=Step One - Web Project Details create_website_step1_desc=Enter the information about the web project. website_dnsname=DNS name +website_deployto=Deploy To validation_invalid_dns_name=Invalid website DNS name, a minimum of 2 alpha-numeric characters are accepted. website_webapp=Default Webapp website_selected_forms=Selected Web Content Forms @@ -957,6 +959,7 @@ create_form_content=Create Content recent_snapshots=Recent Snapshots snapshot_revert=Revert snapshot_preview=Preview +snapshot_deploy=Deploy webapp_current=Current Webapp Folder sandbox_no_modified_items=No modified items sandbox_no_web_forms=No Web Forms available @@ -1018,6 +1021,30 @@ revert_selected_confirm=Are you sure you want to undo the changes to the selecte revert_all_title=Undo All Items revert_all_desc=To undo the changes to all the files in the sandbox, click OK. revert_all_confirm=Are you sure you want to undo the changes to all files in the sandbox? +deploy_title=Deploy Snapshot +deploy_desc=Select the servers to deploy to and click OK. +deploy_destination=Select the destination servers to deploy to +deploy_status=Snapshot {0} is being deployed in the background, refresh this page until the ''View Deployment Report'' link appears. +deploying=Deploying... +deploy_successful=Deployment Successful +deploy_failed=Deployment Failed +deploy_server_not_selected=This server has not been selected as the snapshot has already been deployed successfully. +deploy_started=Started +deploy_finished=Finished +deployed_by=By +deployment_report_action=View Deployment +deployment_report_title=View Deployment Report +deployment_report_title_for=View Deployment Report For Snaphot {0} +deployment_report_desc=View deployment details for each of the servers deployed to. +monitor_deployment_title=Monitor Deployment +monitor_deployment_desc=Monitors the progress of a snapshot deployment to one or more servers. +deploy_status_in_progress=IN PROGRESS +deploy_status_live=LIVE +deploy_status_failed=FAILED +deploy_status_partial=PARTIAL FAILURE +reason=Reason +snapshot=Snapshot +deploy_to_help=A comma separated list of servers to deploy the website to. Each entry can be a host name or an IP address and may also contain a port number. If a port number is not specified the default of {0} will be used. # New User Wizard messages new_user_title=New User Wizard diff --git a/config/alfresco/web-client-config-dialogs.xml b/config/alfresco/web-client-config-dialogs.xml index 2721e2723e..7256afd7ce 100644 --- a/config/alfresco/web-client-config-dialogs.xml +++ b/config/alfresco/web-client-config-dialogs.xml @@ -197,6 +197,21 @@ + + + + + + diff --git a/config/alfresco/web-client-config-properties.xml b/config/alfresco/web-client-config-properties.xml index 0b4e98ad5a..8e1dd14b43 100644 --- a/config/alfresco/web-client-config-properties.xml +++ b/config/alfresco/web-client-config-properties.xml @@ -451,6 +451,7 @@ + diff --git a/config/alfresco/web-client-config-wcm.xml b/config/alfresco/web-client-config-wcm.xml index 808a90977e..494f229315 100644 --- a/config/alfresco/web-client-config-wcm.xml +++ b/config/alfresco/web-client-config-wcm.xml @@ -8,6 +8,20 @@ wcmwf:submit + + + + + admin + + admin + + 50500 + + 5 + + 30 + diff --git a/source/java/org/alfresco/web/bean/actions/handlers/CopyToWebProjectHandler.java b/source/java/org/alfresco/web/bean/actions/handlers/CopyToWebProjectHandler.java index b9cac22e0d..c43686c3c6 100644 --- a/source/java/org/alfresco/web/bean/actions/handlers/CopyToWebProjectHandler.java +++ b/source/java/org/alfresco/web/bean/actions/handlers/CopyToWebProjectHandler.java @@ -98,7 +98,7 @@ public class CopyToWebProjectHandler extends BaseActionHandler folder = avmPath.substring(avmPath.indexOf(AVMConstants.DIR_ROOT)+4); // get the destination web project name - NodeRef webProjectNode = AVMConstants.getWebProjectNode(avmPath); + NodeRef webProjectNode = AVMConstants.getWebProjectNodeFromPath(avmPath); webProject = Repository.getNameForNode( Repository.getServiceRegistry(context).getNodeService(), webProjectNode); } diff --git a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java index f35b21b746..59491edc43 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java @@ -41,6 +41,7 @@ import javax.faces.event.ActionEvent; import javax.faces.model.SelectItem; import javax.transaction.UserTransaction; +import org.alfresco.model.WCMAppModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.actions.AVMRevertStoreAction; import org.alfresco.repo.avm.actions.AVMUndoSandboxListAction; @@ -49,13 +50,17 @@ import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncService; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.Pair; +import org.alfresco.util.VirtServerUtils; import org.alfresco.web.app.Application; import org.alfresco.web.app.context.IContextListener; import org.alfresco.web.app.context.UIContextService; @@ -67,7 +72,6 @@ import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.repository.User; import org.alfresco.web.bean.wizard.WizardManager; -import org.alfresco.web.config.ClientConfigElement; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.IBreadcrumbHandler; import org.alfresco.web.ui.common.component.UIActionLink; @@ -80,8 +84,6 @@ import org.alfresco.web.ui.wcm.component.UIUserSandboxes; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.alfresco.util.VirtServerUtils; - /** * Bean backing up the AVM specific browse screens * @@ -93,6 +95,9 @@ public class AVMBrowseBean implements IContextListener private static final Log LOGGER = LogFactory.getLog(AVMBrowseBean.class); + private static final String REQUEST_BEEN_DEPLOYED_KEY = "_alfBeenDeployedEvaluated"; + private static final String REQUEST_BEEN_DEPLOYED_RESULT = "_alfBeenDeployedResult"; + private static final String MSG_REVERT_SUCCESS = "revert_success"; private static final String MSG_REVERT_SANDBOX = "revert_sandbox_success"; private static final String MSG_SANDBOXTITLE = "sandbox_title"; @@ -100,9 +105,9 @@ public class AVMBrowseBean implements IContextListener private static final String MSG_CREATED_ON = "store_created_on"; private static final String MSG_CREATED_BY = "store_created_by"; private static final String MSG_WORKING_USERS = "store_working_users"; - private static final String MSG_SUBMIT_SUCCESS = "submit_success"; - private static final String MSG_SUBMITALL_SUCCESS = "submitall_success"; - private static final String MSG_SUBMITSELECTED_SUCCESS = "submitselected_success"; +// private static final String MSG_SUBMIT_SUCCESS = "submit_success"; +// private static final String MSG_SUBMITALL_SUCCESS = "submitall_success"; +// private static final String MSG_SUBMITSELECTED_SUCCESS = "submitselected_success"; /** Component id the status messages are tied too */ static final String COMPONENT_SANDBOXESPANEL = "sandboxes-panel"; @@ -135,6 +140,9 @@ public class AVMBrowseBean implements IContextListener /** flag to indicate that all items in the sandbox are involved in the current action */ private boolean allItemsAction = false; + /** list of the deployment monitor ids currently executing */ + private List deploymentMonitorIds = new ArrayList(); + /* component references */ private UIRichList foldersRichList; private UIRichList filesRichList; @@ -429,6 +437,22 @@ public class AVMBrowseBean implements IContextListener this.webapp = webapp; } + /** + * @return Returns the list of deployment monitor ids currently executing + */ + public List getDeploymentMonitorIds() + { + return this.deploymentMonitorIds; + } + + /** + * @param deploymentMonitorIds Sets the list of deployment monitor ids + */ + public void setDeploymentMonitorIds(List deploymentMonitorIds) + { + this.deploymentMonitorIds = deploymentMonitorIds; + } + /** * @return list of available root webapp folders for this Web project */ @@ -639,6 +663,39 @@ public class AVMBrowseBean implements IContextListener return this.getWebProject().isManager(user); } + /** + * @return true if the website has had a deployment attempt + */ + @SuppressWarnings("unchecked") + public boolean getHasDeployBeenAttempted() + { + // NOTE: This method is called a lot as it is referenced as a value binding + // expression in a 'rendered' attribute, we therefore cache the result + // on a per request basis + + List deployReportRefs = null; + + FacesContext context = FacesContext.getCurrentInstance(); + Map request = context.getExternalContext().getRequestMap(); + if (request.get(REQUEST_BEEN_DEPLOYED_KEY) == null) + { + // see if there are any deployment reports for the site + NodeRef webProjectRef = this.getWebsite().getNodeRef(); + deployReportRefs = this.nodeService.getChildAssocs(webProjectRef, + WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + + // add a placeholder object in the request so we don't evaluate this again for this request + request.put(REQUEST_BEEN_DEPLOYED_KEY, Boolean.TRUE); + request.put(REQUEST_BEEN_DEPLOYED_RESULT, deployReportRefs); + } + else + { + deployReportRefs = (List)request.get(REQUEST_BEEN_DEPLOYED_RESULT); + } + + return (deployReportRefs != null && deployReportRefs.size() > 0); + } + /** * @return Map of avm node objects representing the folders with the current website space */ @@ -675,8 +732,6 @@ public class AVMBrowseBean implements IContextListener tx = Repository.getUserTransaction(context, true); tx.begin(); - int rootPathIndex = AVMConstants.buildSandboxRootPath(getSandbox()).length(); - Map nodes = this.avmService.getDirectoryListing(-1, getCurrentPath()); this.files = new ArrayList(nodes.size()); this.folders = new ArrayList(nodes.size()); @@ -1006,8 +1061,6 @@ public class AVMBrowseBean implements IContextListener */ public void createFormContent(ActionEvent event) { - UIActionLink link = (UIActionLink)event.getComponent(); - // setup the correct sandbox for the create action setupSandboxAction(event); @@ -1106,6 +1159,7 @@ public class AVMBrowseBean implements IContextListener /** * Class to handle breadcrumb interaction for AVM page */ + @SuppressWarnings("serial") private class AVMBreadcrumbHandler implements IBreadcrumbHandler { private String path; @@ -1115,6 +1169,7 @@ public class AVMBrowseBean implements IContextListener this.path = path; } + @SuppressWarnings("unchecked") public String navigationOutcome(UIBreadcrumb breadcrumb) { setCurrentPath(path); diff --git a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java index f4b4254f45..c5b8a320e6 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java @@ -25,7 +25,6 @@ package org.alfresco.web.bean.wcm; import java.text.MessageFormat; -import java.util.List; import java.util.Map; import java.util.Stack; import java.util.regex.Matcher; @@ -33,19 +32,19 @@ import java.util.regex.Pattern; import javax.faces.context.FacesContext; +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigService; import org.alfresco.config.JNDIConstants; import org.alfresco.mbeans.VirtServerRegistry; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMNotFoundException; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; -import org.alfresco.service.ServiceRegistry; import org.alfresco.util.VirtServerUtils; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; @@ -276,6 +275,175 @@ public final class AVMConstants return (otherStore + ':' + AVMConstants.getStoreRelativePath(avmPath)); } + /** + * Returns the username to connect as on the remote machine being deployed to + *

+ * This value is read from the <wcm> config section in + * web-client-config-wcm.xml + *

+ * + * @return Username for remote machine + */ + public static String getRemoteDeploymentUsername() + { + String username = "admin"; + + ConfigElement deploymentConfig = getDeploymentConfig(); + if (deploymentConfig != null) + { + ConfigElement elem = deploymentConfig.getChild("remote-username"); + if (elem != null) + { + username = elem.getValue(); + } + } + + return username; + } + + /** + * Returns the password to use on the remote machine being deployed to + *

+ * This value is read from the <wcm> config section in + * web-client-config-wcm.xml + *

+ * + * @return Password for remote machine + */ + public static String getRemoteDeploymentPassword() + { + String password = "admin"; + + ConfigElement deploymentConfig = getDeploymentConfig(); + if (deploymentConfig != null) + { + ConfigElement elem = deploymentConfig.getChild("remote-password"); + if (elem != null) + { + password = elem.getValue(); + } + } + + return password; + } + + /** + * Returns the number of seconds between each call back to the server to + * obtain the latest status of an in progress deployment. + *

+ * This value is read from the <wcm> config section in + * web-client-config-wcm.xml + *

+ * + * @return Number of seconds between each call to the server (in seconds). + * The default is 5. + */ + public static int getRemoteDeploymentPollingFrequency() + { + int pollFreq = 5; + + ConfigElement deploymentConfig = getDeploymentConfig(); + if (deploymentConfig != null) + { + ConfigElement elem = deploymentConfig.getChild("progress-polling-frequency"); + if (elem != null) + { + try + { + int value = Integer.parseInt(elem.getValue()); + if (value > 0) + { + pollFreq = value; + } + } + catch (NumberFormatException nfe) + { + // do nothing, just use the default + } + } + } + + return pollFreq; + } + + /** + * Returns the default RMI registry port to use when one is not supplied + * for target deployment servers. + *

+ * This value is read from the <wcm> config section in + * web-client-config-wcm.xml + *

+ * + * @return The remote RMI registry port to use for deployments. + * The default is 50500. + */ + public static int getRemoteRMIRegistryPort() + { + int rmiPort = 50500; + + ConfigElement deploymentConfig = getDeploymentConfig(); + if (deploymentConfig != null) + { + ConfigElement elem = deploymentConfig.getChild("remote-rmi-port"); + if (elem != null) + { + try + { + int value = Integer.parseInt(elem.getValue()); + if (value > 0) + { + rmiPort = value; + } + } + catch (NumberFormatException nfe) + { + // do nothing, just use the default + } + } + } + + return rmiPort; + } + + /** + * Returns the delay (in seconds) to apply to the start of a deployment + * operation (mainly for demo and testing purposes). + *

+ * This value is read from the <wcm> config section in + * web-client-config-wcm.xml + *

+ * + * @return The delay to use at the start of a deployment. + * The default is 30. + */ + public static int getRemoteDeploymentDelay() + { + int delay = 30; + + ConfigElement deploymentConfig = getDeploymentConfig(); + if (deploymentConfig != null) + { + ConfigElement elem = deploymentConfig.getChild("delay"); + if (elem != null) + { + try + { + int value = Integer.parseInt(elem.getValue()); + if (value > 0) + { + delay = value; + } + } + catch (NumberFormatException nfe) + { + // do nothing, just use the default + } + } + } + + return delay; + } + /** * Returns the main staging store name for the specified store id. * @@ -435,8 +603,17 @@ public final class AVMConstants config.getWCMPort()); } - public static String buildWebappUrl(final String store, - final String webapp) + public static String buildWebappUrl(final String avmPath) + { + if (avmPath == null || avmPath.length() == 0) + { + throw new IllegalArgumentException("AVM path is mandatory."); + } + return AVMConstants.buildWebappUrl(AVMConstants.getStoreName(avmPath), + AVMConstants.getWebapp(avmPath)); + } + + public static String buildWebappUrl(final String store, final String webapp) { if (webapp == null || webapp.length() == 0) { @@ -485,9 +662,11 @@ public final class AVMConstants { throw new IllegalArgumentException("Asset path is mandatory."); } - if (assetPath.startsWith('/' + JNDIConstants.DIR_DEFAULT_WWW + '/' + JNDIConstants.DIR_DEFAULT_APPBASE)) + if (assetPath.startsWith('/' + JNDIConstants.DIR_DEFAULT_WWW + + '/' + JNDIConstants.DIR_DEFAULT_APPBASE)) { - assetPath = assetPath.substring(('/' + JNDIConstants.DIR_DEFAULT_WWW + '/' + JNDIConstants.DIR_DEFAULT_APPBASE).length()); + assetPath = assetPath.substring(('/' + JNDIConstants.DIR_DEFAULT_WWW + + '/' + JNDIConstants.DIR_DEFAULT_APPBASE).length()); } if (assetPath.startsWith('/' + DIR_ROOT)) { @@ -639,19 +818,27 @@ public final class AVMConstants * @return The NodeRef representing the Web Project the path is from or null * if it could not be determined */ - public static NodeRef getWebProjectNode(final String absoluteAVMPath) + public static NodeRef getWebProjectNodeFromPath(final String absoluteAVMPath) + { + return getWebProjectNodeFromStore(AVMConstants.getStoreName(absoluteAVMPath)); + } + + /** + * Returns the NodeRef that represents the given avm store + * + * @param storeName The store name from which to determine the Web Project + * @return The NodeRef representing the Web Project the store is from or null + * if it could not be determined + */ + public static NodeRef getWebProjectNodeFromStore(final String storeName) { // get services FacesContext fc = FacesContext.getCurrentInstance(); SearchService searchService = Repository.getServiceRegistry(fc).getSearchService(); - // get the store name - String storeName = AVMConstants.getStoreName(absoluteAVMPath); - String storeId = AVMConstants.getStoreId(storeName); - // construct the query String path = Application.getRootPath(fc) + "/" + Application.getWebsitesFolderName(fc) + "/*"; - String query = "PATH:\"/" + path + "\" AND @wca\\:avmstore:\"" + storeId + "\""; + String query = "PATH:\"/" + path + "\" AND @wca\\:avmstore:\"" + storeName + "\""; NodeRef webProjectNode = null; ResultSet results = null; @@ -725,16 +912,15 @@ public final class AVMConstants { if (force || VirtServerUtils.requiresUpdateNotification(path)) { - VirtServerRegistry vServerRegistry = AVMConstants.getVirtServerRegistry(); - - int webappIndex = path.indexOf( '/', - path.indexOf(JNDIConstants.DIR_DEFAULT_APPBASE) + - JNDIConstants.DIR_DEFAULT_APPBASE.length() + 1); + final int webappIndex = path.indexOf('/', + path.indexOf(JNDIConstants.DIR_DEFAULT_APPBASE) + + JNDIConstants.DIR_DEFAULT_APPBASE.length() + 1); if (webappIndex != -1) { path = path.substring(0, webappIndex); } + final VirtServerRegistry vServerRegistry = AVMConstants.getVirtServerRegistry(); vServerRegistry.updateAllWebapps(-1, path, true); } } @@ -749,15 +935,15 @@ public final class AVMConstants { if (force || VirtServerUtils.requiresUpdateNotification(path)) { - VirtServerRegistry vServerRegistry = AVMConstants.getVirtServerRegistry(); - - int webappIndex = path.indexOf( '/', path.indexOf(JNDIConstants.DIR_DEFAULT_APPBASE) + - JNDIConstants.DIR_DEFAULT_APPBASE.length() + 1); + final int webappIndex = path.indexOf('/', + path.indexOf(JNDIConstants.DIR_DEFAULT_APPBASE) + + JNDIConstants.DIR_DEFAULT_APPBASE.length() + 1); if (webappIndex != -1) { path = path.substring(0, webappIndex); } + final VirtServerRegistry vServerRegistry = AVMConstants.getVirtServerRegistry(); vServerRegistry.removeAllWebapps(-1, path, true); } } @@ -769,6 +955,20 @@ public final class AVMConstants return (VirtServerRegistry)ac.getBean(BEAN_VIRT_SERVER_REGISTRY); } + private static ConfigElement getDeploymentConfig() + { + if (deploymentConfig == null) + { + ConfigService cfgService = Application.getConfigService(FacesContext.getCurrentInstance()); + ConfigElement wcmCfg = cfgService.getGlobalConfig().getConfigElement("wcm"); + if (wcmCfg != null) + { + deploymentConfig = wcmCfg.getChild("deployment"); + } + } + + return deploymentConfig; + } // Component Separator. private static final String STORE_SEPARATOR = "--"; @@ -820,4 +1020,6 @@ public final class AVMConstants private final static Pattern SANDBOX_RELATIVE_PATH_PATTERN = Pattern.compile("([^:]+:/" + JNDIConstants.DIR_DEFAULT_WWW + "/" + JNDIConstants.DIR_DEFAULT_APPBASE + ")(.*)"); + + private static ConfigElement deploymentConfig = null; } diff --git a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java index baf8e02e3a..5f35be646d 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java @@ -414,7 +414,8 @@ public class CreateFormWizard case 1: { return (this.getSchemaFileName() == null || - this.getSchemaFileName().length() == 0); + this.getSchemaFileName().length() == 0 || + this.getSchemaRootElementNameChoices().size() == 0); } default: { diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java index 1158793340..55a9194d8b 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java @@ -25,6 +25,7 @@ package org.alfresco.web.bean.wcm; import java.io.Serializable; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -75,10 +76,7 @@ import org.apache.commons.logging.LogFactory; */ public class CreateWebsiteWizard extends BaseWizardBean { - private static final String MSG_DESCRIPTION = "description"; - private static final String MSG_NAME = "name"; private static final String MSG_USERROLES = "create_website_summary_users"; - private static final String MSG_NONE = "workflow_not_set"; private static final String COMPONENT_FORMLIST = "form-list"; private static final String COMPONENT_WORKFLOWLIST = "workflow-list"; @@ -96,6 +94,7 @@ public class CreateWebsiteWizard extends BaseWizardBean protected String name; protected String description; protected String webapp = WEBAPP_DEFAULT; + protected List deployTo; protected String websitesFolderId = null; @@ -145,6 +144,7 @@ public class CreateWebsiteWizard extends BaseWizardBean this.dnsName = null; this.title = null; this.description = null; + this.deployTo = null; this.formsDataModel = null; this.forms = new ArrayList(8); this.workflowsDataModel = null; @@ -187,6 +187,9 @@ public class CreateWebsiteWizard extends BaseWizardBean String webapp = (this.webapp != null && this.webapp.length() != 0) ? this.webapp : WEBAPP_DEFAULT; this.nodeService.setProperty(nodeRef, WCMAppModel.PROP_DEFAULTWEBAPP, webapp); + // set the list of servers to deploy to + this.nodeService.setProperty(nodeRef, WCMAppModel.PROP_DEPLOYTO, (Serializable)this.deployTo); + // call a delegate wizard bean to provide invite user functionality InviteWebsiteUsersWizard wiz = getInviteUsersWizard(); wiz.setNode(new Node(nodeRef)); @@ -469,10 +472,39 @@ public class CreateWebsiteWizard extends BaseWizardBean { this.webapp = webapp; } + + /** + * @return The comma separated list of servers to deploy to + */ + public List getDeployTo() + { + return this.deployTo; + } + /** + * @param deployTo The comma separated list of servers to deploy to + */ + public void setDeployTo(List deployTo) + { + this.deployTo = deployTo; + } + + /** + * @return the deploy to help text that gets displayed if the user + * clicks the Help icon + */ + public String getDeployToHelp() + { + String pattern = Application.getMessage(FacesContext.getCurrentInstance(), + "deploy_to_help"); + String defaultPort = Integer.toString(AVMConstants.getRemoteRMIRegistryPort()); + return MessageFormat.format(pattern, new Object[] {defaultPort}); + } + /** * @return summary text for the wizard */ + @SuppressWarnings("unchecked") public String getSummary() { FacesContext fc = FacesContext.getCurrentInstance(); @@ -506,6 +538,7 @@ public class CreateWebsiteWizard extends BaseWizardBean /** * @return the invited users for the project - as UserWrapper instances */ + @SuppressWarnings("unchecked") public List getInvitedUsers() { final FacesContext fc = FacesContext.getCurrentInstance(); diff --git a/source/java/org/alfresco/web/bean/wcm/DeploySnapshotDialog.java b/source/java/org/alfresco/web/bean/wcm/DeploySnapshotDialog.java new file mode 100644 index 0000000000..d0bbbb77e3 --- /dev/null +++ b/source/java/org/alfresco/web/bean/wcm/DeploySnapshotDialog.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.wcm; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.faces.context.FacesContext; + +import org.alfresco.model.WCMAppModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.avm.actions.AVMDeploySnapshotAction; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.action.ActionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.web.bean.dialog.BaseDialogBean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Deploys a web project snapshot to one or more remote servers. + * + * @author gavinc + */ +public class DeploySnapshotDialog extends BaseDialogBean +{ + protected int versionToDeploy; + protected String[] deployTo; + protected NodeRef websiteRef; + protected NodeRef webProjectRef; + + protected AVMBrowseBean avmBrowseBean; + protected ActionService actionService; + + private static final Log logger = LogFactory.getLog(DeploySnapshotDialog.class); + + // ------------------------------------------------------------------------------ + // Dialog implementation + + @Override + public void init(Map parameters) + { + super.init(parameters); + + // setup context for dialog + this.deployTo = null; + this.versionToDeploy = Integer.parseInt(parameters.get("version")); + this.avmBrowseBean.getDeploymentMonitorIds().clear(); + this.webProjectRef = this.avmBrowseBean.getWebsite().getNodeRef(); + String stagingStore = AVMConstants.buildSandboxRootPath(this.avmBrowseBean.getStagingStore()); + this.websiteRef = AVMNodeConverter.ToNodeRef(this.versionToDeploy, stagingStore); + + if (logger.isDebugEnabled()) + logger.debug("Initialising dialog to deploy version " + this.versionToDeploy + + " of " + this.websiteRef.toString()); + } + + @SuppressWarnings("unchecked") + @Override + protected String finishImpl(FacesContext context, String outcome) throws Exception + { + // put all the selected servers to deploy to into a list + List selectedDeployTo = new ArrayList(); + if (this.deployTo != null) + { + for (int x = 0; x < this.deployTo.length; x++) + { + selectedDeployTo.add(this.deployTo[x].trim()); + } + } + + if (logger.isDebugEnabled()) + logger.debug("Executing deployment of " + this.websiteRef.toString() + + " to servers: " + selectedDeployTo); + + if (selectedDeployTo.size() > 0) + { + // TODO: move any existing deployment reports to a node representing the + // snapshot, we can then keep a history of deployment attempts on a + // per snapshot basis. + + NodeRef webProjectRef = this.avmBrowseBean.getWebsite().getNodeRef(); + List allDeployToServers = (List)nodeService.getProperty(webProjectRef, + WCMAppModel.PROP_DEPLOYTO); + List deployReportRefs = nodeService.getChildAssocs( + webProjectRef, WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : deployReportRefs) + { + NodeRef report = ref.getChildRef(); + + String server = (String)this.nodeService.getProperty(report, WCMAppModel.PROP_DEPLOYSERVER); + int version = (Integer)this.nodeService.getProperty(report, WCMAppModel.PROP_DEPLOYVERSION); + if ((version == this.versionToDeploy && selectedDeployTo.contains(server)) || + (version != this.versionToDeploy) || (allDeployToServers.contains(server) == false)) + { + // cascade delete will take care of child-child relationships + this.nodeService.removeChild(webProjectRef, report); + + if (logger.isDebugEnabled()) + logger.debug("Removed exisiting deployment report for server: " + server); + } + } + + // update the selecteddeployto property with list of servers selected + this.nodeService.setProperty(webProjectRef, WCMAppModel.PROP_SELECTEDDEPLOYTO, + (Serializable)selectedDeployTo); + // update the selecteddeployversion property with the selected snapshot version + this.nodeService.setProperty(webProjectRef, WCMAppModel.PROP_SELECTEDDEPLOYVERSION, + this.versionToDeploy); + + // execute a deploy action for each of the selected remote servers asynchronously + for (String targetServer : selectedDeployTo) + { + if (targetServer.length() > 0) + { + // create a deployment monitor object, store in the session, + // add to avm browse bean and pass to action + DeploymentMonitor monitor = new DeploymentMonitor( + this.websiteRef, targetServer, versionToDeploy); + context.getExternalContext().getSessionMap().put(monitor.getId(), monitor); + this.avmBrowseBean.getDeploymentMonitorIds().add(monitor.getId()); + + // create the action + Map args = new HashMap(1, 1.0f); + args.put(AVMDeploySnapshotAction.PARAM_WEBSITE, webProjectRef); + args.put(AVMDeploySnapshotAction.PARAM_TARGET_SERVER, targetServer); + args.put(AVMDeploySnapshotAction.PARAM_DEFAULT_RMI_PORT, + AVMConstants.getRemoteRMIRegistryPort()); + args.put(AVMDeploySnapshotAction.PARAM_REMOTE_USERNAME, + AVMConstants.getRemoteDeploymentUsername()); + args.put(AVMDeploySnapshotAction.PARAM_REMOTE_PASSWORD, + AVMConstants.getRemoteDeploymentPassword()); + args.put(AVMDeploySnapshotAction.PARAM_CALLBACK, monitor); + args.put(AVMDeploySnapshotAction.PARAM_DELAY, + AVMConstants.getRemoteDeploymentDelay()); + Action action = this.actionService.createAction(AVMDeploySnapshotAction.NAME, args); + this.actionService.executeAction(action, this.websiteRef, false, true); + } + } + + // close this dialog and immediately open the monitorDeployment dialog + return "dialog:monitorDeployment"; + } + else + { + return outcome; + } + } + + @Override + public boolean getFinishButtonDisabled() + { + return false; + } + + @Override + public String getCancelButtonLabel() + { + return super.getCancelButtonLabel(); + } + + // ------------------------------------------------------------------------------ + // Bean getters and setters + + /** + * @param avmBrowseBean The AVM BrowseBean to set + */ + public void setAvmBrowseBean(AVMBrowseBean avmBrowseBean) + { + this.avmBrowseBean = avmBrowseBean; + } + + /** + * @param actionService The actionService to set. + */ + public void setActionService(ActionService actionService) + { + this.actionService = actionService; + } + + /** + * Sets the list of remote servers to deploy to + * + * @param deployTo String array of servers to deploy to + */ + public void setDeployTo(String[] deployTo) + { + this.deployTo = deployTo; + } + + /** + * Returns the remote servers to deploy to as an array + * + * @return String array of servers to deploy to + */ + public String[] getDeployTo() + { + return this.deployTo; + } + + /** + * @return The NodeRef of the web project the deployment reports are being shown for + */ + public NodeRef getWebProjectRef() + { + return this.webProjectRef; + } + + /** + * @return The version of the snapshot to deploy + */ + public int getSnapshotVersion() + { + return this.versionToDeploy; + } +} diff --git a/source/java/org/alfresco/web/bean/wcm/DeploymentMonitor.java b/source/java/org/alfresco/web/bean/wcm/DeploymentMonitor.java new file mode 100644 index 0000000000..727a8650e6 --- /dev/null +++ b/source/java/org/alfresco/web/bean/wcm/DeploymentMonitor.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.wcm; + +import java.io.Serializable; + +import org.alfresco.service.cmr.avm.deploy.DeploymentCallback; +import org.alfresco.service.cmr.avm.deploy.DeploymentEvent; +import org.alfresco.service.cmr.avm.deploy.DeploymentEvent.Type; +import org.alfresco.service.cmr.repository.NodeRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Object used to monitor the deployment of a snapshot to a remote + * server. These objects are typically stored in the HTTP session + * and accessed by an AJAX callback to provide progress feedback + * for the deployment. + * + * @author gavinc + */ +@SuppressWarnings("serial") +public class DeploymentMonitor implements DeploymentCallback, Serializable +{ + private String id; + private NodeRef website; + private String targetServer; + private int snapshotVersion; + private boolean started = false; + private boolean finished = false; + private boolean successful = false; + + private static Log logger = LogFactory.getLog(DeploymentMonitor.class); + private static final String ID_PREFIX = "_depmon_"; + + /** + * Default constructor + */ + public DeploymentMonitor(NodeRef website, String targetServer, int snapshotVersion) + { + this.id = ID_PREFIX + Long.toString(System.currentTimeMillis()) + this.hashCode(); + this.website = website; + this.targetServer = targetServer; + this.snapshotVersion = snapshotVersion; + } + + // ------------------------------------------------------------------------------ + // DeploymentCallback implementation + + public void eventOccurred(DeploymentEvent event) + { + // we're only interested in the start and end event for the time + // being, we'll add support for returning item by item progress + // at a later date. + if (event.getType().equals(Type.START)) + { + this.started = true; + } + else if (event.getType().equals(Type.END)) + { + // if we get the END event the deployment was successful + this.successful = true; + this.finished = true; + } + + if (logger.isDebugEnabled()) + logger.debug(this.targetServer + ": " + event.getType() + + " " + event.getDestination()); + } + + /** + * Informs the monitor an error occurred during deployment + * + * @param err The error that caused the deployment to fail + */ + public void errorOccurred(Throwable err) + { + if (logger.isDebugEnabled()) + logger.debug(this.targetServer + ": ERROR: " + err.getMessage()); + + this.successful = false; + this.finished = true; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (id=").append(this.id); + buffer.append(" website=").append(this.website); + buffer.append(" targetServer=").append(this.targetServer); + buffer.append(" snapshotVersion=").append(this.snapshotVersion); + buffer.append(" started=").append(this.started); + buffer.append(" finished=").append(this.finished); + buffer.append(" successful=").append(this.successful).append(")"); + return buffer.toString(); + } + + public String toXML() + { + StringBuilder buffer = new StringBuilder(""); + return buffer.toString(); + } + + // ------------------------------------------------------------------------------ + // Getters and setters + + /** + * @return The id for this deployment monitor + */ + public String getId() + { + return this.id; + } + + /** + * @return The NodeRef representation of the website being deployed + */ + public NodeRef getWebsite() + { + return this.website; + } + + /** + * @return The target server for this deployment + */ + public String getTargetServer() + { + return this.targetServer; + } + + /** + * @return The snapshot version being deployed + */ + public int getSnapshotVersion() + { + return this.snapshotVersion; + } + + /** + * @return true if the deployment has started + */ + public boolean isStarted() + { + return this.started; + } + + /** + * @return true if the deployment has finished + */ + public boolean isFinished() + { + return this.finished; + } + + /** + * @return true if the deployment was successful, + * only reliable once isFinished returns true. + */ + public boolean isSuccessful() + { + return this.successful; + } +} diff --git a/source/java/org/alfresco/web/bean/wcm/DeploymentProgressBean.java b/source/java/org/alfresco/web/bean/wcm/DeploymentProgressBean.java new file mode 100644 index 0000000000..8b2bb64f7b --- /dev/null +++ b/source/java/org/alfresco/web/bean/wcm/DeploymentProgressBean.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.wcm; + +import java.io.IOException; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Bean used by the AJAX callback from the monitor deployment dialog + * to track progress of deployments. + * + * @author gavinc + */ +public class DeploymentProgressBean +{ + private static Log logger = LogFactory.getLog(DeploymentProgressBean.class); + + public void getStatus() throws IOException + { + FacesContext context = FacesContext.getCurrentInstance(); + ResponseWriter out = context.getResponseWriter(); + + Map params = context.getExternalContext().getRequestParameterMap(); + String monitorIds = (String)params.get("ids"); + + if (logger.isDebugEnabled()) + logger.debug("Retrieving progress status for ids: " + monitorIds); + + if (monitorIds != null && monitorIds.length() > 0) + { + StringBuilder xml = new StringBuilder(""); + xml.append(""); + + StringTokenizer tokenizer = new StringTokenizer(monitorIds, ","); + while (tokenizer.hasMoreTokens()) + { + String id = tokenizer.nextToken().trim(); + + // try and find the deployment monitor object in the session + DeploymentMonitor monitor = (DeploymentMonitor)context.getExternalContext(). + getSessionMap().get(id); + + if (monitor != null) + { + if (logger.isDebugEnabled()) + logger.debug("Found monitor object for id '" + id + "': " + monitor); + + xml.append(monitor.toXML()); + + // cleanup the monitor object from the session if it has completed + if (monitor.isFinished()) + { + context.getExternalContext().getSessionMap().remove(id); + } + } + } + + xml.append(""); + + // send the generated XML back to the tree + out.write(xml.toString()); + + if (logger.isDebugEnabled()) + logger.debug("returning XML: " + xml.toString()); + } + } +} diff --git a/source/java/org/alfresco/web/bean/wcm/EditWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/EditWebsiteWizard.java index 196fed3650..613052dc33 100644 --- a/source/java/org/alfresco/web/bean/wcm/EditWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/EditWebsiteWizard.java @@ -67,6 +67,7 @@ public class EditWebsiteWizard extends CreateWebsiteWizard { throw new IllegalArgumentException("Edit Web Project wizard requires action node context."); } + loadWebProjectModel(websiteRef); } @@ -78,11 +79,13 @@ public class EditWebsiteWizard extends CreateWebsiteWizard private void loadWebProjectModel(NodeRef nodeRef) { // simple properties - this.name = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); - this.title = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE); - this.description = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION); - this.dnsName = (String)this.nodeService.getProperty(nodeRef, WCMAppModel.PROP_AVMSTORE); - this.webapp = (String)this.nodeService.getProperty(nodeRef, WCMAppModel.PROP_DEFAULTWEBAPP); + Map props = this.nodeService.getProperties(nodeRef); + this.name = (String)props.get(ContentModel.PROP_NAME); + this.title = (String)props.get(ContentModel.PROP_TITLE); + this.description = (String)props.get(ContentModel.PROP_DESCRIPTION); + this.dnsName = (String)props.get(WCMAppModel.PROP_AVMSTORE); + this.webapp = (String)props.get(WCMAppModel.PROP_DEFAULTWEBAPP); + this.deployTo = (List)props.get(WCMAppModel.PROP_DEPLOYTO); // load the form templates List webFormRefs = this.nodeService.getChildAssocs( @@ -121,7 +124,6 @@ public class EditWebsiteWizard extends CreateWebsiteWizard } // the templates attached to the form - List engineTemplates = formImpl.getRenderingEngineTemplates(); List templateRefs = this.nodeService.getChildAssocs( formRef, WCMAppModel.ASSOC_WEBFORMTEMPLATE, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef tChildRef : templateRefs) @@ -178,6 +180,7 @@ public class EditWebsiteWizard extends CreateWebsiteWizard this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, this.name); this.nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, this.title); this.nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, this.description); + this.nodeService.setProperty(nodeRef, WCMAppModel.PROP_DEPLOYTO, (Serializable)this.deployTo); // clear the existing settings for forms, template and workflows - then the existing methods // can be used to apply the modified and previous settings from scratch diff --git a/source/java/org/alfresco/web/bean/wcm/MonitorDeploymentDialog.java b/source/java/org/alfresco/web/bean/wcm/MonitorDeploymentDialog.java new file mode 100644 index 0000000000..9a546803dd --- /dev/null +++ b/source/java/org/alfresco/web/bean/wcm/MonitorDeploymentDialog.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.wcm; + +import java.util.Map; + +import javax.faces.context.FacesContext; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.dialog.BaseDialogBean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Monitors the deployment of a web project snapshot to one or more remote servers. + * + * @author gavinc + */ +public class MonitorDeploymentDialog extends BaseDialogBean +{ + protected NodeRef webProjectRef; + + protected AVMBrowseBean avmBrowseBean; + + private static final Log logger = LogFactory.getLog(MonitorDeploymentDialog.class); + + // ------------------------------------------------------------------------------ + // Dialog implementation + + @Override + public void init(Map parameters) + { + super.init(parameters); + + // setup context for dialog + this.webProjectRef = this.avmBrowseBean.getWebsite().getNodeRef(); + + if (logger.isDebugEnabled()) + { + logger.debug("Initialising dialog to monitor deployment of " + + this.webProjectRef.toString()); + } + } + + @Override + protected String finishImpl(FacesContext context, String outcome) throws Exception + { + return outcome; + } + + @Override + protected String getDefaultCancelOutcome() + { + return "dialog:close:browseWebsite"; + } + + @Override + public String getCancelButtonLabel() + { + return Application.getMessage(FacesContext.getCurrentInstance(), "close"); + } + + // ------------------------------------------------------------------------------ + // Bean getters and setters + + /** + * @param avmBrowseBean The AVM BrowseBean to set + */ + public void setAvmBrowseBean(AVMBrowseBean avmBrowseBean) + { + this.avmBrowseBean = avmBrowseBean; + } + + /** + * @return The NodeRef of the web project the deployment reports are being shown for + */ + public NodeRef getWebProjectRef() + { + return this.webProjectRef; + } +} diff --git a/source/java/org/alfresco/web/bean/wcm/ViewDeploymentReportDialog.java b/source/java/org/alfresco/web/bean/wcm/ViewDeploymentReportDialog.java new file mode 100644 index 0000000000..b6223f05e8 --- /dev/null +++ b/source/java/org/alfresco/web/bean/wcm/ViewDeploymentReportDialog.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.wcm; + +import java.util.Map; + +import javax.faces.context.FacesContext; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.dialog.BaseDialogBean; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Views the deployment reports created as a result of the last deployment attempt + * + * @author gavinc + */ +public class ViewDeploymentReportDialog extends BaseDialogBean +{ + protected NodeRef webProjectRef; + protected Integer deployedVersion; + + protected AVMBrowseBean avmBrowseBean; + + private static final Log logger = LogFactory.getLog(ViewDeploymentReportDialog.class); + + // ------------------------------------------------------------------------------ + // Dialog implementation + + @Override + public void init(Map parameters) + { + super.init(parameters); + + this.webProjectRef = this.avmBrowseBean.getWebsite().getNodeRef(); + + if (logger.isDebugEnabled()) + logger.debug("Initialising dialog to view deployment report for " + + this.avmBrowseBean.getStagingStore()); + } + + @Override + public String getCancelButtonLabel() + { + return Application.getMessage(FacesContext.getCurrentInstance(), "close"); + } + + @Override + protected String finishImpl(FacesContext context, String outcome) throws Exception + { + return outcome; + } + + // ------------------------------------------------------------------------------ + // Bean getters and setters + + /** + * @return The NodeRef of the web project the deployment reports are being shown for + */ + public NodeRef getWebProjectRef() + { + return this.webProjectRef; + } + + /** + * @param avmBrowseBean The AVM BrowseBean instance to use + */ + public void setAvmBrowseBean(AVMBrowseBean avmBrowseBean) + { + this.avmBrowseBean = avmBrowseBean; + } +} diff --git a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java index 4d8997da1e..aa0d6ba571 100644 --- a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java @@ -23,6 +23,7 @@ package org.alfresco.web.forms; import freemarker.ext.dom.NodeModel; +import freemarker.cache.TemplateLoader; import freemarker.template.*; import java.io.*; import java.util.*; @@ -76,7 +77,37 @@ public class FreeMarkerRenderingEngine final Configuration cfg = new Configuration(); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + cfg.setTemplateLoader(new TemplateLoader() + { + public void closeTemplateSource(final Object templateSource) + throws IOException + { + ((InputStream)templateSource).close(); + } + + public Object findTemplateSource(final String name) + throws IOException + { + LOGGER.debug("request to load template " + name); + final RenderingEngine.TemplateResourceResolver trr = (RenderingEngine.TemplateResourceResolver) + model.get(RenderingEngineTemplateImpl.PROP_RESOURCE_RESOLVER); + + return trr.resolve(name); + } + + public long getLastModified(final Object templateSource) + { + // no caching for now... + return System.currentTimeMillis(); + } + + public Reader getReader(final Object templateSource, final String encoding) + throws IOException + { + return new InputStreamReader((InputStream)templateSource); + } + }); final Template t = new Template("freemarker_template", new InputStreamReader(ret.getInputStream()), cfg); @@ -139,6 +170,10 @@ public class FreeMarkerRenderingEngine " to " + m.getClass().getName() + "."); } } + else if (qn.equals(RenderingEngineTemplateImpl.PROP_RESOURCE_RESOLVER)) + { + continue; + } else { final String[] splitQName = QName.splitPrefixedQName(qn.toPrefixString()); diff --git a/source/java/org/alfresco/web/forms/RenderingEngine.java b/source/java/org/alfresco/web/forms/RenderingEngine.java index 6fb8bb4df1..8cb1ccae16 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngine.java +++ b/source/java/org/alfresco/web/forms/RenderingEngine.java @@ -24,6 +24,7 @@ package org.alfresco.web.forms; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; +import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; @@ -72,6 +73,15 @@ public interface RenderingEngine ///////////////////////////////////////////////////////////////////////////// + public interface TemplateResourceResolver + extends Serializable + { + public InputStream resolve(final String resourceName) + throws IOException; + } + + ///////////////////////////////////////////////////////////////////////////// + public final static QName ROOT_NAMESPACE = QName.createQName(null, "root_namespace"); diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java index d42a1fbff0..3159541a88 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java @@ -26,6 +26,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -82,6 +84,18 @@ public class RenderingEngineTemplateImpl { private static final Log LOGGER = LogFactory.getLog(RenderingEngineTemplateImpl.class); + private static final DynamicNamespacePrefixResolver namespacePrefixResolver = + new DynamicNamespacePrefixResolver(); + static + { + RenderingEngineTemplateImpl.namespacePrefixResolver.registerNamespace(NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); + } + + static final QName PROP_RESOURCE_RESOLVER = QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "resource_resolver", + namespacePrefixResolver); + private final NodeRef nodeRef; private final NodeRef renditionPropertiesNodeRef; @@ -324,7 +338,7 @@ public class RenderingEngineTemplateImpl avmService.setNodeProperties(rendition.getPath(), props); } - /** + /** * Builds the model to pass to the rendering engine. */ protected Map buildModel(final FormInstanceData formInstanceData, @@ -332,23 +346,60 @@ public class RenderingEngineTemplateImpl throws IOException, SAXException { - final DynamicNamespacePrefixResolver namespacePrefixResolver = - new DynamicNamespacePrefixResolver(); - namespacePrefixResolver.registerNamespace(NamespaceService.ALFRESCO_PREFIX, - NamespaceService.ALFRESCO_URI); - final String formInstanceDataAvmPath = formInstanceData.getPath(); final String renditionAvmPath = rendition.getPath(); final String parentPath = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]; final String sandboxUrl = AVMConstants.buildStoreUrl(formInstanceDataAvmPath); + final String webappUrl = AVMConstants.buildWebappUrl(formInstanceDataAvmPath); final HashMap model = new HashMap(); // add simple scalar parameters model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, "avm_sandbox_url", namespacePrefixResolver), sandboxUrl); - model.put(XSLTRenderingEngine.PROP_URI_RESOLVER_BASE_URI, - sandboxUrl); + model.put(RenderingEngineTemplateImpl.PROP_RESOURCE_RESOLVER, + new RenderingEngine.TemplateResourceResolver() + { + public InputStream resolve(final String name) + { + final NodeService nodeService = + RenderingEngineTemplateImpl.this.getServiceRegistry().getNodeService(); + final NodeRef parentNodeRef = + nodeService.getPrimaryParent(RenderingEngineTemplateImpl.this.getNodeRef()).getParentRef(); + LOGGER.debug("request to resolve resource " + name + + " webapp url is " + webappUrl + + " and data dictionary workspace is " + parentNodeRef); + final NodeRef result = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, name); + if (result != null) + { + final ContentService contentService = + RenderingEngineTemplateImpl.this.getServiceRegistry().getContentService(); + try + { + LOGGER.debug("found " + name + " in data dictonary: " + result); + return contentService.getReader(result, ContentModel.PROP_CONTENT).getContentInputStream(); + } + catch (Exception e) + { + LOGGER.debug(e); + } + } + + URI uri = null; + try + { + uri = new URI(webappUrl + (name.charAt(0) == '/' ? name : '/' + name)); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("loading " + uri); + return uri.toURL().openStream(); + } + catch (Exception e) + { + LOGGER.debug(e); + return null; + } + } + }); model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, "form_instance_data_file_name", namespacePrefixResolver), diff --git a/source/java/org/alfresco/web/forms/XMLUtil.java b/source/java/org/alfresco/web/forms/XMLUtil.java index 3bf864835e..1c56404ca0 100644 --- a/source/java/org/alfresco/web/forms/XMLUtil.java +++ b/source/java/org/alfresco/web/forms/XMLUtil.java @@ -38,10 +38,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; +import org.w3c.dom.*; import org.xml.sax.SAXException; /** @@ -76,7 +73,9 @@ public class XMLUtil final TransformerFactory tf = TransformerFactory.newInstance(); final Transformer t = tf.newTransformer(); t.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); - + t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + t.setOutputProperty(OutputKeys.METHOD, "xml"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("writing out a document for " + @@ -151,7 +150,6 @@ public class XMLUtil IOException { final DocumentBuilder db = XMLUtil.getDocumentBuilder(); - final Document result = db.parse(source); source.close(); return result; @@ -174,24 +172,44 @@ public class XMLUtil * @param to an ancestor of from which will be the root of the path * @return an xpath to to rooted at from. */ - public static String buildXPath(final Element from, final Element to) + public static String buildXPath(final Node from, final Element to) { String result = ""; Node tmp = from; do { - Node tmp2 = tmp; - int position = 1; - while (tmp2.getPreviousSibling() != null) + if (tmp instanceof Attr) { - if (tmp2.getNodeName().equals(tmp.getNodeName())) - { - position++; - } - tmp2 = tmp2.getPreviousSibling(); + assert result.length() == 0; + result = "@" + tmp.getNodeName(); + } + else if (tmp instanceof Element) + { + Node tmp2 = tmp; + int position = 1; + while (tmp2.getPreviousSibling() != null) + { + if (tmp2.getNodeName().equals(tmp.getNodeName())) + { + position++; + } + tmp2 = tmp2.getPreviousSibling(); + } + String part = tmp.getNodeName() + "[" + position + "]"; + result = "/" + part + result; + } + else if (tmp instanceof Text) + { + assert result.length() == 0; + result = "/text()"; + } + else + { + if (LOGGER.isDebugEnabled()) + { + throw new IllegalArgumentException("unsupported node type " + tmp); + } } - String part = tmp.getNodeName() + "[" + position + "]"; - result = result == null ? "/" + part : "/" + part + result; tmp = tmp.getParentNode(); } while (tmp != to.getParentNode() && tmp != null); diff --git a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java index 3e44300870..c6bf9873ff 100644 --- a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java @@ -27,6 +27,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.*; import javax.xml.parsers.DocumentBuilder; +import javax.xml.transform.ErrorListener; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; @@ -228,9 +229,6 @@ public class XSLTRenderingEngine private static final Log LOGGER = LogFactory.getLog(XSLTRenderingEngine.class); - public static final QName PROP_URI_RESOLVER_BASE_URI = - QName.createQName(NamespaceService.ALFRESCO_URI, "xslt_resolver_base_uri"); - public XSLTRenderingEngine() { } public String getName() { return "XSLT"; } @@ -401,13 +399,83 @@ public class XSLTRenderingEngine this.addScripts(model, xslTemplate); this.addParameters(model, xslTemplate); + final LinkedList errors = new LinkedList(); + final ErrorListener errorListener = new ErrorListener() + { + public void error(final TransformerException te) + throws TransformerException + { + LOGGER.debug("error " + te.getMessageAndLocation()); + errors.add(te); + } + + public void fatalError(final TransformerException te) + throws TransformerException + { + LOGGER.debug("fatalError " + te.getMessageAndLocation()); + throw te; + } + + public void warning(final TransformerException te) + throws TransformerException + { + LOGGER.debug("warning " + te.getMessageAndLocation()); + errors.add(te); + } + }; + + // create a uri resolver to resolve document() calls to the virtualized + // web application + final URIResolver uriResolver = new URIResolver() + { + public Source resolve(final String href, String base) + throws TransformerException + { + LOGGER.debug("request to resolve href " + href + + " using base " + base); + final RenderingEngine.TemplateResourceResolver trr = (RenderingEngine.TemplateResourceResolver) + model.get(RenderingEngineTemplateImpl.PROP_RESOURCE_RESOLVER); + + InputStream in = null; + try + { + in = trr.resolve(href); + } + catch (Exception e) + { + throw new TransformerException("unable to load " + href, e); + } + + if (in == null) + { + throw new TransformerException("unable to resolve href " + href); + } + + try + { + final Document d = XMLUtil.parse(in); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("loaded " + XMLUtil.toString(d)); + return new DOMSource(d); + } + catch (Exception e) + { + throw new TransformerException("unable to load " + href, e); + } + } + }; + Source xmlSource = this.getXMLSource(model); Transformer t = null; try { final TransformerFactory tf = TransformerFactory.newInstance(); + tf.setErrorListener(errorListener); + tf.setURIResolver(uriResolver); t = tf.newTransformer(new DOMSource(xslTemplate)); + t.setErrorListener(errorListener); + t.setURIResolver(uriResolver); t.setParameter("versionParam", "2.0"); } catch (TransformerConfigurationException tce) @@ -416,47 +484,6 @@ public class XSLTRenderingEngine throw new RenderingEngine.RenderingException(tce); } - // create a uri resolver to resolve document() calls to the virtualized - // web application - t.setURIResolver(new URIResolver() - { - public Source resolve(final String href, String base) - throws TransformerException - { - LOGGER.debug("request to resolve href " + href + - " using base " + base); - if (model.containsKey(PROP_URI_RESOLVER_BASE_URI)) - { - base = (String)model.get(PROP_URI_RESOLVER_BASE_URI); - LOGGER.debug("overriding base with " + base); - } - - URI uri = null; - try - { - uri = new URI(base + href); - } - catch (URISyntaxException e) - { - throw new TransformerException("unable to create uri " + base + href, - e); - } - try - { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("loading " + uri); - final Document d = XMLUtil.parse(uri.toURL().openStream()); - if (LOGGER.isDebugEnabled()) - LOGGER.debug("loaded " + XMLUtil.toString(d)); - return new DOMSource(d); - } - catch (Exception e) - { - throw new TransformerException("unable to load " + uri, e); - } - } - }); - try { t.transform(xmlSource, result); @@ -471,5 +498,15 @@ public class XSLTRenderingEngine LOGGER.error("unexpected error " + e); throw new RenderingEngine.RenderingException(e); } + + if (errors.size() != 0) + { + final StringBuilder msg = new StringBuilder("errors encountered during transformation: \n"); + for (TransformerException te : errors) + { + msg.append(te.getMessageAndLocation()).append("\n"); + } + throw new RenderingEngine.RenderingException(msg.toString()); + } } } diff --git a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java index 64eb28bdc1..eab072c84f 100644 --- a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java +++ b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java @@ -299,6 +299,7 @@ public class Schema2XForms "' element of the '" + this.targetNamespace + "' XML Schema."); xformsDocument.getDocumentElement().insertBefore(comment, xformsDocument.getDocumentElement().getFirstChild()); + xformsDocument.normalizeDocument(); return xformsDocument; } @@ -565,7 +566,7 @@ public class Schema2XForms if (LOGGER.isDebugEnabled()) { LOGGER.debug("appending " + data.prototype.getNodeName() + - " to " + XMLUtil.buildXPath((Element)n, instanceDocumentElement)); + " to " + XMLUtil.buildXPath(n, instanceDocumentElement)); } n.appendChild(data.prototype.cloneNode(true)); } @@ -574,9 +575,9 @@ public class Schema2XForms if (LOGGER.isDebugEnabled()) { LOGGER.debug("inserting " + data.prototype.getNodeName() + - " into " + XMLUtil.buildXPath((Element)n.getParentNode(), + " into " + XMLUtil.buildXPath(n.getParentNode(), instanceDocumentElement) + - " before " + XMLUtil.buildXPath((Element)n.getNextSibling(), + " before " + XMLUtil.buildXPath(n.getNextSibling(), instanceDocumentElement)); } n.getParentNode().insertBefore(data.prototype.cloneNode(true), @@ -587,7 +588,7 @@ public class Schema2XForms if (LOGGER.isDebugEnabled()) { LOGGER.debug("appending " + data.prototype.getNodeName() + - " to " + XMLUtil.buildXPath((Element)n.getParentNode(), + " to " + XMLUtil.buildXPath(n.getParentNode(), instanceDocumentElement)); } n.getParentNode().appendChild(data.prototype.cloneNode(true)); @@ -731,15 +732,6 @@ public class Schema2XForms } } - - // sort the enums values and then add them as choices - // - // TODO: Should really put the default value (if any) at the top of the list. - // - /*List sortedList = choiceValues.subList(0, choiceValues.size()); - Collections.sort(sortedList); - Iterator iterator = sortedList.iterator();*/ - // -> no, already sorted final Map result = new HashMap(); for (XSTypeDefinition type : choiceValues) { @@ -774,7 +766,7 @@ public class Schema2XForms formSection.appendChild(this.createTrigger(xformsDocument, null, typeBindId, - "toggle to case " + caseId, + textValue, toggle, setValue)); } @@ -1294,17 +1286,11 @@ public class Schema2XForms { // look for compatible types final XSTypeDefinition controlType = elementDecl.getTypeDefinition(); - defaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, - NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":type", - controlType.getName()); - defaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, - NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":nil", - "true"); //get possible values final List enumValues = new LinkedList(); //add the type (if not abstract) - if (!((XSComplexTypeDefinition) controlType).getAbstract()) + if (!((XSComplexTypeDefinition)controlType).getAbstract()) { enumValues.add(controlType); } @@ -1337,30 +1323,45 @@ public class Schema2XForms switchElement.setAttributeNS(NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX + ":bind", bindId); + switchElement.setAttributeNS(NamespaceConstants.XFORMS_NS, + NamespaceConstants.XFORMS_PREFIX + ":appearance", + "full"); formSection.appendChild(switchElement); - final Element firstCaseElement = caseTypes.get(controlType.getName()); - switchElement.appendChild(firstCaseElement); - final Element firstGroupElement = this.addComplexType(xformsDocument, - modelSection, - defaultInstanceElement, - firstCaseElement, - schema, - (XSComplexTypeDefinition)controlType, - elementDecl, - pathToRoot, - true, - false, - resourceBundle); - firstGroupElement.setAttributeNS(NamespaceConstants.XFORMS_NS, - NamespaceConstants.XFORMS_PREFIX + ":appearance", - ""); + if (!((XSComplexTypeDefinition)controlType).getAbstract()) + { + final Element firstCaseElement = caseTypes.get(controlType.getName()); + switchElement.appendChild(firstCaseElement); + final Element firstGroupElement = this.addComplexType(xformsDocument, + modelSection, + defaultInstanceElement, + firstCaseElement, + schema, + (XSComplexTypeDefinition)controlType, + elementDecl, + pathToRoot, + true, + false, + resourceBundle); + firstGroupElement.setAttributeNS(NamespaceConstants.XFORMS_NS, + NamespaceConstants.XFORMS_PREFIX + ":appearance", + ""); + } + + defaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, + NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":type", + (((XSComplexTypeDefinition)controlType).getAbstract() + ? compatibleTypes.first().getName() + : controlType.getName())); + defaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, + NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":nil", + "true"); /////////////// add sub types ////////////// // add each compatible type within // a case statement - for (XSTypeDefinition type : compatibleTypes) + for (final XSTypeDefinition type : compatibleTypes) { final String compatibleTypeName = type.getName(); @@ -1552,7 +1553,7 @@ public class Schema2XForms bindId = bind.getAttributeNS(null, "id"); } } - + LOGGER.debug("found bindId " + bindId + " for element " + element.getName()); //find the control Element control = null; if (bindId != null) @@ -1570,12 +1571,24 @@ public class Schema2XForms { control = (Element) pointer.getNode(); } + else + { + LOGGER.debug("unable to resolve pointer " + pointer.asPath()); + } } //copy it if (control == null) { LOGGER.warn("Corresponding control not found"); + this.addElementToGroup(xformsDocument, + modelSection, + defaultInstanceElement, + repeatSection, + schema, + element, + pathToRoot, + resourceBundle); } else { @@ -1588,64 +1601,14 @@ public class Schema2XForms } else { - //add it normally - final String elementName = this.getElementName(element, xformsDocument); - final String path = (pathToRoot.length() == 0 - ? elementName - : pathToRoot + "/" + elementName); - - final Element newDefaultInstanceElement = xformsDocument.createElement(elementName); - if (element.getConstraintType() != XSConstants.VC_NONE) - { - Node value = xformsDocument.createTextNode(element.getConstraintValue()); - newDefaultInstanceElement.appendChild(value); - } - - this.addElement(xformsDocument, - modelSection, - newDefaultInstanceElement, - repeatSection, - schema, - element, - path, - resourceBundle); - - final SchemaUtil.Occurance elementOccurs = SchemaUtil.getOccurance(element); - LOGGER.debug("adding " + (elementOccurs.maximum == 1 - ? 1 - : elementOccurs.minimum + 1) + - " default instance element for " + elementName + - " at path " + path); - // update the default instance - if (elementOccurs.isRepeated()) - { - LOGGER.debug("adding " + (elementOccurs.minimum + 1) + - " default instance elements for " + elementName + - " at path " + path); - for (int i = 0; i < elementOccurs.minimum + 1; i++) - { - final Element e = (Element)newDefaultInstanceElement.cloneNode(true); - if (i == elementOccurs.minimum) - { - e.setAttributeNS(NamespaceService.ALFRESCO_URI, - NamespaceService.ALFRESCO_PREFIX + ":prototype", - "true"); - } - defaultInstanceElement.appendChild(e); - } - } - else - { - LOGGER.debug("adding one default instance element for " + elementName + - " at path " + path); - if (elementOccurs.minimum == 0) - { - newDefaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, - NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":nil", - "true"); - } - defaultInstanceElement.appendChild(newDefaultInstanceElement); - } + this.addElementToGroup(xformsDocument, + modelSection, + defaultInstanceElement, + repeatSection, + schema, + element, + pathToRoot, + resourceBundle); } } else @@ -1661,6 +1624,76 @@ public class Schema2XForms LOGGER.debug("--- end of addGroup from owner=" + owner.getName()); } } + + private void addElementToGroup(final Document xformsDocument, + final Element modelSection, + final Element defaultInstanceElement, + final Element formSection, + final XSModel schema, + final XSElementDeclaration element, + final String pathToRoot, + final ResourceBundle resourceBundle) + throws FormBuilderException + { + //add it normally + final String elementName = this.getElementName(element, xformsDocument); + final String path = (pathToRoot.length() == 0 + ? elementName + : pathToRoot + "/" + elementName); + + final Element newDefaultInstanceElement = xformsDocument.createElement(elementName); + if (element.getConstraintType() != XSConstants.VC_NONE) + { + Node value = xformsDocument.createTextNode(element.getConstraintValue()); + newDefaultInstanceElement.appendChild(value); + } + + this.addElement(xformsDocument, + modelSection, + newDefaultInstanceElement, + formSection, + schema, + element, + path, + resourceBundle); + + final SchemaUtil.Occurance elementOccurs = SchemaUtil.getOccurance(element); + LOGGER.debug("adding " + (elementOccurs.maximum == 1 + ? 1 + : elementOccurs.minimum + 1) + + " default instance element for " + elementName + + " at path " + path); + // update the default instance + if (elementOccurs.isRepeated()) + { + LOGGER.debug("adding " + (elementOccurs.minimum + 1) + + " default instance elements for " + elementName + + " at path " + path); + for (int i = 0; i < elementOccurs.minimum + 1; i++) + { + final Element e = (Element)newDefaultInstanceElement.cloneNode(true); + if (i == elementOccurs.minimum) + { + e.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":prototype", + "true"); + } + defaultInstanceElement.appendChild(e); + } + } + else + { + LOGGER.debug("adding one default instance element for " + elementName + + " at path " + path); + if (elementOccurs.minimum == 0) + { + newDefaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS, + NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":nil", + "true"); + } + defaultInstanceElement.appendChild(newDefaultInstanceElement); + } + } /** * Add a repeat section if maxOccurs > 1. @@ -2366,6 +2399,15 @@ public class Schema2XForms { appearance = "full"; } + if (controlType.isDefinedFacet(XSSimpleTypeDefinition.FACET_MAXLENGTH) || + controlType.isDefinedFacet(XSSimpleTypeDefinition.FACET_LENGTH)) + { + result.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":maxLength", + (controlType.isDefinedFacet(XSSimpleTypeDefinition.FACET_MAXLENGTH) + ? controlType.getLexicalFacetValue(XSSimpleTypeDefinition.FACET_MAXLENGTH) + : controlType.getLexicalFacetValue(XSSimpleTypeDefinition.FACET_MAXLENGTH))); + } } this.setXFormsId(result); result.appendChild(this.createLabel(xformsDocument, caption)); @@ -2946,6 +2988,9 @@ public class Schema2XForms (this.submitMethod != null ? this.submitMethod : Schema2XForms.SubmitMethod.POST).toString()); + result.setAttributeNS(NamespaceConstants.XFORMS_NS, + NamespaceConstants.XFORMS_PREFIX + ":encoding", + "UTF-8"); return result; } diff --git a/source/java/org/alfresco/web/forms/xforms/SchemaUtil.java b/source/java/org/alfresco/web/forms/xforms/SchemaUtil.java index fca3ae92fc..49ac7804c8 100644 --- a/source/java/org/alfresco/web/forms/xforms/SchemaUtil.java +++ b/source/java/org/alfresco/web/forms/xforms/SchemaUtil.java @@ -94,37 +94,35 @@ public class SchemaUtil //////////////////////////////////////////////////////////////////////////// - private final static Comparator TYPE_EXTENSION_SORTER = new Comparator() + private final static Comparator TYPE_EXTENSION_SORTER = + new Comparator() { - public int compare(Object obj1, Object obj2) + public int compare(final XSTypeDefinition type1, final XSTypeDefinition type2) { - if (obj1 == null && obj2 != null) - return -1; - else if (obj1 != null && obj2 == null) - return 1; - else if (obj1 == obj2 || (obj1 == null && obj2 == null)) - return 0; + int result = 0; + if (type1 == null && type2 != null) + { + result = -1; + } + else if (type1 != null && type2 == null) + { + result = 1; + } + else if (type1 == type2 || (type1 == null && type2 == null)) + { + result = 0; + } else { - try - { - final XSTypeDefinition type1 = (XSTypeDefinition) obj1; - final XSTypeDefinition type2 = (XSTypeDefinition) obj2; - return (type1.derivedFromType(type2, XSConstants.DERIVATION_EXTENSION) - ? 1 - : (type2.derivedFromType(type1, XSConstants.DERIVATION_EXTENSION) - ? -1 - : 0)); - } - catch (ClassCastException ex) - { - String s = "ClassCastException in typeExtensionSorter: one of the types is not a type !"; - s = s + "\n obj1 class = " + obj1.getClass().getName() + ", toString=" + obj1.toString(); - s = s + "\n obj2 class = " + obj2.getClass().getName() + ", toString=" + obj2.toString(); - SchemaUtil.LOGGER.error(s, ex); - return 0; - } + result = (type1.derivedFromType(type2, XSConstants.DERIVATION_EXTENSION) + ? 1 + : (type2.derivedFromType(type1, XSConstants.DERIVATION_EXTENSION) + ? -1 + : type1.getName().compareTo(type2.getName()))); } + if (LOGGER.isDebugEnabled() && false) + LOGGER.debug("compare(" + type1 + ", " + type2 + ") = " + result); + return result; } }; @@ -301,36 +299,47 @@ public class SchemaUtil final TreeMap> typeTree) { if (type == null) + { return; - + } + if (LOGGER.isDebugEnabled()) + LOGGER.debug("buildTypeTree(" + type.getName() + ", " + descendents.size() + " descendents)"); if (descendents.size() > 0) { - //TreeSet compatibleTypes = (TreeSet) typeTree.get(type.getName()); TreeSet compatibleTypes = typeTree.get(type.getName()); if (compatibleTypes == null) { - //compatibleTypes = new TreeSet(descendents); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("no compatible types found for " + type.getName() + ", creating a new set"); compatibleTypes = new TreeSet(TYPE_EXTENSION_SORTER); typeTree.put(type.getName(), compatibleTypes); } + if (LOGGER.isDebugEnabled()) + LOGGER.debug("adding " + descendents.size() + " descendents to " + type.getName()); compatibleTypes.addAll(descendents); } final XSTypeDefinition parentType = type.getBaseType(); - if (parentType == null || type.getTypeCategory() != parentType.getTypeCategory()) { return; } - if (type != parentType && - (parentType.getName() == null || !parentType.getName().equals("anyType"))) + + if (type != parentType && parentType.getName() != null && !parentType.getName().equals("anyType")) { - - //TreeSet newDescendents=new TreeSet(descendents); - final TreeSet newDescendents = - new TreeSet(TYPE_EXTENSION_SORTER); + TreeSet newDescendents = typeTree.get(parentType.getName()); + if (newDescendents == null) + { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("type tree doesn't contain " + parentType.getName() + + ", creating a new descendant set"); + newDescendents = new TreeSet(TYPE_EXTENSION_SORTER); + } + if (LOGGER.isDebugEnabled()) + LOGGER.debug("adding " + descendents.size() + " descendants to existing " + newDescendents.size() + + " descendants of " + parentType.getName()); newDescendents.addAll(descendents); //extension (we only add it to "newDescendants" because we don't want @@ -341,7 +350,13 @@ public class SchemaUtil if (complexType.getDerivationMethod() == XSConstants.DERIVATION_EXTENSION && !complexType.getAbstract() && !descendents.contains(type)) + { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("adding " + type.getName() + + " to existing " + newDescendents.size() + + " descendents of " + parentType.getName()); newDescendents.add(type); + } } //note: extensions are impossible on simpleTypes ! @@ -354,7 +369,8 @@ public class SchemaUtil { final TreeMap> result = new TreeMap>(); - LOGGER.debug("buildTypeTree " + schema); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("buildTypeTree " + schema); // build the type tree for complex types final XSNamedMap types = schema.getComponents(XSConstants.TYPE_DEFINITION); for (int i = 0; i < types.getLength(); i++) diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java index 73a59294f8..c68348fe36 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java @@ -402,7 +402,7 @@ public class XFormsBean this.xformsSession.schema2XForms.removePrototypeNodes(documentElement); documentElement = (Element)instanceData.importNode(documentElement, true); instanceData.appendChild(documentElement); - + instanceData.normalizeDocument(); final ResponseWriter out = context.getResponseWriter(); XMLUtil.print(instanceData, out, false); out.close(); diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java index 5407086a4e..b2f1ae7394 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java @@ -25,9 +25,12 @@ import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.web.bean.wcm.AVMBrowseBean; +import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.forms.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.web.util.JavaScriptUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -59,7 +62,9 @@ public class XFormsProcessor "/scripts/ajax/dojo/" + (LOGGER.isDebugEnabled() ? "dojo.js.uncompressed.js" : "dojo.js"), + "/scripts/ajax/ajax_helper.js", "/scripts/ajax/xforms.js", + "/scripts/ajax/file_picker_widget.js", "/scripts/upload_helper.js", }; @@ -108,6 +113,8 @@ public class XFormsProcessor //make the XFormsBean available for this session final XFormsBean xforms = (XFormsBean) FacesHelper.getManagedBean(fc, "XFormsBean"); + final AVMBrowseBean avmBrowseBean = (AVMBrowseBean) + FacesHelper.getManagedBean(fc, "AVMBrowseBean"); try { xforms.setXFormsSession((XFormsBean.XFormsSession)session); @@ -142,52 +149,68 @@ public class XFormsProcessor e = result.createElement("script"); e.setAttribute("type", "text/javascript"); final StringBuilder js = new StringBuilder("\ndjConfig = {isDebug:" + LOGGER.isDebugEnabled() + "};\n"); - js.append("var alfresco_xforms_constants = {};\n"); - js.append("alfresco_xforms_constants.WEBAPP_CONTEXT = '"). - append(contextPath). + final String[] jsNamespacesObjects = { "alfresco", "alfresco.constants", "alfresco.xforms", "alfresco.xforms.constants" }; + for (final String jsNamespace : jsNamespacesObjects) + { + js.append(jsNamespace). + append(" = typeof "). + append(jsNamespace). + append(" == 'undefined' ? {} : "). + append(jsNamespace). + append(";\n"); + } + js.append("alfresco.constants.WEBAPP_CONTEXT = '"). + append(JavaScriptUtils.javaScriptEscape(contextPath)). append("';\n"); - js.append("alfresco_xforms_constants.XFORMS_UI_DIV_ID = '"). + js.append("alfresco.constants.AVM_WEBAPP_CONTEXT = '"). + append(JavaScriptUtils.javaScriptEscape(avmBrowseBean.getWebapp())). + append("';\n"); + js.append("alfresco.constants.AVM_WEBAPP_URL = '"). + append(JavaScriptUtils.javaScriptEscape(AVMConstants.buildWebappUrl(AVMConstants.getCorrespondingPreviewStoreName(avmBrowseBean.getSandbox()), + avmBrowseBean.getWebapp()))). + append("';\n"); + js.append("alfresco.xforms.constants.XFORMS_UI_DIV_ID = '"). append(xformsUIDivId). append("';\n"); - js.append("alfresco_xforms_constants.FORM_INSTANCE_DATA_NAME = '"). - append(session.getFormInstanceDataName()). + js.append("alfresco.xforms.constants.FORM_INSTANCE_DATA_NAME = '"). + append(JavaScriptUtils.javaScriptEscape(session.getFormInstanceDataName())). append("';\n"); SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.SHORT, Application.getLanguage(fc)); - js.append("alfresco_xforms_constants.DATE_FORMAT = '"). + js.append("alfresco.xforms.constants.DATE_FORMAT = '"). append(sdf.toLocalizedPattern()). append("';\n"); sdf = (SimpleDateFormat) SimpleDateFormat.getTimeInstance(DateFormat.SHORT, Application.getLanguage(fc)); - js.append("alfresco_xforms_constants.TIME_FORMAT = '"). + js.append("alfresco.xforms.constants.TIME_FORMAT = '"). append(sdf.toLocalizedPattern()). append("';\n"); sdf = (SimpleDateFormat) SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Application.getLanguage(fc)); - js.append("alfresco_xforms_constants.DATE_TIME_FORMAT = '"). + js.append("alfresco.xforms.constants.DATE_TIME_FORMAT = '"). append(sdf.toLocalizedPattern()). append("';\n"); for (String[] ns : JS_NAMESPACES) { - js.append("alfresco_xforms_constants."). + js.append("alfresco.xforms.constants."). append(ns[0].toUpperCase()). append("_NS = '").append(ns[1]).append("';\n"); - js.append("alfresco_xforms_constants."). + js.append("alfresco.xforms.constants."). append(ns[0].toUpperCase()). append("_PREFIX = '").append(ns[2]).append("';\n"); } final ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance()); - js.append("alfresco_xforms_constants.resources = {\n"); + js.append("alfresco.xforms.constants.resources = {\n"); for (String k : BUNDLE_KEYS) { js.append(k). append(": '"). - append(bundle.getString(k)). + append(JavaScriptUtils.javaScriptEscape(bundle.getString(k))). append("'"). append(k.equals(BUNDLE_KEYS[BUNDLE_KEYS.length - 1]) ? "\n};" : ","). append("\n"); diff --git a/source/java/org/alfresco/web/ui/common/Utils.java b/source/java/org/alfresco/web/ui/common/Utils.java index 8761feb15b..3c0cc32a38 100644 --- a/source/java/org/alfresco/web/ui/common/Utils.java +++ b/source/java/org/alfresco/web/ui/common/Utils.java @@ -112,6 +112,7 @@ public final class Utils * * @param string the String to convert */ + //XXXarielb perhaps use org.springframework.web.util.HtmlUtils instead? public static String encode(String string) { if (string == null) diff --git a/source/java/org/alfresco/web/ui/common/converter/MultiValueConverter.java b/source/java/org/alfresco/web/ui/common/converter/MultiValueConverter.java index 0b3f0ee1eb..e57340e095 100644 --- a/source/java/org/alfresco/web/ui/common/converter/MultiValueConverter.java +++ b/source/java/org/alfresco/web/ui/common/converter/MultiValueConverter.java @@ -57,7 +57,7 @@ public class MultiValueConverter implements Converter StringTokenizer tokenizer = new StringTokenizer(value, ","); while (tokenizer.hasMoreTokens()) { - items.add(tokenizer.nextToken()); + items.add(tokenizer.nextToken().trim()); } return items; diff --git a/source/java/org/alfresco/web/ui/common/tag/MultiValueConverterTag.java b/source/java/org/alfresco/web/ui/common/tag/MultiValueConverterTag.java new file mode 100644 index 0000000000..70c532a595 --- /dev/null +++ b/source/java/org/alfresco/web/ui/common/tag/MultiValueConverterTag.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.ui.common.tag; + +import javax.faces.convert.Converter; +import javax.faces.webapp.ConverterTag; +import javax.servlet.jsp.JspException; + +import org.alfresco.web.ui.common.converter.MultiValueConverter; + +/** + * Allows the MultiValueConverter component to be used on JSP pages + * + * @author gavinc + */ +public class MultiValueConverterTag extends ConverterTag +{ + /** + * Default Constructor + */ + public MultiValueConverterTag() + { + setConverterId(MultiValueConverter.CONVERTER_ID); + } + + /** + * @see javax.faces.webapp.ConverterTag#createConverter() + */ + protected Converter createConverter() throws JspException + { + return (MultiValueConverter)super.createConverter(); + } +} diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIDeployWebsite.java b/source/java/org/alfresco/web/ui/wcm/component/UIDeployWebsite.java new file mode 100644 index 0000000000..11184031ab --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/component/UIDeployWebsite.java @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.ui.wcm.component; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.faces.component.UIInput; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.el.ValueBinding; +import javax.transaction.UserTransaction; + +import org.alfresco.model.WCMAppModel; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.wcm.AVMConstants; +import org.alfresco.web.bean.wcm.DeploymentMonitor; +import org.alfresco.web.ui.common.Utils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * JSF component that allows a user to select which servers to deploy a + * website to and provides monitoring of the deployments selected + * + * @author gavinc + */ +public class UIDeployWebsite extends UIInput +{ + protected NodeRef webProjectRef; + protected Integer snapshotVersion = -1; + protected Boolean monitorDeployment; + protected List monitorIds; + + private static Log logger = LogFactory.getLog(UIDeployWebsite.class); + + // ------------------------------------------------------------------------------ + // Component implementation + + /** + * Default constructor + */ + public UIDeployWebsite() + { + setRendererType(null); + } + + @Override + public String getFamily() + { + return "org.alfresco.faces.DeployWebsite"; + } + + @Override + public void decode(FacesContext context) + { + super.decode(context); + + Map valuesMap = context.getExternalContext().getRequestParameterValuesMap(); + String[] values = (String[])valuesMap.get(this.getClientId(context)); + + setSubmittedValue(values); + } + + @SuppressWarnings("unchecked") + @Override + public void restoreState(FacesContext context, Object state) + { + Object values[] = (Object[])state; + // standard component attributes are restored by the super class + super.restoreState(context, values[0]); + this.webProjectRef = (NodeRef)values[1]; + this.monitorDeployment = (Boolean)values[2]; + this.monitorIds = (List)values[3]; + this.snapshotVersion = (Integer)values[4]; + } + + @Override + public Object saveState(FacesContext context) + { + Object values[] = new Object[5]; + // standard component attributes are saved by the super class + values[0] = super.saveState(context); + values[1] = this.webProjectRef; + values[2] = this.monitorDeployment; + values[3] = this.monitorIds; + values[4] = this.snapshotVersion; + return values; + } + + @SuppressWarnings("unchecked") + @Override + public void encodeBegin(FacesContext context) throws IOException + { + if (isRendered() == false) + { + return; + } + + ResponseWriter out = context.getResponseWriter(); + UserTransaction tx = null; + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true); + tx.begin(); + + NodeRef webProject = this.getWebsite(); + if (webProject == null) + { + throw new IllegalArgumentException("The web project must be specified."); + } + + // add some before the panels + out.write("\n
\n"); + + if (this.getMonitor()) + { + // get the ids of the deployment monitor objects + List deployMonitorIds = this.getMonitorIds(); + + if (logger.isDebugEnabled()) + { + logger.debug("Monitoring deployment of: " + deployMonitorIds); + } + + // TODO: Add support for 'sniffing' the session for deployment monitors + // this could be useful when the monitor ids are not known + + // render the supporting script required for monitoring + renderScript(context, out, deployMonitorIds); + + // render each server being deployed with an animated icon, the subsequent + // AJAX callback will update the progress. + for (String id : deployMonitorIds) + { + // try and find the monitor object in the session, if it's not there + // it has probably completed and been removed + DeploymentMonitor monitor = (DeploymentMonitor)context.getExternalContext(). + getSessionMap().get(id); + if (monitor != null) + { + if (logger.isDebugEnabled()) + logger.debug("Found deployment monitor: " + monitor); + + renderServer(context, out, monitor.getTargetServer(), false, true, id); + } + } + } + else + { + // get a list of the servers that have been successfully deployed to + NodeService nodeService = Repository.getServiceRegistry(context).getNodeService(); + int deployingVersion = this.getSnapshotVersion(); + List serversAlreadyDeployed = new ArrayList(); + List deployReportRefs = nodeService.getChildAssocs( + webProjectRef, WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : deployReportRefs) + { + NodeRef report = ref.getChildRef(); + Boolean success = (Boolean)nodeService.getProperty(report, + WCMAppModel.PROP_DEPLOYSUCCESSFUL); + int deployedVersion = (Integer)nodeService.getProperty(report, + WCMAppModel.PROP_DEPLOYVERSION); + if (success.booleanValue() && (deployingVersion == deployedVersion)) + { + serversAlreadyDeployed.add((String)nodeService.getProperty(report, + WCMAppModel.PROP_DEPLOYSERVER)); + } + } + + // get the list of servers for the user to select from + List servers = (List)nodeService.getProperty(webProject, + WCMAppModel.PROP_DEPLOYTO); + + if (logger.isDebugEnabled()) + logger.debug("Servers available: " + servers + ", servers already deployed: " + + serversAlreadyDeployed); + + // render the list of servers, only pre-select those that have not been + // deployed successfully + for (String server : servers) + { + boolean preSelected = !serversAlreadyDeployed.contains(server); + renderServer(context, out, server, preSelected, false, null); + } + } + + tx.commit(); + } + catch (Throwable err) + { + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + throw new RuntimeException(err); + } + } + + // ------------------------------------------------------------------------------ + // Strongly typed component property accessors + + /** + * @return The NodeRef representation of the web project to show the deployment reports for + */ + public NodeRef getWebsite() + { + ValueBinding vb = getValueBinding("website"); + if (vb != null) + { + this.webProjectRef = (NodeRef)vb.getValue(getFacesContext()); + } + + return this.webProjectRef; + } + + /** + * @param value The NodeRef representation of the web project to show the deployment reports for + */ + public void setWebsite(NodeRef value) + { + this.webProjectRef = value; + } + + /** + * @return true if the component should monitor a deployment + */ + public boolean getMonitor() + { + ValueBinding vb = getValueBinding("monitor"); + if (vb != null) + { + this.monitorDeployment = (Boolean)vb.getValue(getFacesContext()); + } + + if (this.monitorDeployment == null) + { + this.monitorDeployment = Boolean.FALSE; + } + + return this.monitorDeployment.booleanValue(); + } + + /** + * @param monitor Determines whether a deployment should be monitored + */ + public void setMonitor(boolean monitor) + { + this.monitorDeployment = new Boolean(monitor); + } + + /** + * @return The list of deployment monitor IDs + */ + @SuppressWarnings("unchecked") + public List getMonitorIds() + { + ValueBinding vb = getValueBinding("monitorIds"); + if (vb != null) + { + this.monitorIds = (List)vb.getValue(getFacesContext()); + } + + return this.monitorIds; + } + + /** + * @param monitorIds List of monitor IDs to look for + */ + public void setMonitorIds(List monitorIds) + { + this.monitorIds = monitorIds; + } + + /** + * @return The version of the snapshot being deployed + */ + public int getSnapshotVersion() + { + ValueBinding vb = getValueBinding("snapshotVersion"); + if (vb != null) + { + this.snapshotVersion = (Integer)vb.getValue(getFacesContext()); + } + + return this.snapshotVersion; + } + + /** + * @param snapshotVersion The version of the snapshot being deployed + */ + public void setSnapshotVersion(int snapshotVersion) + { + this.snapshotVersion = snapshotVersion; + } + + // ------------------------------------------------------------------------------ + // Helpers + + private void renderScript(FacesContext context, ResponseWriter out, + List monitorIds) throws IOException + { +// // render supporting Yahoo scripts +// Utils.writeYahooScripts(context, out, null); + + // create comma separated list of deplyment ids + StringBuilder ids = new StringBuilder(); + for (int x = 0; x < monitorIds.size(); x++) + { + if (x > 0) + { + ids.append(","); + } + + String id = monitorIds.get(x); + ids.append(id); + } + + // determine the polling frequency value + int pollFreq = AVMConstants.getRemoteDeploymentPollingFrequency() * 1000; + + // render the script to handle the progress monitoring + out.write("\n"); + } + + private void renderServer(FacesContext context, ResponseWriter out, String server, + boolean selected, boolean monitoring, String monitorId) throws IOException + { + String contextPath = context.getExternalContext().getRequestContextPath(); + + out.write(""); + out.write(""); + out.write(""); + out.write(""); + out.write("
"); + if (monitoring) + { + out.write("
"); + out.write(""); + } + else + { + out.write("
"); + out.write(""); + } + out.write("
"); + out.write("
"); + out.write("
"); + out.write("
"); + out.write(server); + out.write("
"); + if (monitoring) + { + out.write("
"); + out.write(Application.getMessage(context, "deploying")); + out.write("
"); + } + else if (selected == false) + { + out.write("
 "); + out.write(Application.getMessage(context, "deploy_server_not_selected")); + out.write("
"); + } + out.write("
"); + + // add some padding under each panel + out.write("\n
\n"); + } +} diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIDeploymentReports.java b/source/java/org/alfresco/web/ui/wcm/component/UIDeploymentReports.java new file mode 100644 index 0000000000..19dd4c1c27 --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/component/UIDeploymentReports.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.ui.wcm.component; + +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.el.ValueBinding; +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMAppModel; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.ui.common.PanelGenerator; +import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.common.component.SelfRenderingComponent; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.StringUtils; + +/** + * JSF component that displays the latest deployment reports for a web project. + * + * @author gavinc + */ +public class UIDeploymentReports extends SelfRenderingComponent +{ + protected NodeRef webProjectRef; + + private static Log logger = LogFactory.getLog(UIDeploymentReports.class); + + // ------------------------------------------------------------------------------ + // Component implementation + + /** + * @see javax.faces.component.UIComponent#getFamily() + */ + public String getFamily() + { + return "org.alfresco.faces.DeploymentReports"; + } + + public void restoreState(FacesContext context, Object state) + { + Object values[] = (Object[])state; + // standard component attributes are restored by the super class + super.restoreState(context, values[0]); + this.webProjectRef = (NodeRef)values[1]; + } + + public Object saveState(FacesContext context) + { + Object values[] = new Object[2]; + // standard component attributes are saved by the super class + values[0] = super.saveState(context); + values[1] = this.webProjectRef; + return values; + } + + /** + * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext) + */ + @SuppressWarnings("unchecked") + public void encodeBegin(FacesContext context) throws IOException + { + if (isRendered() == false) + { + return; + } + + ResponseWriter out = context.getResponseWriter(); + UserTransaction tx = null; + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true); + tx.begin(); + + NodeRef webProject = getValue(); + if (webProject == null) + { + throw new IllegalArgumentException("The web project must be specified."); + } + + if (logger.isDebugEnabled()) + logger.debug("Rendering deployment reports for: " + webProject.toString()); + + // render the supporting JavaScript + renderScript(context, out); + + // iterate through each deployment report + NodeService nodeService = Repository.getServiceRegistry(context).getNodeService(); + ContentService contentService = Repository.getServiceRegistry(context).getContentService(); + List deployReportRefs = nodeService.getChildAssocs( + this.webProjectRef, WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : deployReportRefs) + { + // render each report + renderReport(context, out, ref.getChildRef(), nodeService, contentService); + } + + // add some padding after the panels + out.write("\n
\n"); + + tx.commit(); + } + catch (Throwable err) + { + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + throw new RuntimeException(err); + } + } + + // ------------------------------------------------------------------------------ + // Strongly typed component property accessors + + /** + * @return The NodeRef representation of the web project to show the deployment reports for + */ + public NodeRef getValue() + { + ValueBinding vb = getValueBinding("value"); + if (vb != null) + { + this.webProjectRef = (NodeRef)vb.getValue(getFacesContext()); + } + + return this.webProjectRef; + } + + /** + * @param value The NodeRef representation of the web project to show the deployment reports for + */ + public void setValue(NodeRef value) + { + this.webProjectRef = value; + } + + // ------------------------------------------------------------------------------ + // Helpers + + private void renderScript(FacesContext context, ResponseWriter out) + throws IOException + { + out.write("\n"); + } + + private void renderReport(FacesContext context, ResponseWriter out, NodeRef deploymentReport, + NodeService nodeService, ContentService contentService) + throws IOException + { + if (logger.isDebugEnabled()) + logger.debug("Rendering report: " + deploymentReport); + + // add some padding before the panel + out.write("\n
\n"); + + // start the surrounding panel + PanelGenerator.generatePanelStart(out, + context.getExternalContext().getRequestContextPath(), "innerwhite", "white"); + + // extract the information we need to display + String server = (String)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYSERVER); + Integer snapshot = (Integer)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYVERSION); + String creator = (String)nodeService.getProperty(deploymentReport, ContentModel.PROP_CREATOR); + Date startTime = (Date)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYSTARTTIME); + Date endTime = (Date)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYENDTIME); + String started = Utils.getDateTimeFormat(context).format(startTime); + String finished = Utils.getDateTimeFormat(context).format(endTime); + Boolean success = (Boolean)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYSUCCESSFUL); + String failReason = (String)nodeService.getProperty(deploymentReport, WCMAppModel.PROP_DEPLOYFAILEDREASON); + String content = ""; + ContentReader reader = contentService.getReader(deploymentReport, ContentModel.PROP_CONTENT); + if (reader != null) + { + content = reader.getContentString(); + if (content != null) + { + content = StringUtils.replace(content, "\r\n", "
"); + } + else + { + content = ""; + } + } + + out.write(""); + out.write("
"); + out.write("
"); + out.write(server); + out.write("
  "); + if (success.booleanValue()) + { + out.write(Application.getMessage(context, "deploy_successful")); + } + else + { + out.write(Application.getMessage(context, "deploy_failed")); + } + out.write("
"); + out.write("
"); + out.write(Application.getMessage(context, "snapshot")); + out.write(": "); + out.write(snapshot.toString()); + out.write("
"); + out.write("
"); + out.write(Application.getMessage(context, "deploy_started")); + out.write(": "); + out.write(started); + out.write("
"); + out.write("
"); + out.write(Application.getMessage(context, "deploy_finished")); + out.write(": "); + out.write(finished); + out.write("
"); + out.write("
"); + out.write(Application.getMessage(context, "deployed_by")); + out.write(": "); + out.write(creator); + out.write("
"); + if (success.booleanValue() == false && failReason != null && failReason.length() > 0) + { + out.write("
"); + out.write(Application.getMessage(context, "reason")); + out.write(": "); + out.write(failReason); + out.write("
"); + } + if (content.length() > 0) + { + out.write("
 "); + out.write(Application.getMessage(context, "details")); + out.write("
\n"); + out.write(""); + } + out.write("\n
\n"); + out.write("
"); + + // finish the surrounding panel + PanelGenerator.generatePanelEnd(out, + context.getExternalContext().getRequestContextPath(), "innerwhite"); + } +} diff --git a/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java b/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java index 977ab3be3b..f079cc40d5 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UISandboxSnapshots.java @@ -26,6 +26,7 @@ package org.alfresco.web.ui.wcm.component; import java.io.IOException; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -40,10 +41,16 @@ import javax.faces.context.ResponseWriter; import javax.faces.el.ValueBinding; import javax.transaction.UserTransaction; +import org.alfresco.model.WCMAppModel; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.VersionDescriptor; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.ui.common.ComponentConstants; import org.alfresco.web.ui.common.ConstantMethodBinding; import org.alfresco.web.ui.common.Utils; @@ -61,6 +68,7 @@ public class UISandboxSnapshots extends SelfRenderingComponent { private static final String ACT_SNAPSHOT_PREVIEW = "snapshot_preview"; private static final String ACT_SNAPSHOT_REVERT = "snapshot_revert"; + private static final String ACT_SNAPSHOT_DEPLOY = "snapshot_deploy"; private static final String REQUEST_SNAPVERSION = "_snapVer"; @@ -72,14 +80,14 @@ public class UISandboxSnapshots extends SelfRenderingComponent public static final String FILTER_DATE_WEEK = "week"; public static final String FILTER_DATE_MONTH = "month"; - private static final String COMPONENT_ACTIONS = "org.alfresco.faces.Actions"; - private static final String MSG_LABEL = "name"; private static final String MSG_DESCRIPTION = "description"; private static final String MSG_DATE = "date"; private static final String MSG_USERNAME = "username"; private static final String MSG_VERSION = "version"; + private static final String MSG_STATUS = "status"; private static final String MSG_ACTIONS = "actions"; + private static final String MSG_LIVE = "live"; /** sandbox to show snapshots for */ private String value; @@ -87,6 +95,9 @@ public class UISandboxSnapshots extends SelfRenderingComponent /** date filter to use when listing snapshots */ private String dateFilter; + /** The snapshot version deployed and the state of that deployment */ + private int deployAttemptVersion = -1; + private String deployStatus; // ------------------------------------------------------------------------------ // Component implementation @@ -174,6 +185,8 @@ public class UISandboxSnapshots extends SelfRenderingComponent out.write(""); out.write(bundle.getString(MSG_VERSION)); out.write(""); + out.write(bundle.getString(MSG_STATUS)); + out.write(""); out.write(bundle.getString(MSG_ACTIONS)); out.write(""); @@ -211,6 +224,10 @@ public class UISandboxSnapshots extends SelfRenderingComponent } versions = avmService.getStoreVersions(sandbox, fromDate, toDate); } + + // determine the deployment status for the website + determineDeploymentStatus(context, sandbox); + Map requestMap = context.getExternalContext().getRequestMap(); for (int i=versions.size() - 1; i >= 0; i--) // reverse order { @@ -219,6 +236,8 @@ public class UISandboxSnapshots extends SelfRenderingComponent // only display snapshots with a valid tag - others are system generated snapshots if (item.getTag() != null && item.getVersionID() != 0) { + int version = item.getVersionID(); + out.write(""); out.write(item.getTag()); out.write(""); @@ -228,20 +247,45 @@ public class UISandboxSnapshots extends SelfRenderingComponent out.write(""); out.write(item.getCreator()); out.write(""); - out.write(Integer.toString(item.getVersionID())); + out.write(Integer.toString(version)); + out.write(""); + if (version == this.deployAttemptVersion && this.deployStatus != null) + { + out.write(this.deployStatus); + } + else + { + out.write(" "); + } out.write(""); - // actions for the item + + // create actions for the item + + // revert action UIActionLink action = findAction(ACT_SNAPSHOT_REVERT, sandbox); if (action == null) { Map params = new HashMap(2, 1.0f); params.put("sandbox", sandbox); params.put("version", "#{" + REQUEST_SNAPVERSION + "}"); - action = createAction(context, sandbox, ACT_SNAPSHOT_REVERT, null, + action = createAction(context, sandbox, ACT_SNAPSHOT_REVERT, "/images/icons/revert.gif", "#{AVMBrowseBean.revertSnapshot}", null, null, params); } requestMap.put(REQUEST_SNAPVERSION, Integer.toString(item.getVersionID())); + Utils.encodeRecursive(context, action); + out.write("  "); + + // deploy action + action = findAction(ACT_SNAPSHOT_DEPLOY, sandbox); + if (action == null) + { + Map params = new HashMap(2, 1.0f); + params.put("version", "#{" + REQUEST_SNAPVERSION + "}"); + action = createAction(context, sandbox, ACT_SNAPSHOT_DEPLOY, "/images/icons/deploy.gif", + "#{DialogManager.setupParameters}", "dialog:deploySnapshot", null, params); + } + Utils.encodeRecursive(context, action); requestMap.remove(REQUEST_SNAPVERSION); //out.write(" "); @@ -419,6 +463,91 @@ public class UISandboxSnapshots extends SelfRenderingComponent return control; } + private void determineDeploymentStatus(FacesContext context, String sandbox) + { + // work out what status to show against which snapshot + NodeRef webProjectRef = AVMConstants.getWebProjectNodeFromStore(sandbox); + NodeService nodeService = Repository.getServiceRegistry(context).getNodeService(); + List selectedServers = (List)nodeService.getProperty(webProjectRef, + WCMAppModel.PROP_SELECTEDDEPLOYTO); + Integer ver = (Integer)nodeService.getProperty(webProjectRef, + WCMAppModel.PROP_SELECTEDDEPLOYVERSION); + if (ver != null) + { + this.deployAttemptVersion = ver.intValue(); + } + + if (selectedServers != null && selectedServers.size() > 0) + { + // if the 'selecteddeployto' property is set a deployment has been attempted + List deployReportRefs = nodeService.getChildAssocs( + webProjectRef, WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + + List deployedServers = new ArrayList(); + + boolean oneOrMoreFailed = false; + boolean allFailed = true; + for (ChildAssociationRef ref : deployReportRefs) + { + NodeRef report = ref.getChildRef(); + + // get the name of the server and the deploy outcome + String serverName = (String)nodeService.getProperty(report, + WCMAppModel.PROP_DEPLOYSERVER); + Boolean successful = (Boolean)nodeService.getProperty(report, + WCMAppModel.PROP_DEPLOYSUCCESSFUL); + + deployedServers.add(serverName); + if (successful != null) + { + if (successful.booleanValue()) + { + allFailed = false; + } + else + { + oneOrMoreFailed = true; + } + } + } + + // now we have a list of servers that were deployed see if all + // the selected servers have a report, if not it means a deployment + // is in progress. If all servers reports are present then + // determine the status by the outcomes of from all the reports. + boolean allPresent = true; + for (String selectedServer : selectedServers) + { + if (deployedServers.contains(selectedServer) == false) + { + allPresent = false; + break; + } + } + + if (allPresent) + { + // get the right status string + if (allFailed) + { + this.deployStatus = Application.getMessage(context, "deploy_status_failed"); + } + else if (oneOrMoreFailed) + { + this.deployStatus = Application.getMessage(context, "deploy_status_partial"); + } + else + { + this.deployStatus = Application.getMessage(context, "deploy_status_live"); + } + } + else + { + this.deployStatus = Application.getMessage(context, "deploy_status_in_progress"); + } + } + } + private AVMService getAVMService(FacesContext fc) { return (AVMService)FacesContextUtils.getRequiredWebApplicationContext(fc).getBean("AVMService"); diff --git a/source/java/org/alfresco/web/ui/wcm/tag/DeployWebsiteTag.java b/source/java/org/alfresco/web/ui/wcm/tag/DeployWebsiteTag.java new file mode 100644 index 0000000000..47891a143b --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/tag/DeployWebsiteTag.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.ui.wcm.tag; + +import javax.faces.component.UIComponent; + +import org.alfresco.web.ui.common.tag.BaseComponentTag; + +/** + * Tag class that allows the DeployWebsite component to be used on a JSP page. + * + * @author gavinc + */ +public class DeployWebsiteTag extends BaseComponentTag +{ + private String value; + private String website; + private String monitor; + private String monitorIds; + private String snapshotVersion; + + /** + * @see javax.faces.webapp.UIComponentTag#getComponentType() + */ + public String getComponentType() + { + return "org.alfresco.faces.DeployWebsite"; + } + + /** + * @see javax.faces.webapp.UIComponentTag#getRendererType() + */ + public String getRendererType() + { + return null; + } + + /** + * @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent) + */ + protected void setProperties(UIComponent component) + { + super.setProperties(component); + + setStringProperty(component, "value", this.value); + setStringProperty(component, "website", this.website); + setBooleanProperty(component, "monitor", this.monitor); + setStringProperty(component, "monitorIds", this.monitorIds); + setIntProperty(component, "snapshotVersion", this.snapshotVersion); + } + + /** + * @see org.alfresco.web.ui.common.tag.HtmlComponentTag#release() + */ + public void release() + { + super.release(); + this.value = null; + this.website = null; + this.monitor = null; + this.monitorIds = null; + this.snapshotVersion = null; + } + + /** + * @param value the value (the list of servers to deploy to) + */ + public void setValue(String value) + { + this.value = value; + } + + /** + * @param monitor Flag to indicate whether to select servers or show deployment progress + */ + public void setMonitor(String monitor) + { + this.monitor = monitor; + } + + /** + * @param monitorIds List of deployment monitor IDs to look for + */ + public void setMonitorIds(String monitorIds) + { + this.monitorIds = monitorIds; + } + + /** + * @param website NodeRef of the web project being deployed + */ + public void setWebsite(String website) + { + this.website = website; + } + + /** + * @param snapshotVersion The version of the snapshot to deploy to + */ + public void setSnapshotVersion(String snapshotVersion) + { + this.snapshotVersion = snapshotVersion; + } +} diff --git a/source/java/org/alfresco/web/ui/wcm/tag/DeploymentReportsTag.java b/source/java/org/alfresco/web/ui/wcm/tag/DeploymentReportsTag.java new file mode 100644 index 0000000000..8c2695e044 --- /dev/null +++ b/source/java/org/alfresco/web/ui/wcm/tag/DeploymentReportsTag.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.ui.wcm.tag; + +import javax.faces.component.UIComponent; + +import org.alfresco.web.ui.common.tag.BaseComponentTag; + +/** + * Tag class that allows the DeploymentReports component to be used on a JSP page. + * + * @author gavinc + */ +public class DeploymentReportsTag extends BaseComponentTag +{ + private String value; + + /** + * @see javax.faces.webapp.UIComponentTag#getComponentType() + */ + public String getComponentType() + { + return "org.alfresco.faces.DeploymentReports"; + } + + /** + * @see javax.faces.webapp.UIComponentTag#getRendererType() + */ + public String getRendererType() + { + return null; + } + + /** + * @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent) + */ + protected void setProperties(UIComponent component) + { + super.setProperties(component); + + setStringProperty(component, "value", this.value); + } + + /** + * @see org.alfresco.web.ui.common.tag.HtmlComponentTag#release() + */ + public void release() + { + super.release(); + this.value = null; + } + + /** + * Set the value (NodeRef of the web project) + * + * @param value the value + */ + public void setValue(String value) + { + this.value = value; + } +} diff --git a/source/test-resources/xforms/customer-tests/grumpy.burton.1.xsd b/source/test-resources/xforms/customer-tests/grumpy.burton.1.xsd new file mode 100644 index 0000000000..8aa2a5e949 --- /dev/null +++ b/source/test-resources/xforms/customer-tests/grumpy.burton.1.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/source/test-resources/xforms/demos/user-registration/user-registration.xsd b/source/test-resources/xforms/demos/user-registration/user-registration.xsd new file mode 100644 index 0000000000..639ca480c0 --- /dev/null +++ b/source/test-resources/xforms/demos/user-registration/user-registration.xsd @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Britsh Columbia + + + + + New Brunswick + + + + + New Foundland + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + minimal + + + + + + + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/interesting-schema-test/attribute-group-test.xsd b/source/test-resources/xforms/unit-tests/interesting-schema-test/attribute-group-test.xsd new file mode 100644 index 0000000000..147dbf2326 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/interesting-schema-test/attribute-group-test.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/interesting-schema-test/no-elements-test.xsd b/source/test-resources/xforms/unit-tests/interesting-schema-test/no-elements-test.xsd new file mode 100644 index 0000000000..ea40bc45c7 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/interesting-schema-test/no-elements-test.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/interesting-schema-test/readonly-and-default-values-test.xsd b/source/test-resources/xforms/unit-tests/interesting-schema-test/readonly-and-default-values-test.xsd new file mode 100644 index 0000000000..109afee3f1 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/interesting-schema-test/readonly-and-default-values-test.xsd @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + full + + + full + + + minimal + + + minimal + + + + + + + + + + + + + + + + + + + + full + + + full + + + minimal + + + minimal + + + + + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.ftl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.ftl new file mode 100644 index 0000000000..13c795ae83 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.ftl @@ -0,0 +1 @@ +
Value from data dictionary is ${.vars["include-test"]["in-data-dictionary"]}
diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.xsl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.xsl new file mode 100644 index 0000000000..fcd698f655 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-data-dictionary.xsl @@ -0,0 +1,10 @@ + + + + +
Value from data dictonary is
+
+
diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.ftl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.ftl new file mode 100644 index 0000000000..fd4c47a126 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.ftl @@ -0,0 +1 @@ +
Value from webapp is ${.vars["include-test"]["in-webapp"]}
diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.xsl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.xsl new file mode 100644 index 0000000000..9913061317 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test-webapp.xsl @@ -0,0 +1,10 @@ + + + + +
Value from webapp is
+
+
diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.ftl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.ftl new file mode 100644 index 0000000000..0d6997f62e --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.ftl @@ -0,0 +1,11 @@ + + + Include Test + + +
Generated by include-test.ftl
+
Value from template is ${.vars["include-test"]["in-template"]}
+ <#include "include-test-data-dictionary.ftl"> + <#include "include-test-webapp.ftl"> + + diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsd b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsd new file mode 100644 index 0000000000..7af58d033d --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsd @@ -0,0 +1,23 @@ + + + + + This form demonstrates methods of including templates from templates. To set up configure the form like this: + configure include-test.xsl and include-test.ftl as the rendering engine templates for the form. + upload include-test-data-dictionary.* into the data dictionary folder created for the form (e.g. Data Dictionary/Web Forms/include-test + upload include-test-webapp.* into the root of your webapp directory within the web project. + + When the rendering template gets executed, it should be able to include all auxilliary xsls and ftls. + + + + + + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsl b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsl new file mode 100644 index 0000000000..06e2e46159 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/rendering-engine-test/include-test.xsl @@ -0,0 +1,31 @@ + + + + + + + + + +
Value from template is
+
+ + + + + Include Test + + +
Generated by include-test.xsl
+ + + + + +
+
diff --git a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd index 053e0de289..3d2af4dd27 100644 --- a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd +++ b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd @@ -138,7 +138,7 @@ - + diff --git a/source/test-resources/xforms/unit-tests/simple-test/textarea-test.xsd b/source/test-resources/xforms/unit-tests/simple-test/textarea-test.xsd new file mode 100644 index 0000000000..373511fbd2 --- /dev/null +++ b/source/test-resources/xforms/unit-tests/simple-test/textarea-test.xsd @@ -0,0 +1,42 @@ + + + + + + + + + minimal + + + + + + + + full + + + + + + + + + minimal + + + + + + + full + + + + + + + diff --git a/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsd b/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsd deleted file mode 100644 index 36b99c9da1..0000000000 --- a/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsd +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - minimal - - - - - - - - - diff --git a/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsl b/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsl deleted file mode 100644 index ae49080b76..0000000000 --- a/source/test-resources/xforms/unit-tests/textarea-test/textarea-test.xsl +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - repeat-components - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
zero-to-one
one-to-one
- - one-to-inf - -
    - -
  • -
    -
-
- - zero-to-inf - -
    - -
  • -
    -
-
- - one-to-five - -
    - -
  • -
    -
-
- - zero-to-five - -
    - -
  • -
    -
-
- - one-to-five-multi - -
    - -
      -
    • -
    • -
    -
    -
-
- - zero-to-five-multi - -
    - -
  • -
      -
    • -
    • -
    -
  • -
    -
-
- - -
-
diff --git a/source/web/WEB-INF/alfresco.tld b/source/web/WEB-INF/alfresco.tld index 5f705c3c03..0029cd7fc8 100644 --- a/source/web/WEB-INF/alfresco.tld +++ b/source/web/WEB-INF/alfresco.tld @@ -1345,6 +1345,16 @@ Allows the BooleanLabelConverter to be used on a page + + + convertMultiValue + org.alfresco.web.ui.common.tag.MultiValueConverterTag + JSP + + + Allows the MulitValueConverter to be used on a page + + dynamicDescription diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index 7a9bc3a7f3..1a4779466e 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -2917,6 +2917,61 @@ + + + The bean that backs up the Deploy Snapshot Dialog + + DeploySnapshotDialog + org.alfresco.web.bean.wcm.DeploySnapshotDialog + session + + avmBrowseBean + #{AVMBrowseBean} + + + actionService + #{ActionService} + + + nodeService + #{NodeService} + + + + + + The bean that backs up the Monitor Deployment Dialog + + MonitorDeploymentDialog + org.alfresco.web.bean.wcm.MonitorDeploymentDialog + session + + avmBrowseBean + #{AVMBrowseBean} + + + nodeService + #{NodeService} + + + + + + The bean that backs up the View Deployment Report Dialog + + ViewDeploymentReportDialog + org.alfresco.web.bean.wcm.ViewDeploymentReportDialog + session + + avmBrowseBean + #{AVMBrowseBean} + + + nodeService + #{NodeService} + + + @@ -3162,5 +3217,14 @@ schema2XFormsProperties #{Schema2XFormsProperties} + + + + + Bean that returns deployment progress status + + DeploymentProgressBean + org.alfresco.web.bean.wcm.DeploymentProgressBean + request diff --git a/source/web/WEB-INF/faces-config-navigation.xml b/source/web/WEB-INF/faces-config-navigation.xml index 87a1acf34a..b9846cc20d 100644 --- a/source/web/WEB-INF/faces-config-navigation.xml +++ b/source/web/WEB-INF/faces-config-navigation.xml @@ -883,7 +883,11 @@ - /jsp/* + /jsp/* + + browseWebsite + /jsp/wcm/browse-website.jsp + browseSandbox /jsp/wcm/browse-sandbox.jsp diff --git a/source/web/WEB-INF/faces-config-wcm.xml b/source/web/WEB-INF/faces-config-wcm.xml index ae4905b2d8..1b6a644183 100644 --- a/source/web/WEB-INF/faces-config-wcm.xml +++ b/source/web/WEB-INF/faces-config-wcm.xml @@ -24,6 +24,15 @@ org.alfresco.web.ui.wcm.component.UIFormProcessor + + org.alfresco.faces.DeploymentReports + org.alfresco.web.ui.wcm.component.UIDeploymentReports + + + + org.alfresco.faces.DeployWebsite + org.alfresco.web.ui.wcm.component.UIDeployWebsite + diff --git a/source/web/WEB-INF/wcm.tld b/source/web/WEB-INF/wcm.tld index dd432095ba..585cd7b479 100644 --- a/source/web/WEB-INF/wcm.tld +++ b/source/web/WEB-INF/wcm.tld @@ -147,4 +147,89 @@ + + deploymentReports + org.alfresco.web.ui.wcm.tag.DeploymentReportsTag + JSP + Deployment Reports + Renders the latest deployment reports for a web project + + + id + false + true + The component identifier for this component + + + + value + true + true + The sandbox to show the list of snapshots for + + + + rendered + false + true + + + + + deployWebsite + org.alfresco.web.ui.wcm.tag.DeployWebsiteTag + JSP + Deploy Website + Renders a list of servers to deploy to or show deployment progress for + + + website + true + true + The NodeRef of the website to deploy or being deployed + + + + snapshotVersion + false + true + The version of the snapshot to deploy or being deployed + + + + value + true + true + The list of servers to deploy to + + + + id + false + true + The component identifier for this component + + + + rendered + false + true + Flag to determine whether component should be rendered + + + + monitor + false + true + Whether the component is monitoring a deployment + + + + monitorIds + false + true + List of deployment monitor ids to look for + + + diff --git a/source/web/css/main.css b/source/web/css/main.css index 939e730244..2452686f79 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -174,6 +174,14 @@ a.footer:hover padding: 2px; } +.mainHeading +{ + color: #004488; + font-size: 14px; + font-weight: bold; + padding-bottom: 2px; +} + .summary { color: #004488; @@ -632,3 +640,29 @@ a.sidebarButtonLink, a.sidebarButtonLink:link, a.sidebarButtonLink:visited font-weight: normal; font-size:12px; } + +.deployPanelCheckbox +{ + padding-left: 6px; + padding-right: 16px; +} + +.deployPanelStatusIcon +{ + padding-left: 9px; + padding-right: 17px; +} + +.deployPanelIcon +{ + padding-left: 12px; + padding-right: 12px; +} + +.deployPanelServerName +{ + color: #004488; + font-size: 14px; + font-weight: bold; + padding-bottom: 2px; +} diff --git a/source/web/images/icons/deploy.gif b/source/web/images/icons/deploy.gif new file mode 100644 index 0000000000000000000000000000000000000000..962d2a9bf6c5d2c2c4567756cf3aeff73e5c0499 GIT binary patch literal 598 zcmZ?wbhEHb6l4%&c*Xz%|NsB*=;%0h{OFDy+m#EXTXuh|-}th9=cmp+Uwig{Yuxa- zd&Tj#o$p&V+-qHPwQl}_hWQ8T=j@ujYG>or6_Z!)nZ9(x>g@;SuG-w#-TUkB@AGdi z-}-R(<+s;EdS57&7_r&L~pWc6b_u}=lN6+p*eer1i z!ntqWz54#++uL_ zX>DTa=xFQgVq)&^>0z176x7Ge#5imAET$>bW&{R$db@}SdoG$cwL@Ru&WDdp$kEkc zUDq^QTWfwUPH``1kKI$-&CDdZIe7iu8Ci|Yj!iQ+ck&fr=MlTWYI=pq#zrE*kM+e1 z4OYW;CJPIDH$he@S!pdb literal 0 HcmV?d00001 diff --git a/source/web/images/icons/deploy_failed.gif b/source/web/images/icons/deploy_failed.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ad5d8d06800a2ecde0da88fbb16dc86ef152fe1 GIT binary patch literal 374 zcmZ?wbhEHb6krfwxXJ(m|NsBbDz0too1TzW(%3b*p>tAQTi?bV`}Z6=v3|?WCokVU zdj96ammlvweQW8Ry7$Pb9s7@-ICuH*$#a`_9eDNr^NY71pS^zn<;U+&-+t~ra`M5m zSJ!Xd`Tpns*I$3%eEf2Tf#FPA8qf-`Rn#XGf3h$#FeowTfQ$zDiGgjh!^D6k76N_j zM+;60@~F&Rk)rUxfK#f!?Da)~HBOF9&U({@nHD~pc(TFitq;eQIt~8GZpm`D_J0*- zS7PC7R*tt_A(@BPfgXhp;9*%e)CN@FoGlFcP-p;P>ES?vy-*9$hum%8ieTB6E literal 0 HcmV?d00001 diff --git a/source/web/images/icons/deploy_large.gif b/source/web/images/icons/deploy_large.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6384ada9f3c892082a7cc111f333b6f198edcba GIT binary patch literal 1366 zcmd6m>sOKo0LGEXgR?f9%V@JDnU$tXyX;i+gKl9~yQn$SY+GJ(9%nnJ>&&FknSdIp zdC8oD2+9is;T7a!rX`^W7y^nf8iw4Y$O~C%rEc!8*z@7}_?+K|-*fm#)cyl0elS1S z8`w&gmzVF{t!FUV)pd=Ro3vM&hjUx>xy{2^rXdf2@)#pmTlCjhqgVjC!7~x~7JQqT zD6kR*mJ*@8L})7&*>80`BS{?PolYXxKxFGkAVdIEH-X+;jGi(;N}}DXV04$abd@x; zmD9wxn*MD}9-(*i() zrOJt1sEDa9=IDwTN_=xKiP=kPc~D9bl-9T2rnR?#ot5>?WIC&!(o}P|p3QAz@WgB` z$Y8Oj7G~xb7k+q{k|w|Khx$g2x+q^q%GZ)g^fi?Ra+QHXHUbP24={nCRRUThZPt!^ zlRcf2(q5-Z_FSo+9vYk;Hn@zI*Y+e?R=WJcSykTes=NXnsaRiKs;{XskgG>24Mqmp z$e8h}&X`$4=ae%>^%F1v$4Lka$`)=P`3Yt+GF}OjyVJm3_VP zN7|u5wPs*`;mxbpb91j=zMON7Kzh}Hvh)5uu|(7^6ga0Gy5Yf>bF(wEQ}#)#&2E`6 zKh+IsR0E2kVa?Q()8Viijbjj`fBSa9Y@Qe&H$u>eR;!W89!aG=_wRR##Uehx4Fq{K zTGP_f(&FOc{QSJj<#IZmHk%ECAdN<&R4QdMSyxw=NF)*pg&+uWI2-@~=yW=nOm1js zsI9Ff5D5P|_MdD2yFxD@++Z*jEO>=%!^Tj%5A1|#p;ZA5+(~f8B_x$V@$NW~z(sQbIV#5@Bvn-gy+f&>p1J*#iGl~k2 z=k(*vfpscBYT?FgDEK6%`chw5dJ>oF6}Vd)m|aU;w=eb34El5}nD+2u1|8|0$WD&T zOr-cV;diGA6E>}K_jX`T;m$dZHX{&g*K7!lL7nrQOiGu)&91t5SL>OBTN6cPCOF=o z8K;V~&DEs$E6)Q1`?72C9{62KuksJ7&c=foYm@6eFHy$xiyQYhM!K)|Tpz`d+&o$Z zrgpDt^f~lXSqPk!iN%Gw!AWi)DP;NZkBWp#k&GnZS4?)&i>(1)hT}}B__Ze)Cqw*Y z%<^1a6(aEnTG5v}8iW?jz&&^F@IwS~gO5iC6a~k5WL2kU%KhXh-dJ!rUmXDt^2H&7 zdbjQ&1QekvkXaNdDlJ&S-=g^F!yR1MDtB50B19qmxCwn7bsib%b%ScD_-pLz0yiW| zJy99oj>2z_%AymupSmoT?~WLY!J%=Xyu#0~6q+y_lDlW!Kf|J^eHc!tx7f5Wm5Q5vzqCi48v&wejlS zeq~@w%tY*=A~hQCbArDo67y+XcuJ9X`q*G*oG&`w+WOr{3UZ5gSbFrP4j)!b$%UYf VGIZ&FMGRk)@Y@T4#vK9s>K`t=tV;j@ literal 0 HcmV?d00001 diff --git a/source/web/images/icons/deploy_server.gif b/source/web/images/icons/deploy_server.gif new file mode 100644 index 0000000000000000000000000000000000000000..0806ad38cf897c9f50bfe1bfadc0d48c50b72afe GIT binary patch literal 583 zcmZ?wbhEHb6krfwc*Xz%|NsC0^XK31-+%x9{rBh3-;bZa|NQmm`Rk9Lzy4UVYSW?> z8&<5__V&Yu9Ty(Cn_Pk+Teb1Y&V4VB9(Z~D{JSen zSNfW-^iRAwXVT5Ni|()9@MOpO$J-CQJa+HP!~0(zId2UJ*cEf({gwJt?Mtt(4B8Z- zSRkq2sRr~T*sp_*Q2fcl$iU#spaXIlC{7sImo)e`HOUFKwYSMNH>_aB%9JIR8k(6UsHt0KFU{n5 z#-+%8Dk^3vpiaeRh8HIBEf2&@B8Hd;%l#Gmy!ZM1_W8We51&t1L}<`K3>*Xp&48BR zbUGcgbM~2823y49NUXLQDuYX*bI7zR7FWvTNElUOI$I>Fek_nF`Od}D<%kqj z!kTKON?zYAt80?hK9wk*h-(_BEVdE~tC-B3n6i#fT5xH^-%~QN$v1GRSqb=CN!N3( zq-S5gModg2;4^QtM9Qa~11;Sz+g}(SP+3$akHX-R=^PTRO80V<$q_TEM0B>0FRkNA zYPn(sM^sZKtY!=3m3&zRPs-v-s+G<1`X-5@QC#y_RNWwyD+RK8!^mVpY8EbykeHU0 zoRO1sJ^M;JF)gb=q-=fCIiPx`Z|)jw(hjus43|(@#T4d!GNb6>qYj;+s~^zz89RGl z^$d-455DeyHQr|!>m44g;7NvFPt-lp7{}g@ny1xmos-ia%(R*K`j(8vuHS-jvbUgMewkIR4r+Wtw_F_1@Ufu2^X zr_&5v4j|(Fw_UB1+V1Jz=hJ<9t6{`G4i)Y`(|Rek{c2)Y z=H;%;Y+ccx{SOQK%S!dMhePy71`f@@p&Ph7KvumJqG~j$TPHh%W#J(;$D`_gNu_4! zt;0iB!>E1yR0HaK6E5Sg?BeGn{-7wCfk#nLNHP*lMWZQb3>9M>F)lh6k)(5I3JOI= zVyI{o35iJBxc`qGpJw*o-2PvJm<2Bbfu4c(F4bE41jx+^Dqp!d+_I)T$8G)YimQ3_ zkbJ!BI!d^d*|NbsAea>s9$j(|9&&5L1vge`!IdNPz7m4#TGy{Hd0^4%Jh#I;jzKE6 z9n#!^t$;KUi15%tuzzd;wj^e}b(!~Xr?@I&j^~~&B5aGd>S#!u1tl8zojx6zE`1fLA0kIoZ`A(RsBHDab7jTBD+3o2QRv3A=r)3Q( zZ!W}24J!WCOAz%y0BzrO&+o?$Z>CNa?GNz)j5$XO?|+fNuV=e`r3J@m@;3co1XkX_ zg?ens^b1%W(DpgQ8@yMMu7Y{L1Bb@8z4U0l8)PU@Z^meRJ+=h+$qT_pye`BZIOs!m zS#{1)cj8M#H2mU${9I@Uf?%RoLXklc`7p$Bi5k+9D^smvfc(cG$wr{k3t@rBljGUD zcDirF0o!2+n{j99&*vxN-BV(Li>nb1I>$ZCOU`lkISy?1MEF|Nm87_jE}QqJUta;G zAoayjfpAQI*$ECo!xJc!=JhAjw;pT}$onvSVf@&t=1j>F? z-e{=3+0=Neh4l_==Uw(*yPfnq)dKdqgzR$zx()0`oP^>}7DfgJQwAN73Xq=|*p?rd zwV^DCgM+2W7vw0Y;jO*;;}`}p6^pHPrv{4_507?6Xq;Gc<$DLvo~9Mryjj{ zr)S0@h86$!-Z&w&R_o87Kfiwc`uX$cj~_q2fB*jN+qW-YzI^`t`QyirA3l6||Ni~E zckkZ5ef#?L>z6NIzIgHC`Sa(`o;`c|^y%Zrj~_jH^zh-s2M-?HyLa!xg$rxeteG}# zT6cGMQ&Ur8V`F7yCD5B-?+z|P@h1x-1A`xf4#-)cIALHv-JmSm+|sP<*U_oT($mYt zs@d7atSvK5#%rd>?Ad;rsxlmlIDGW=4UA1a+&wkfrcU=UG&C|X^YHT3RN>z%AmC$S zY+|ZwX}wlRP5O+qkEx!no`sdoT0v<63!Xp@e`14W0eX_6;n8mrfmSW0iK0Nf2teZ>O}@D#sz=;UQKvrxqSb qrzIT|!?dQECLc2D^q%e=G{?d)k*RC8h>~ZK(h7lv&eqI~4Aubun*ZVe literal 0 HcmV?d00001 diff --git a/source/web/images/icons/deployment_report_large.gif b/source/web/images/icons/deployment_report_large.gif new file mode 100644 index 0000000000000000000000000000000000000000..64fc26dab104ba11ff329a8bbfe4a3ec9a228653 GIT binary patch literal 1472 zcmd^;{ZrEg0EdSl15%V>hGYnv!g#p~rJ6#T;2~W}C05vl2WJ@pow$&EA$7bQFI`DP zk6<(QzJ2$;G37;sjSU!rvMOGDGxmi(FM`ZU7j46g>bEA{< z_b@~Zf!>Y>+HkbrI;c}~Is%P@r?PPr7K7JK=XOz90t&N}%;1ygJR-mq^orPm$E?m? zCckGvXD+>ZyR7ogi>ao8TWYd}s3hVj2 zo2|waE|=5kbT}Lv8yj}JeSLl1X0xrWty!(s)z#INl@*J{Vm6yiCX>-< zG#Cua%gakkOM1Otr_*V*+Qr31jYgwZt5qu1!otG*{Jc`BoST~)A0L-UBtoIEudlDG zt4kmd@cDcmkH_V5IUEj~&1SJ!OeT}TV9@Dw003w-8kI_=P$*+ppDv94yi^U_h#mC4~}7zA>8s;31k zC!I(j=1h;ZzClG?-X?B5Qvb_qz3Bbtx7o|XAiJ7jS^9$s6NTMKi)u745ppOGRas(v z4=*stv3lwGg6;`*#*O%|XSAV{xo}eA6itYEC*hb7^|-(D`mO^fZpWOTaSvs!F1?JH z2C|eBMQJ56t6>q`Y-uwKA1pYhD7Jb>W=>r4il7!8zUR95*V9Pb2paMGCvi<5M{63s zi@vH32+zOd76xL2AUSmx!sNuebx}wu?A-DDwcytUp(4y>BsBhBg}gDOJsnVqUW%}f z4tJE5XG(Fkd(TqZ8V(Yqur{-x4h%W}N!#DL4CCteD^O+0#a-Eb~8?(OgaC4LdP9Q6P(z5HY_PURDE(=+EnT4leGNQ%)HzJ zd|kNf`7HW_A RO;6cldz$jip537Ie*kLMx3B;J literal 0 HcmV?d00001 diff --git a/source/web/images/parts/deploy_panel_bg.gif b/source/web/images/parts/deploy_panel_bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5e780b2949e7396a280940396a0e72e35f0bc7c GIT binary patch literal 263 zcmV+i0r>t$Nk%w1VG0090K@hJRK^!D%b_3rZY`1piDK#Ool#2Amrf^x~sIG<31bV_YluUL(C%XN6a;BfdsE}PHih| z75Kb@h>41ejE#zF3zwd%@FbA_AWW& z^5VaOX&|IHo?$^U&BdrVnMlRr$s`LBX^u{@RDyw$%tH|fkc!hWk_zucqEws{Aj=DB zz>BgBB}ouP9zuemBv~dYDwD|o0631LX?kDqpXmQs8hA*7AU6>00o=hSNPhO|@vg2D zCvy~vj-HMtU13G3qVrY1q5YI8ckoSaXHk`YXjrd2tZB2ox8+qdjgF0?mE+^6>ZpCf zj+Qq&rW{zy?A$DN%;|Ds*F0ViR)VkLnARWgW38LNH?jIqIJC7L#?BEW5u-@#B9mgU zV!#8eQIaKbPku5`VS1z#&aS*}d0be0osHZYZ11i6I8nCiMJ?90s}@7I zZ=}JZPOe%<{HHIKe=r$7X^X1V{g&I4)`AzxYV>)nxm7=%uc|H38gh>G{Xw1~$mPE> CZcxMk literal 0 HcmV?d00001 diff --git a/source/web/images/parts/deploy_panel_separator.gif b/source/web/images/parts/deploy_panel_separator.gif new file mode 100644 index 0000000000000000000000000000000000000000..496c1bc0b952fe14d2ab6b694be85f8df6b2b976 GIT binary patch literal 194 zcmZ?wbhEHbWMc4OIKlt||NsAg`0&x*Bd5<^xP0UGz3aE`Ub}hc?)`^%?mc+$@X^If zmv=TC4D r(qK_I-k>Ou$i~;`Rid>vX#F*vvej>k_D6X)2t=^3HJ?;rVXy`O-#=m> literal 0 HcmV?d00001 diff --git a/source/web/images/parts/deploy_panel_start.gif b/source/web/images/parts/deploy_panel_start.gif new file mode 100644 index 0000000000000000000000000000000000000000..aab1b8ea3e4549e0873abcecd7bfe32a4e78e1fc GIT binary patch literal 468 zcmV;_0W1DTNk%w1VG0090M!5h00030|NrRe>%GLw(%InNFT$_%)7?Wz{=CT$kDvV(9hT2!N|_T&DFTU$k5f< z-{k1-^7ZZU^yBC1*4^Us_W1Jk_wn@h=j!b0@AB~U_V4rc?(+2b`uq3!`u6zw=IibC z`1$nr`1AJn`TP6#`T73;|NQ;^`~3Xs>+Ajf{r~^}0000000000000000000000000 z00000A^8LW001`tEC2ui015y|000K@z(8O|$V`sMfP=zWsAACA>|&$AuGj*k;ploD z6-a7K9!tb!@>#`hv)AtS89}ep&#SyXe{T8zerE}Tgo9@;h>3`23XP79XCac4l4mcM zn3rcFoSmGTo}FhSq@|>zrln^ltgWnP2eGoTXD7C|wzasoXC1!3zGo=I#KXeH#AhDM z%*$sb(9zJ(($Un_CD+y3(%jY%*wf(Q-s0ieh!(y7m#2)gY()wI9Fl8IRYR~u$V}Z#S9A&NPO7HQOSf23~C67KvKvI0~j<6SUEt5 KOBrs0002Av?If`P literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_01.gif b/source/web/images/parts/innerwhite_01.gif new file mode 100644 index 0000000000000000000000000000000000000000..0442fdd06fdf7b4c0afc2fd44b6913ad3a6e2862 GIT binary patch literal 60 zcmZ?wbhEHbWM^P!n8*ME|Ns9#bLI??RQ$=p$iTqNpaT*G$ultV&QZ^l?B$i`N!ph6 IQHQ}A03rSm^#A|> literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_02.gif b/source/web/images/parts/innerwhite_02.gif new file mode 100644 index 0000000000000000000000000000000000000000..bc45b522648014dd26b91a5b2c7650d970aaef3e GIT binary patch literal 55 zcmZ?wbhEHbWM^P!n8*ME|Ns9#bLI??RQ$=p$iTqNpaT*G$ulr`YnGfBZD;n D*PIW~ literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_03.gif b/source/web/images/parts/innerwhite_03.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a6d85b793d7948175f7e556b82180c9d29d6e4c GIT binary patch literal 60 zcmZ?wbhEHbWM^P!n8*ME|Ns9#bLI??RQ$=p$iTqNpaT*G$ultVPH7je-t}f)$EQ$f I7e)qa05;|lXaE2J literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_04.gif b/source/web/images/parts/innerwhite_04.gif new file mode 100644 index 0000000000000000000000000000000000000000..8c9e99bc40e958bef712d84b62d1f1918634f6eb GIT binary patch literal 57 zcmZ?wbhEHbWM^P!n8*ME|Ns9#bLI??RQ$=p$iTqNpaT*G$ulr9x30a%^>}Mk Is~&?j05p*jpa1{> literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_08.gif b/source/web/images/parts/innerwhite_08.gif new file mode 100644 index 0000000000000000000000000000000000000000..c8f1a8b840b08526b8ddd76192710860d4b119d8 GIT binary patch literal 55 zcmZ?wbhEHbWM^P!n8*ME|Ns9#bLI??RQ$=p$iTqNpaT*G$ulr<^z^Sht;O%k$Y2cs D)%p)r literal 0 HcmV?d00001 diff --git a/source/web/images/parts/innerwhite_09.gif b/source/web/images/parts/innerwhite_09.gif new file mode 100644 index 0000000000000000000000000000000000000000..b440024c05bb290e40ffc77f06e7091e88111e08 GIT binary patch literal 64 zcmZ?wbhEHb - + diff --git a/source/web/jsp/wcm/create-form-wizard/details.jsp b/source/web/jsp/wcm/create-form-wizard/details.jsp index 1c2675f232..3bd29714c3 100644 --- a/source/web/jsp/wcm/create-form-wizard/details.jsp +++ b/source/web/jsp/wcm/create-form-wizard/details.jsp @@ -25,6 +25,7 @@ <%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> <%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> <%@ page import="org.alfresco.web.bean.wcm.CreateFormWizard" %> +<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %>
+ + - +   - +   - + +   + + <%-- Disabled action for GA - + --%>
@@ -138,6 +144,29 @@ + + + + + - +
+ + + + + + + + + + + +
diff --git a/source/web/jsp/wcm/deploy.jsp b/source/web/jsp/wcm/deploy.jsp new file mode 100644 index 0000000000..643fe5919d --- /dev/null +++ b/source/web/jsp/wcm/deploy.jsp @@ -0,0 +1,36 @@ +<%-- + * Copyright (C) 2005-2007 Alfresco Software Limited. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing +--%> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> +<%@ taglib uri="/WEB-INF/wcm.tld" prefix="w" %> + +<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> + + diff --git a/source/web/jsp/wcm/deployment-report.jsp b/source/web/jsp/wcm/deployment-report.jsp new file mode 100644 index 0000000000..246bca655f --- /dev/null +++ b/source/web/jsp/wcm/deployment-report.jsp @@ -0,0 +1,44 @@ +<%-- + * Copyright (C) 2005-2007 Alfresco Software Limited. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing +--%> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> +<%@ taglib uri="/WEB-INF/wcm.tld" prefix="w" %> + +<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> + + + + + + + + + + + diff --git a/source/web/jsp/wcm/monitor-deployment.jsp b/source/web/jsp/wcm/monitor-deployment.jsp new file mode 100644 index 0000000000..10f9f9061b --- /dev/null +++ b/source/web/jsp/wcm/monitor-deployment.jsp @@ -0,0 +1,36 @@ +<%-- + * Copyright (C) 2005-2007 Alfresco Software Limited. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing +--%> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> +<%@ taglib uri="/WEB-INF/wcm.tld" prefix="w" %> + +<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> + + \ No newline at end of file diff --git a/source/web/jsp/wcm/output-path-pattern-help.jsp b/source/web/jsp/wcm/output-path-pattern-help.jsp index 07de5758c2..65129f572f 100644 --- a/source/web/jsp/wcm/output-path-pattern-help.jsp +++ b/source/web/jsp/wcm/output-path-pattern-help.jsp @@ -20,7 +20,7 @@
webappThe name of the webapp in which the form instance data is being created. Typically, if specifying an absolute output path pattern, the path will begin with the webapp folder (i.e. /${webapp}/...)
extensionThe default extension associated with the mime-type configured for the rendering engine template. This variable is only available for rendition ouput path patterns.
xmlThe xml instance data collected by the form.
nodeThe form instance data node.
nodeThe form instance data node. This variable is only available for rendition ouput path patterns.
dateThe current date at which the form instance data is being saved. Refer to the FreeMarker date reference for more information.
diff --git a/source/web/jsp/wcm/tiny_mce_image_dialog.jsp b/source/web/jsp/wcm/tiny_mce_image_dialog.jsp new file mode 100644 index 0000000000..416c522d2e --- /dev/null +++ b/source/web/jsp/wcm/tiny_mce_image_dialog.jsp @@ -0,0 +1,189 @@ + + + + + + + + + + {$lang_insert_image_title} + + + + + + + +   + + + + + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + + +  
+
+
+
+ x +
+
+
+ +
+
+ +
+ +
+ +
+
+
+ + +
diff --git a/source/web/jsp/wcm/tiny_mce_link_dialog.jsp b/source/web/jsp/wcm/tiny_mce_link_dialog.jsp new file mode 100644 index 0000000000..1344c0d137 --- /dev/null +++ b/source/web/jsp/wcm/tiny_mce_link_dialog.jsp @@ -0,0 +1,187 @@ + + + + + + + + + + {$lang_insert_link_title} + + + + + + + +   + + + + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + + +  
+
+
+
+ +
+
+
+
+
+ +
+ +
+ +
+
+
+ + +
diff --git a/source/web/scripts/ajax/ajax_helper.js b/source/web/scripts/ajax/ajax_helper.js new file mode 100644 index 0000000000..e4e0546d05 --- /dev/null +++ b/source/web/scripts/ajax/ajax_helper.js @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +//////////////////////////////////////////////////////////////////////////////// +// Ajax helper library +// +// This script manages ajax requests and provides a wrapper around the dojo +// library. +// +// This script requires dojo.js to be loaded in advance. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// AJAX helper +//////////////////////////////////////////////////////////////////////////////// + +alfresco = typeof alfresco == "undefined" ? {} : alfresco; +alfresco.constants = typeof alfresco.constants == "undefined" ? {} : alfresco.constants; +alfresco.constants.AJAX_LOADER_DIV_ID = "alfresco-ajax-loader"; + +alfresco.AjaxHelper = function() +{ +} + +/** Creates an ajax request object. */ +alfresco.AjaxHelper.createRequest = function(target, serverMethod, methodArgs, load, error) +{ + var result = new dojo.io.Request(alfresco.constants.WEBAPP_CONTEXT + + "/ajax/invoke/XFormsBean." + serverMethod, + "text/xml"); + result.target = target; + result.content = methodArgs; + result.method = "POST"; + result.load = load; + dojo.event.connect(result, "load", function(type, data, evt) + { + alfresco.AjaxHelper._loadHandler(result); + }); + result.error = error || function(type, e, impl) + { + dojo.debug("error [" + type + "] " + e.message); + if (impl.status == 401) + { + document.getElementById("logout").onclick(); + } + else + { + _show_error(document.createTextNode(e.message)); + alfresco.AjaxHelper._loadHandler(this); + } + }; + return result; +} + +/** Sends an ajax request object. */ +alfresco.AjaxHelper.sendRequest = function(req) +{ + alfresco.AjaxHelper._sendHandler(req); + req.encoding = "utf-8"; + dojo.io.queueBind(req); +} + +/** + * Returns the ajax loader div element. If it hasn't yet been created, it is created. + */ +alfresco.AjaxHelper._getLoaderElement = function() +{ + var result = document.getElementById(alfresco.constants.AJAX_LOADER_DIV_ID); + if (result) + { + return result; + } + result = document.createElement("div"); + result.setAttribute("id", alfresco.constants.AJAX_LOADER_DIV_ID); + dojo.html.setClass(result, "xformsAjaxLoader"); + dojo.html.hide(result); + document.body.appendChild(result); + return result; +} + +/** All pending ajax requests. */ +alfresco.AjaxHelper._requests = []; + +/** Updates the loader message or hides it if nothing is being loaded. */ +alfresco.AjaxHelper._updateLoaderDisplay = function() +{ + var ajaxLoader = alfresco.AjaxHelper._getLoaderElement(); + ajaxLoader.innerHTML = (alfresco.AjaxHelper._requests.length == 0 + ? alfresco.xforms.constants.resources["idle"] + : (alfresco.xforms.constants.resources["loading"] + + (alfresco.AjaxHelper._requests.length > 1 + ? " (" + alfresco.AjaxHelper._requests.length + ")" + : "..."))); + if (djConfig.isDebug) + { + dojo.debug(ajaxLoader.innerHTML); + } + if (/* djConfig.isDebug && */ alfresco.AjaxHelper._requests.length != 0) + { + dojo.html.show(ajaxLoader); + } + else + { + dojo.html.hide(ajaxLoader); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// ajax event handlers +//////////////////////////////////////////////////////////////////////////////// + +alfresco.AjaxHelper._sendHandler = function(req) +{ + alfresco.AjaxHelper._requests.push(req); + alfresco.AjaxHelper._updateLoaderDisplay(); +} + +alfresco.AjaxHelper._loadHandler = function(req) +{ + var index = alfresco.AjaxHelper._requests.indexOf(req); + if (index != -1) + { + alfresco.AjaxHelper._requests.splice(index, 1); + } + else + { + var urls = []; + for (var i = 0; i < alfresco.AjaxHelper._requests.length; i++) + { + urls.push(alfresco.AjaxHelper._requests[i].url); + } + throw new Error("unable to find " + req.url + + " in [" + urls.join(", ") + "]"); + } + alfresco.AjaxHelper._updateLoaderDisplay(); +} diff --git a/source/web/scripts/ajax/file_picker_widget.js b/source/web/scripts/ajax/file_picker_widget.js new file mode 100644 index 0000000000..f8543e3576 --- /dev/null +++ b/source/web/scripts/ajax/file_picker_widget.js @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +//////////////////////////////////////////////////////////////////////////////// +// FilePickerWidget +// +// This script communicates with the XFormBean to manage a file picker widget +// for selecting and uploading files in the avm. +// +// This script requires dojo.js, ajax_helper.js and upload_helper.js to be +// loaded in advance. +//////////////////////////////////////////////////////////////////////////////// +alfresco = typeof alfresco == "undefined" ? {} : alfresco; + +/** + * The file picker widget. + */ +alfresco.FilePickerWidget = function(uploadId, node, value, readonly, change_callback, resize_callback) +{ + this.uploadId = uploadId; + this.node = node; + this.value = value == null || value.length == 0 ? null : value; + this.readonly = readonly || false; + this.change_callback = change_callback; + this.resize_callback = resize_callback; +} + +// static methods and properties + +alfresco.FilePickerWidget._uploads = []; +alfresco.FilePickerWidget._handleUpload = function(id, fileInput, webappRelativePath, widget) +{ + alfresco.FilePickerWidget._uploads[id] = + { + widget:widget, + path: fileInput.value, + webappRelativePath: webappRelativePath + }; + + handle_upload_helper(fileInput, + id, + alfresco.FilePickerWidget._upload_completeHandler, + alfresco.constants.WEBAPP_CONTEXT, + "/ajax/invoke/XFormsBean.uploadFile", + { currentPath: webappRelativePath }); +} + +alfresco.FilePickerWidget._upload_completeHandler = function(id, path, fileName, fileTypeImage, error) +{ + var upload = alfresco.FilePickerWidget._uploads[id]; + upload.widget._upload_completeHandler(fileName, + upload.webappRelativePath, + fileTypeImage, + error); +} + +// instance methods and properties + +alfresco.FilePickerWidget.prototype = { + +getValue: function() +{ + return this.value; +}, + +setValue: function(v) +{ + this.value = (v == null || v.length == 0 ? null : v); + if (this.selectedPathInput) + { + this.selectedPathInput.value = v; + } + + this.change_callback(this); +}, + +setReadonly: function(r) +{ + this.readonly = r; + if (this._selectButton) + { + this._selectButton.disabled = this.readonly; + } + else if (this.readonly) + { + this._showSelectedValue(); + } +}, + +render: function() +{ + this._showSelectedValue(); +}, + +_showStatus: function(text, isError) +{ + var d = this.node.ownerDocument; + if (!this.statusDiv || !this.statusDiv.parentNode) + { + this.statusDiv = d.createElement("div"); + this.statusDiv.setAttribute("id", this.uploadId + "-status"); + this.statusDiv.widget = this; + this.node.insertBefore(this.statusDiv, this.node.firstChild); + dojo.html.setClass(this.statusDiv, "infoText xformsFilePickerStatus"); + if (isError) + { + dojo.html.addClass(this.statusDiv, "statusErrorText"); + } + this.statusDiv.appendChild(d.createTextNode(text)); + this.node.style.height = (parseInt(this.node.style.height) + + dojo.html.getMargin(this.statusDiv).height + + this.statusDiv.offsetHeight) + "px"; + this.resize_callback(this); + } + else + { + this.statusDiv.firstChild.nodeValue = text; + } + setTimeout("var _status = document.getElementById('" + this.uploadId + + "-status'); if (_status && _status) { _status.widget._hideStatus(); }", 5000); +}, + +_hideStatus: function() +{ + if (this.statusDiv) + { + var anim = dojo.lfx.html.fadeOut(this.statusDiv, 500); + var _fp_widget = this; + anim.onEnd = function() + { + if (_fp_widget.statusDiv && _fp_widget.statusDiv.parentNode) + { + _fp_widget.node.style.height = (parseInt(_fp_widget.node.style.height) - + _fp_widget.statusDiv.offsetHeight) + "px"; + dojo.dom.removeChildren(_fp_widget.statusDiv); + dojo.dom.removeNode(_fp_widget.statusDiv); + _fp_widget.resize_callback(_fp_widget); + _fp_widget.statusDiv = null; + } + }; + + anim.play(); + } +}, + +_showSelectedValue: function() +{ + var d = this.node.ownerDocument; + dojo.dom.removeChildren(this.node); + this.statusDiv = null; + this.contentDiv = null; + this.addContentDiv = null; + + this.node.style.height = "20px"; + this.node.style.lineHeight = this.node.style.height; + this.node.style.position = "relative"; + this.node.style.whiteSpace = "nowrap"; + + this.resize_callback(this); + + this.selectedPathInput = d.createElement("input"); + this.selectedPathInput.type = "text"; + this.selectedPathInput.value = this.value == null ? "" : this.value; + this.node.appendChild(this.selectedPathInput); + + dojo.event.connect(this.selectedPathInput, "onblur", this, this._selectPathInput_changeHandler); + + this._selectButton = d.createElement("input"); + this._selectButton.filePickerWidget = this; + this._selectButton.type = "button"; + this._selectButton.value = this.value == null ? "Select" : "Change"; + this._selectButton.disabled = this.readonly; + this._selectButton.style.margin = "0px 10px 0px 10px"; + this.node.appendChild(this._selectButton); + + this.selectedPathInput.style.width = (1 - + ((this._selectButton.offsetWidth + + dojo.html.getMargin(this._selectButton).width) / + dojo.html.getContentBox(this.node).width)) * 100 + "%"; + dojo.event.connect(this._selectButton, + "onclick", + this, + this._selectButton_clickHandler); +}, + +_selectButton_clickHandler: function(event) +{ + var w = event.target.filePickerWidget; + w._navigateToNode(w.getValue() || ""); +}, + +_selectPathInput_changeHandler: function(event) +{ + this.setValue(event.target.value); +}, + +_navigateToNode: function(path) +{ + var req = alfresco.AjaxHelper.createRequest(this, + "getFilePickerData", + {}, + function(type, data, evt) + { + this.target._showPicker(data.documentElement); + }); + req.content.currentPath = path; + alfresco.AjaxHelper.sendRequest(req); +}, + +_showPicker: function(data) +{ + while (this.node.hasChildNodes() && + this.node.lastChild != this.statusDiv) + { + this.node.removeChild(this.node.lastChild); + } + + var d = this.node.ownerDocument; + this.node.style.height = (200 + + (this.statusDiv + ? (parseInt(this.statusDiv.style.height) + + parseInt(this.statusDiv.style.marginTop) + + parseInt(this.statusDiv.style.marginBottom)) + : 0) + "px"); + + this.resize_callback(this); + + var currentPath = data.getElementsByTagName("current-node")[0]; + currentPath = currentPath.getAttribute("webappRelativePath"); + var currentPathName = currentPath.replace(/.*\/([^/]+)/, "$1") + + var headerDiv = d.createElement("div"); + dojo.html.setClass(headerDiv, "xformsFilePickerHeader"); + this.node.appendChild(headerDiv); + headerDiv.appendChild(d.createTextNode("In: ")); + this.headerMenuTriggerLink = d.createElement("a"); + this.headerMenuTriggerLink.filePickerWidget = this; + this.headerMenuTriggerLink.style.textDecoration = "none"; + this.headerMenuTriggerLink.setAttribute("href", "javascript:void(0)"); + this.headerMenuTriggerLink.setAttribute("webappRelativePath", currentPath); + dojo.html.setClass(this.headerMenuTriggerLink, "xformsFilePickerHeaderMenuTrigger"); + headerDiv.appendChild(this.headerMenuTriggerLink); + + dojo.event.connect(this.headerMenuTriggerLink, + "onmouseover", + function(event) + { + event.currentTarget.style.backgroundColor = "#fefefe"; + event.currentTarget.style.borderStyle = "inset"; + }); + dojo.event.connect(this.headerMenuTriggerLink, + "onmouseout", + function(event) + { + var w = event.currentTarget.filePickerWidget; + if (!w.parentPathMenu) + { + event.currentTarget.style.backgroundColor = + event.currentTarget.parentNode.style.backgroundColor; + event.currentTarget.style.borderStyle = "solid"; + } + }); + dojo.event.connect(this.headerMenuTriggerLink, + "onclick", + function(event) + { + var t = event.currentTarget; + var w = t.filePickerWidget; + if (w.parentPathMenu) + { + w._closeParentPathMenu(); + } + else + { + w._openParentPathMenu(t, t.getAttribute("webappRelativePath")); + } + }); + + this.headerMenuTriggerLink.appendChild(d.createTextNode(currentPathName)); + + headerMenuTriggerImage = d.createElement("img"); + this.headerMenuTriggerLink.appendChild(headerMenuTriggerImage); + this.headerMenuTriggerLink.image = headerMenuTriggerImage; + headerMenuTriggerImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/menu.gif"); + headerMenuTriggerImage.style.borderWidth = "0px"; + headerMenuTriggerImage.style.marginLeft = "4px"; + headerMenuTriggerImage.align = "absmiddle"; + + var headerRightDiv = d.createElement("div"); + + var addContentLink = d.createElement("a"); + headerRightDiv.appendChild(addContentLink); + addContentLink.setAttribute("webappRelativePath", currentPath); + addContentLink.filePickerWidget = this; + addContentLink.setAttribute("href", "javascript:void(0)"); + dojo.event.connect(addContentLink, + "onclick", + function(event) + { + var w = event.target.filePickerWidget; + if (w.addContentDiv) + { + w._hideAddContent(); + } + else + { + w._showAddContent(event.target.getAttribute("webappRelativePath")); + } + }); + + var addContentImage = d.createElement("img"); + addContentImage.style.borderWidth = "0px"; + addContentImage.style.margin = "0px 2px 0px 2px"; + addContentImage.align = "absmiddle"; + addContentImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/add.gif"); + addContentLink.appendChild(addContentImage); + + addContentLink.appendChild(d.createTextNode(alfresco.xforms.constants.resources["add_content"])); + + var navigateToParentLink = d.createElement("a"); + headerRightDiv.appendChild(navigateToParentLink); + navigateToParentLink.setAttribute("webappRelativePath", currentPath); + navigateToParentLink.filePickerWidget = this; + navigateToParentLink.setAttribute("href", "javascript:void(0)"); + if (currentPathName != "/") + { + dojo.event.connect(navigateToParentLink, + "onclick", + function(event) + { + var w = event.target.filePickerWidget; + var parentPath = event.target.getAttribute("webappRelativePath"); + parentPath = (parentPath.lastIndexOf("/") == 0 + ? "/" + : parentPath.substring(0, parentPath.lastIndexOf("/"))); + w._navigateToNode(parentPath); + }); + } + + var navigateToParentNodeImage = d.createElement("img"); + navigateToParentNodeImage.style.borderWidth = "0px"; + dojo.html.setOpacity(navigateToParentNodeImage, (currentPathName == "/" ? .3 : 1)); + navigateToParentNodeImage.style.margin = "0px 2px 0px 2px"; + navigateToParentNodeImage.align = "absmiddle"; + navigateToParentNodeImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/up.gif"); + navigateToParentLink.appendChild(navigateToParentNodeImage); + navigateToParentLink.appendChild(d.createTextNode(alfresco.xforms.constants.resources["go_up"])); + + headerRightDiv.style.position = "absolute"; + headerRightDiv.style.height = headerDiv.style.height; + headerRightDiv.style.lineHeight = headerRightDiv.style.height; + headerRightDiv.style.top = "0px"; + headerRightDiv.style.right = "0px"; + headerRightDiv.style.paddingRight = "2px"; + headerDiv.appendChild(headerRightDiv); + + this.contentDiv = d.createElement("div"); + dojo.html.setClass(this.contentDiv, "xformsFilePickerFileList"); + this.node.appendChild(this.contentDiv); + + var footerDiv = d.createElement("div"); + dojo.html.setClass(footerDiv, "xformsFilePickerFooter"); + this.node.appendChild(footerDiv); + + var cancelButton = d.createElement("input"); + cancelButton.type = "button"; + cancelButton.filePickerWidget = this; + + cancelButton.value = alfresco.xforms.constants.resources["cancel"]; + footerDiv.appendChild(cancelButton); + + cancelButton.style.margin = ((.5 * footerDiv.offsetHeight) - + (.5 * cancelButton.offsetHeight)) + "px 0px"; + dojo.event.connect(cancelButton, "onclick", function(event) + { + var w = event.target.filePickerWidget; + w._showSelectedValue(); + }); + this.contentDiv.style.height = (this.node.offsetHeight - + (this.statusDiv ? this.statusDiv.offsetHeight : 0) - + footerDiv.offsetHeight - + headerDiv.offsetHeight - 10) + "px"; + + var childNodes = data.getElementsByTagName("child-node"); + for (var i = 0; i < childNodes.length; i++) + { + if (childNodes[i].nodeType != dojo.dom.ELEMENT_NODE) + { + continue; + } + var webappRelativePath = childNodes[i].getAttribute("webappRelativePath"); + var fileName = webappRelativePath.replace(/.*\/([^/]+)/, "$1"); + var row = this._createRow(fileName, + webappRelativePath, + childNodes[i].getAttribute("type") == "directory", + childNodes[i].getAttribute("image"), + "xformsRow" + (i % 2 ? "Even" : "Odd")); + this.contentDiv.appendChild(row); + } +}, + +_createRow: function(fileName, webappRelativePath, isDirectory, fileTypeImage, rowClass) +{ + var d = this.contentDiv.ownerDocument; + var result = d.createElement("div"); + result.setAttribute("id", fileName + "-row"); + + dojo.html.setClass(result, "xformsFilePickerRow " + rowClass); + dojo.event.browser.addListener(result, + "mouseover", + function(event) + { + var prevHover = event.currentTarget.parentNode.hoverNode; + if (prevHover) + { + dojo.html.removeClass(prevHover, "xformsRowHover"); + } + event.currentTarget.parentNode.hoverNode = event.currentTarget; + dojo.html.addClass(event.currentTarget, "xformsRowHover"); + }, + true); + dojo.event.browser.addListener(result, + "mouseout", + function(event) + { + if (event.relatedTarget && + event.relatedTarget.parentNode == event.currentTarget) + { + return true; + } + dojo.html.removeClass(event.currentTarget, "xformsRowHover"); + }, + true); + var e = d.createElement("img"); + e.align = "absmiddle"; + e.style.margin = "0px 4px 0px 4px"; + e.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + fileTypeImage); + result.appendChild(e); + + if (isDirectory) + { + e = d.createElement("a"); + e.filePickerWidget = this; + e.setAttribute("href", "javascript:void(0)"); + e.setAttribute("webappRelativePath", webappRelativePath); + dojo.event.connect(e, "onclick", function(event) + { + var w = event.target.filePickerWidget; + w._navigateToNode(event.target.getAttribute("webappRelativePath")); + return true; + }); + e.appendChild(d.createTextNode(fileName)); + result.appendChild(e); + } + else + { + result.appendChild(d.createTextNode(fileName)); + } + + e = d.createElement("input"); + e.filePickerWidget = this; + e.type = "button"; + e.name = webappRelativePath; + e.value = "Select"; + result.appendChild(e); + + e.style.position = "absolute"; + e.style.right = "10px"; + e.style.top = (.5 * result.offsetHeight) - (.5 * e.offsetHeight) + "px"; + dojo.event.connect(e, "onclick", function(event) + { + var w = event.target.filePickerWidget; + w.setValue(event.target.name); + w._showSelectedValue(); + }); + return result; +}, + +_hideAddContent: function() +{ + if (this.addContentDiv) + { + dojo.dom.removeChildren(this.addContentDiv); + dojo.dom.removeNode(this.addContentDiv); + this.addContentDiv = null; + } +}, + +_showAddContent: function(currentPath) +{ + if (this.addContentDiv) + { + return; + } + var d = this.node.ownerDocument; + this.addContentDiv = d.createElement("div"); + dojo.html.setClass(this.addContentDiv, "xformsFilePickerAddContent"); + + if (this.contentDiv.firstChild) + { + this.contentDiv.insertBefore(this.addContentDiv, this.contentDiv.firstChild); + } + else + { + this.contentDiv.appendChild(this.addContentDiv); + } + var e = d.createElement("div"); + e.style.marginLeft = "4px"; + this.addContentDiv.appendChild(e); + e.appendChild(d.createTextNode("Upload: ")); + + var fileInputDiv = d.createElement("div"); + this.addContentDiv.appendChild(fileInputDiv); + var fileInput = d.createElement("input"); + fileInput.type = "file"; + fileInput.widget = this; + fileInput.name = this.uploadId + "_file_input"; + fileInput.size = "35"; + fileInput.setAttribute("webappRelativePath", currentPath); + fileInputDiv.appendChild(fileInput); + fileInputDiv.style.position = "absolute"; + fileInputDiv.style.right = "10px"; + fileInputDiv.style.top = (.5 * this.addContentDiv.offsetHeight) - (.5 * fileInputDiv.offsetHeight) + "px"; + + dojo.event.connect(fileInput, + "onchange", + function(event) + { + var w = event.target.widget; + if (w.addContentDiv) + { + var d = w.addContentDiv.ownerDocument; + dojo.dom.removeChildren(w.addContentDiv); + + var fileName = event.target.value.replace(/.*[\/\\]([^\/\\]+)/, "$1"); + w.addContentDiv.appendChild(d.createTextNode(alfresco.xforms.constants.resources["upload"] + ": " + fileName)); + var img = d.createElement("img"); + img.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + + "/images/icons/process_animation.gif"); + img.style.position = "absolute"; + img.style.right = "10px"; + img.style.height = (.5 * w.addContentDiv.offsetHeight) + "px"; + img.style.top = (.25 * w.addContentDiv.offsetHeight) + "px"; + w.addContentDiv.appendChild(img); + } + + alfresco.FilePickerWidget._handleUpload(w.uploadId, + event.target, + event.target.getAttribute("webappRelativePath"), + w); + }); +}, + +_upload_completeHandler: function(fileName, webappRelativePath, fileTypeImage, error) +{ + if (error) + { + this._showStatus(error, true); + this._hideAddContent(); + this._showAddContent(webappRelativePath); + } + else + { + var nextRow = dojo.dom.nextElement(this.addContentDiv); + var rowClass = (nextRow + ? ("xformsRow" + (dojo.html.hasClass(nextRow, "xformsRowEven") + ? "Odd" + : "Even")) + : "xformsRowEvent"); + var row = this._createRow(fileName, + webappRelativePath == "/" ? "/" + fileName : webappRelativePath + "/" + fileName, + false, + fileTypeImage, + rowClass); + this.contentDiv.replaceChild(row, this.addContentDiv); + this.addContentDiv = null; + } +}, + +_closeParentPathMenu: function() +{ + if (this.parentPathMenu) + { + dojo.dom.removeChildren(this.parentPathMenu); + dojo.dom.removeNode(this.parentPathMenu); + this.parentPathMenu = null; + } + this.headerMenuTriggerLink.style.borderStyle = "solid"; +}, + +_openParentPathMenu: function(target, path) +{ + var d = target.ownerDocument; + this.parentPathMenu = d.createElement("div"); + this.parentPathMenu.filePickerWidget = this; + d.currentParentPathMenu = this.parentPathMenu; + + // handler for closing the menu if the mouse is clicked + // outside of the menu + var parentPathMenu_documentClickHandler = function(event) + { + var t = event.target; + var d = event.target.ownerDocument; + + // always remove - this handler only ever needs to handle a single click + d.removeEventListener("click", parentPathMenu_documentClickHandler, true); + while (t && t != d) + { + if (t == d.currentParentPathMenu || + t == d.currentParentPathMenu.filePickerWidget.headerMenuTriggerLink) + { + // the click is coming from within the component - ignore it + return true; + } + t = t.parentNode; + } + d.currentParentPathMenu.filePickerWidget._closeParentPathMenu(); + }; + d.addEventListener("click", parentPathMenu_documentClickHandler, true); + + dojo.html.setClass(this.parentPathMenu, "xformsFilePickerParentPathMenu"); + + var left = 0; + var top = 0; + var n = target; + do + { + left += n.offsetLeft;// + parseInt(n.style.marginLeft) + parseInt(n.style.borderLeft); + top += n.offsetTop;// + parseInt(n.style.marginTop) + parseInt(n.style.borderTop); + n = n.parentNode; + } + while (n != this.node); + this.parentPathMenu.style.top = top + target.offsetHeight + "px"; + this.parentPathMenu.style.left = left + "px"; + var parentNodes = null; + if (path == "/") + { + parentNodes = [ "/" ]; + } + else + { + parentNodes = path.split("/"); + parentNodes[0] = "/"; + } + + var pathTextDiv = d.createElement("div"); + pathTextDiv.style.fontWeight = "bold"; + pathTextDiv.style.paddingLeft = "5px"; + + pathTextDiv.appendChild(d.createTextNode(alfresco.xforms.constants.resources["path"])); + this.parentPathMenu.appendChild(pathTextDiv); + var currentPathNodes = []; + for (var i = 0; i < parentNodes.length; i++) + { + if (i != 0) + { + currentPathNodes.push(parentNodes[i]); + } + var path = i == 0 ? "/" : "/" + currentPathNodes.join("/"); + var parentNodeDiv = d.createElement("div"); + parentNodeDiv.setAttribute("webappRelativePath", path); + this.parentPathMenu.appendChild(parentNodeDiv); + parentNodeDiv.style.display = "block"; + parentNodeDiv.style.paddingLeft = (i * 16) + parseInt(pathTextDiv.style.paddingLeft) + "px"; + parentNodeDiv.style.paddingRight = parseInt(pathTextDiv.style.paddingLeft) + "px"; + parentNodeDiv.style.whiteSpace = "nowrap"; + + var parentNodeImage = d.createElement("img"); + parentNodeImage.align = "absmiddle"; + parentNodeImage.style.marginRight = "4px"; + parentNodeDiv.appendChild(parentNodeImage); + parentNodeImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + + "/images/icons/space_small.gif"); + parentNodeDiv.appendChild(parentNodeImage); + parentNodeDiv.appendChild(d.createTextNode(path)); + dojo.event.connect(parentNodeDiv, + "onclick", + function(event) + { + var w = event.currentTarget; + var path = w.getAttribute("webappRelativePath"); + w = w.parentNode; + w.filePickerWidget._closeParentPathMenu(); + w.filePickerWidget._navigateToNode(path); + }); + } + this.node.appendChild(this.parentPathMenu); +} +}; diff --git a/source/web/scripts/ajax/xforms.js b/source/web/scripts/ajax/xforms.js index 81790815d8..20c9580d31 100644 --- a/source/web/scripts/ajax/xforms.js +++ b/source/web/scripts/ajax/xforms.js @@ -31,6 +31,7 @@ //////////////////////////////////////////////////////////////////////////////// djConfig.bindEncoding = "UTF-8"; +djConfig.parseWidgets = false; dojo.require("dojo.date.common"); dojo.require("dojo.debug.console"); dojo.require("dojo.lang.assert"); @@ -44,22 +45,6 @@ function _xforms_init() dojo.addOnLoad(_xforms_init); -tinyMCE.init({ - theme: "advanced", - mode: "exact", - width: -1, - auto_resize: false, - force_p_newlines: false, - encoding: "UTF-8", - add_unload_trigger: false, - add_form_submit_trigger: false, - theme_advanced_toolbar_location: "top", - theme_advanced_toolbar_align: "left", - theme_advanced_buttons1: "bold,italic,underline,strikethrough,separator,fontselect,fontsizeselect", - theme_advanced_buttons2: "link,unlink,image,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,undo,redo,separator,forecolor,backcolor", - theme_advanced_buttons3: "" -}); - //////////////////////////////////////////////////////////////////////////////// // constants // @@ -67,16 +52,15 @@ tinyMCE.init({ // and the webapp context path are expected to be provided by the jsp including // this script. //////////////////////////////////////////////////////////////////////////////// -alfresco_xforms_constants.XFORMS_ERROR_DIV_ID = "alfresco-xforms-error"; -alfresco_xforms_constants.AJAX_LOADER_DIV_ID = "alfresco-ajax-loader"; +alfresco.xforms.constants.XFORMS_ERROR_DIV_ID = "alfresco-xforms-error"; -alfresco_xforms_constants.EXPANDED_IMAGE = new Image(); -alfresco_xforms_constants.EXPANDED_IMAGE.src = - alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/expanded.gif"; +alfresco.xforms.constants.EXPANDED_IMAGE = new Image(); +alfresco.xforms.constants.EXPANDED_IMAGE.src = + alfresco.constants.WEBAPP_CONTEXT + "/images/icons/expanded.gif"; -alfresco_xforms_constants.COLLAPSED_IMAGE = new Image(); -alfresco_xforms_constants.COLLAPSED_IMAGE.src = - alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/collapsed.gif"; +alfresco.xforms.constants.COLLAPSED_IMAGE = new Image(); +alfresco.xforms.constants.COLLAPSED_IMAGE.src = + alfresco.constants.WEBAPP_CONTEXT + "/images/icons/collapsed.gif"; //////////////////////////////////////////////////////////////////////////////// // widgets @@ -418,8 +402,8 @@ dojo.declare("alfresco.xforms.Widget", _getChildXFormsNode: function(nodeName) { var x = _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, nodeName); for (var i = 0; i < x.length; i++) { @@ -472,7 +456,7 @@ dojo.declare("alfresco.xforms.Widget", getAppearance: function() { var result = (this.xformsNode.getAttribute("appearance") || - this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":appearance")); + this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":appearance")); return result == null || result.length == 0 ? null : result; }, @@ -549,12 +533,12 @@ dojo.declare("alfresco.xforms.FilePicker", dojo.html.prependClass(this.domNode, "xformsFilePicker"); attach_point.appendChild(this.domNode); //XXXarielb support readonly and disabled - this.widget = new FilePickerWidget(this.id, - this.domNode, - this.getInitialValue(), - false, - this._filePicker_changeHandler, - this._filePicker_resizeHandler); + this.widget = new alfresco.FilePickerWidget(this.id, + this.domNode, + this.getInitialValue(), + false, + this._filePicker_changeHandler, + this._filePicker_resizeHandler); this.widget.render(); }, @@ -600,6 +584,10 @@ dojo.declare("alfresco.xforms.TextField", alfresco.xforms.Widget, function(xform, xformsNode) { + this._maxLength = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxLength") + ? Number(this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxLength")) + : -1); + }, { @@ -616,11 +604,18 @@ dojo.declare("alfresco.xforms.TextField", this.widget.setAttribute("type", "text"); this.widget.setAttribute("id", this.id + "-widget"); this.widget.setAttribute("value", initial_value); - if (this.getAppearance() == "full") + if (this._maxLength >= 0) + { + this.widget.setAttribute("maxlength", this._maxLength); + var maxWidth = this.domNode.offsetWidth; + + this.widget.style.maxWidth = "100%"; + this.widget.setAttribute("size", this._maxLength); + } + else if (this.getAppearance() == "full") { this.widget.style.width = "100%"; } - this.domNode.appendChild(this.widget); if (this.isReadonly()) { @@ -669,9 +664,9 @@ dojo.declare("alfresco.xforms.NumericalRange", function(xform, xformsNode) { dojo.require("dojo.widget.Slider"); - this.fractionDigits = (_hasAttribute(this.xformsNode, alfresco_xforms_constants.ALFRESCO_PREFIX + ":fractionDigits") - ? Number(this.xformsNode.getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":fractionDigits")) - : -1); + this._fractionDigits = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":fractionDigits") + ? Number(this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":fractionDigits")) + : -1); }, { ///////////////////////////////////////////////////////////////// @@ -687,10 +682,10 @@ dojo.declare("alfresco.xforms.NumericalRange", sliderDiv.style.marginBottom = "5px"; this.domNode.appendChild(sliderDiv); - var minimum = Number(this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":start")); - var maximum = Number(this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":end")); + var minimum = Number(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":start")); + var maximum = Number(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":end")); var snapValues = 0; - if (this.fractionDigits == 0) + if (this._fractionDigits == 0) { snapValues = maximum - minimum + 1; } @@ -744,9 +739,9 @@ dojo.declare("alfresco.xforms.NumericalRange", _hSlider_valueChangedHandler: function(value) { - if (this.fractionDigits >= 0) + if (this._fractionDigits >= 0) { - value = Math.round(value * Math.pow(10, this.fractionDigits)) / Math.pow(10, this.fractionDigits); + value = Math.round(value * Math.pow(10, this._fractionDigits)) / Math.pow(10, this._fractionDigits); } this.currentValueDiv.replaceChild(document.createTextNode("Value: " + value), this.currentValueDiv.firstChild); @@ -776,7 +771,7 @@ dojo.declare("alfresco.xforms.PlainTextEditor", this.widget = document.createElement("textarea"); this.domNode.appendChild(this.widget); this.widget.setAttribute("id", this.id + "-widget"); - this.widget.setAttribute("value", initialValue); + this.widget.appendChild(document.createTextNode(initialValue)); if (this.isReadonly()) { this.widget.setAttribute("readonly", this.isReadonly()); @@ -858,6 +853,15 @@ dojo.declare("alfresco.xforms.RichTextEditor", this.domNode.appendChild(this.widget); dojo.html.prependClass(this.widget, "xformsTextArea"); this.widget.innerHTML = this.getInitialValue() || ""; + var images = this.widget.getElementsByTagName("img"); + for (var i = 0; i < images.length; i++) + { + if (images[i].getAttribute("src") && + images[i].getAttribute("src").match("^/")) + { + images[i].setAttribute("src", alfresco.constants.AVM_WEBAPP_URL + images[i].getAttribute("src")); + } + } if (!this.isReadonly()) { this._createTinyMCE(); @@ -887,7 +891,9 @@ dojo.declare("alfresco.xforms.RichTextEditor", getValue: function() { - return this.isReadonly() ? this.widget.innerHTML : tinyMCE.getContent(this.id); + var result = this.isReadonly() ? this.widget.innerHTML : tinyMCE.getContent(this.id); + result = result.replace(new RegExp(alfresco.constants.AVM_WEBAPP_URL, "g"), ""); + return result; }, setReadonly: function(readonly) @@ -975,19 +981,19 @@ dojo.declare("alfresco.xforms.AbstractSelectWidget", { var binding = this.xform.getBinding(this.xformsNode); var values = _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "item"); var result = []; for (var i = 0; i < values.length; i++) { var label = _getElementsByTagNameNS(values[i], - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "label")[0]; var value = _getElementsByTagNameNS(values[i], - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "value")[0]; var valid = true; if (binding.constraint) @@ -995,9 +1001,12 @@ dojo.declare("alfresco.xforms.AbstractSelectWidget", if (!dojo.render.html.ie) { valid = _evaluateXPath(binding.constraint, value, XPathResult.BOOLEAN_TYPE); - dojo.debug("evaludated constraint " + binding.constraint + - " on " + dojo.dom.textContent(value) + - " to " + valid); + if (djConfig.isDebug) + { + dojo.debug("evaludated constraint " + binding.constraint + + " on " + dojo.dom.textContent(value) + + " to " + valid); + } } else { @@ -1012,9 +1021,12 @@ dojo.declare("alfresco.xforms.AbstractSelectWidget", valid: valid }); - dojo.debug("values["+ i + "] = {id: " + result[i].id + - ",label: " + result[i].label + ",value: " + result[i].value + - ",valid: " + result[i].valid + "}"); + if (djConfig.isDebug) + { + dojo.debug("values["+ i + "] = {id: " + result[i].id + + ",label: " + result[i].label + ",value: " + result[i].value + + ",valid: " + result[i].valid + "}"); + } } return result; } @@ -1207,6 +1219,10 @@ dojo.declare("alfresco.xforms.Select1", this._selectedValue = initial_value; radio.checked = true; } + if (this.isReadonly()) + { + radio.setAttribute("disabled", true); + } dojo.event.connect(radio, "onclick", this, this._radio_clickHandler); } this.widget.style.height = this.widget.offsetHeight + "px"; @@ -1232,6 +1248,11 @@ dojo.declare("alfresco.xforms.Select1", this._selectedValue = initial_value; option.selected = true; } + + if (this.isReadonly()) + { + this.widget.setAttribute("disabled", true); + } } dojo.event.connect(this.widget, "onchange", this, this._combobox_changeHandler); } @@ -1329,6 +1350,10 @@ dojo.declare("alfresco.xforms.Checkbox", { this.widget.setAttribute("checked", true); } + if (this.isReadonly()) + { + this.widget.setAttribute("disabled", true); + } dojo.event.connect(this.widget, "onclick", this, this._checkbox_clickHandler); }, @@ -1370,9 +1395,9 @@ dojo.declare("alfresco.xforms.DatePicker", function(xform, xformsNode) { dojo.require("dojo.widget.DatePicker"); - this._noValueSet = (alfresco_xforms_constants.resources["eg"] + " " + + this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " + dojo.date.format(new Date(), - {datePattern: alfresco_xforms_constants.DATE_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_FORMAT, selector: 'dateOnly'})); }, { @@ -1428,7 +1453,7 @@ dojo.declare("alfresco.xforms.DatePicker", var jsDate = dojo.date.fromRfc3339(initial_value); this.widget.setAttribute("value", dojo.date.format(jsDate, - {datePattern: alfresco_xforms_constants.DATE_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_FORMAT, selector: 'dateOnly'})); } else @@ -1436,18 +1461,25 @@ dojo.declare("alfresco.xforms.DatePicker", this.widget.setAttribute("value", this._noValueSet); dojo.html.addClass(this.widget, "xformsGhostText"); } + if (this.isReadonly()) + { + this.widget.setAttribute("disabled", true); + } this.domNode.appendChild(this.widget); var expandoImage = document.createElement("img"); - expandoImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); + expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); expandoImage.align = "absmiddle"; expandoImage.style.margin = "0px 5px"; this.domNode.appendChild(expandoImage); - dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler); - dojo.event.connect(this.widget, "onfocus", this, this._dateTextBox_focusHandler); - dojo.event.connect(this.widget, "onchange", this, this._dateTextBox_changeHandler); + if (!this.isReadonly()) + { + dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler); + dojo.event.connect(this.widget, "onfocus", this, this._dateTextBox_focusHandler); + dojo.event.connect(this.widget, "onchange", this, this._dateTextBox_changeHandler); + } }, setValue: function(value, forceCommit) @@ -1461,7 +1493,7 @@ dojo.declare("alfresco.xforms.DatePicker", alfresco.xforms.DatePicker.superclass.setValue.call(this, value, forceCommit); var jsDate = dojo.date.fromRfc3339(value); this.widget.value = dojo.date.format(jsDate, - {datePattern: alfresco_xforms_constants.DATE_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_FORMAT, selector: 'dateOnly'}); dojo.html.removeClass(this.widget, "xformsGhostText"); } @@ -1478,7 +1510,7 @@ dojo.declare("alfresco.xforms.DatePicker", else { var jsDate = dojo.date.parse(this.widget.value, - {datePattern: alfresco_xforms_constants.DATE_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_FORMAT, selector: 'dateOnly'}); return dojo.date.toRfc3339(jsDate, "dateOnly"); } @@ -1525,11 +1557,11 @@ dojo.declare("alfresco.xforms.TimePicker", function(xform, xformsNode) { dojo.require("dojo.widget.TimePicker"); - this._noValueSet = (alfresco_xforms_constants.resources["eg"] + " " + + this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " + dojo.date.format(new Date(), - {timePattern: alfresco_xforms_constants.TIME_FORMAT, + {timePattern: alfresco.xforms.constants.TIME_FORMAT, selector: "timeOnly"})); - this._xformsFormat = "HH:mm:ss"; + this._xformsFormat = "HH:mm:ss.S"; }, { /** */ @@ -1592,7 +1624,7 @@ dojo.declare("alfresco.xforms.TimePicker", var jsDate = dojo.date.parse(initial_value, {timePattern: this._xformsFormat, selector: "timeOnly"}); this.widget.setAttribute("value", dojo.date.format(jsDate, - {timePattern: alfresco_xforms_constants.TIME_FORMAT, + {timePattern: alfresco.xforms.constants.TIME_FORMAT, selector: "timeOnly"})); } else @@ -1600,18 +1632,25 @@ dojo.declare("alfresco.xforms.TimePicker", this.widget.setAttribute("value", this._noValueSet); dojo.html.addClass(this.widget, "xformsGhostText"); } + if (this.isReadonly()) + { + this.widget.setAttribute("disabled", true); + } this.domNode.appendChild(this.widget); var expandoImage = document.createElement("img"); - expandoImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); + expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); expandoImage.align = "absmiddle"; expandoImage.style.margin = "0px 5px"; this.domNode.appendChild(expandoImage); - dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler); - dojo.event.connect(this.widget, "onfocus", this, this._timeTextBox_focusHandler); - dojo.event.connect(this.widget, "onchange", this, this._timeTextBox_changeHandler); + if (!this.isReadonly()) + { + dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler); + dojo.event.connect(this.widget, "onfocus", this, this._timeTextBox_focusHandler); + dojo.event.connect(this.widget, "onchange", this, this._timeTextBox_changeHandler); + } }, setValue: function(value, forceCommit) @@ -1625,7 +1664,7 @@ dojo.declare("alfresco.xforms.TimePicker", alfresco.xforms.TimePicker.superclass.setValue.call(this, value, forceCommit); var jsDate = dojo.date.parse(value, {timePattern: this._xformsFormat, selector: "timeOnly"}); this.widget.value = dojo.date.format(jsDate, - {timePattern: alfresco_xforms_constants.TIME_FORMAT, + {timePattern: alfresco.xforms.constants.TIME_FORMAT, selector: "timeOnly"}); dojo.html.removeClass(this.widget, "xformsGhostText"); } @@ -1642,7 +1681,7 @@ dojo.declare("alfresco.xforms.TimePicker", else { var jsDate = dojo.date.parse(this.widget.value, - {timePattern: alfresco_xforms_constants.TIME_FORMAT, + {timePattern: alfresco.xforms.constants.TIME_FORMAT, selector: "timeOnly"}); return dojo.date.format(jsDate, {timePattern: this._xformsFormat, selector: "timeOnly"}); } @@ -1690,9 +1729,9 @@ dojo.declare("alfresco.xforms.DateTimePicker", dojo.require("dojo.widget.DatePicker"); dojo.require("dojo.widget.TimePicker"); - this._noValueSet = (alfresco_xforms_constants.resources["eg"] + " " + + this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " + dojo.date.format(new Date(), - {datePattern: alfresco_xforms_constants.DATE_TIME_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT, selector: "dateOnly"})); }, { @@ -1781,7 +1820,7 @@ dojo.declare("alfresco.xforms.DateTimePicker", var jsDate = dojo.date.fromRfc3339(initial_value); this.widget.setAttribute("value", dojo.date.format(jsDate, - {timePattern: alfresco_xforms_constants.DATE_TIME_FORMAT, + {timePattern: alfresco.xforms.constants.DATE_TIME_FORMAT, selector: "timeOnly"})); } else @@ -1793,7 +1832,7 @@ dojo.declare("alfresco.xforms.DateTimePicker", this.widget.style.width = (3 * this.widget.offsetWidth) + "px"; var expandoImage = document.createElement("img"); - expandoImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); + expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif"); expandoImage.align = "absmiddle"; expandoImage.style.margin = "0px 5px"; @@ -1815,7 +1854,7 @@ dojo.declare("alfresco.xforms.DateTimePicker", alfresco.xforms.DateTimePicker.superclass.setValue.call(this, value, forceCommit); var jsDate = dojo.date.fromRfc3339(value); this.widget.value = dojo.date.format(jsDate, - {datePattern: alfresco_xforms_constants.DATE_TIME_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT, selector: "dateOnly"}); dojo.html.removeClass(this.widget, "xformsGhostText"); } @@ -1832,7 +1871,7 @@ dojo.declare("alfresco.xforms.DateTimePicker", else { var jsDate = dojo.date.parse(this.widget.value, - {datePattern: alfresco_xforms_constants.DATE_TIME_FORMAT, + {datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT, selector: "dateOnly"}); return dojo.date.toRfc3339(jsDate); } @@ -2099,9 +2138,12 @@ dojo.declare("alfresco.xforms.Group", { for (var i = 0; i < this._children.length; i++) { - dojo.debug(this.id + "[" + i + "]: " + - " is " + this._children[i].id + - " the same as " + child.id + "?"); + if (djConfig.isDebug) + { + dojo.debug(this.id + "[" + i + "]: " + + " is " + this._children[i].id + + " the same as " + child.id + "?"); + } if (this._children[i] == child) { return i; @@ -2199,7 +2241,7 @@ dojo.declare("alfresco.xforms.Group", var requiredImage = document.createElement("img"); requiredImage.setAttribute("src", - alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/required_field.gif"); + alfresco.constants.WEBAPP_CONTEXT + "/images/icons/required_field.gif"); requiredImage.style.verticalAlign = "middle"; requiredImage.style.marginLeft = "5px"; requiredImage.style.marginRight = "5px"; @@ -2377,7 +2419,7 @@ dojo.declare("alfresco.xforms.Group", this.toggleExpandedImage = document.createElement("img"); this._groupHeaderNode.appendChild(this.toggleExpandedImage); - this.toggleExpandedImage.setAttribute("src", alfresco_xforms_constants.EXPANDED_IMAGE.src); + this.toggleExpandedImage.setAttribute("src", alfresco.xforms.constants.EXPANDED_IMAGE.src); this.toggleExpandedImage.align = "absmiddle"; this.toggleExpandedImage.style.marginLeft = "5px"; this.toggleExpandedImage.style.marginRight = "5px"; @@ -2403,7 +2445,7 @@ dojo.declare("alfresco.xforms.Group", isExpanded: function() { return (this.toggleExpandedImage.getAttribute("src") == - alfresco_xforms_constants.EXPANDED_IMAGE.src); + alfresco.xforms.constants.EXPANDED_IMAGE.src); }, /** @@ -2416,8 +2458,8 @@ dojo.declare("alfresco.xforms.Group", { this.toggleExpandedImage.src = (expanded - ? alfresco_xforms_constants.EXPANDED_IMAGE.src - : alfresco_xforms_constants.COLLAPSED_IMAGE.src); + ? alfresco.xforms.constants.EXPANDED_IMAGE.src + : alfresco.xforms.constants.COLLAPSED_IMAGE.src); this.domNode.childContainerNode.style.display = expanded ? "block" : "none"; } }, @@ -2615,27 +2657,26 @@ dojo.declare("alfresco.xforms.SwitchGroup", render: function(attach_point) { alfresco.xforms.SwitchGroup.superclass.render.call(this, attach_point); - this._groupHeaderNode = document.createElement("div"); - this._groupHeaderNode.setAttribute("id", this.id + "-groupHeaderNode"); - this.domNode.appendChild(this._groupHeaderNode); - this._groupHeaderNode.style.backgroundColor = "orange"; var cases = this._getCaseToggleTriggers(); + var caseToggleSelect = document.createElement("select"); + caseToggleSelect.setAttribute("id", this.id + "-toggle-select"); + caseToggleSelect.style.position = "absolute"; + caseToggleSelect.style.right = "0px"; + caseToggleSelect.style.top = "0px"; + this._groupHeaderNode.appendChild(caseToggleSelect); for (var i = 0; i < cases.length; i++) { - var d = document.createElement("div"); - this._groupHeaderNode.appendChild(d); - var link = document.createElement("a"); - link.setAttribute("id", cases[i].id); - link.trigger = cases[i]; - link.appendChild(document.createTextNode(cases[i].getLabel())); - d.appendChild(link); - dojo.event.browser.addListener(link, - "onclick", - function(event) - { - event.target.trigger.fire(); - }); + var option = document.createElement("option"); + caseToggleSelect.appendChild(option); + var caseId = cases[i].getActions()["toggle"].properties["case"]; + option.setAttribute("value", caseId); + option.appendChild(document.createTextNode(cases[i].getLabel())); + if (cases[i].getActions()["toggle"].properties["case"] == this._selectedCaseId) + { + option.selected = true; + } } + dojo.event.connect(caseToggleSelect, "onchange", this, this._caseToggleSelect_changeHandler); }, ///////////////////////////////////////////////////////////////// @@ -2659,7 +2700,18 @@ dojo.declare("alfresco.xforms.SwitchGroup", this._children[i].domContainer.style.display = "none"; } } - this._updateDisplay(false); + this._updateDisplay(true); + }, + + ///////////////////////////////////////////////////////////////// + // DOM event handlers + ///////////////////////////////////////////////////////////////// + + _caseToggleSelect_changeHandler: function(event) + { + dojo.event.browser.stopEvent(event); + var t = this._getCaseToggleTriggerByCaseId(event.target.value); + t.fire(); } }); @@ -2702,7 +2754,7 @@ dojo.declare("alfresco.xforms.ViewRoot", var icon = document.createElement("img"); this._groupHeaderNode.appendChild(icon); - icon.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/file_large.gif"); + icon.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/file_large.gif"); icon.align = "absmiddle"; icon.style.marginLeft = "5px"; icon.style.marginRight = "5px"; @@ -2721,7 +2773,7 @@ dojo.declare("alfresco.xforms.ViewRoot", getLabel: function() { var result = alfresco.xforms.ViewRoot.superclass.getLabel.call(this); - result += " " + alfresco_xforms_constants.FORM_INSTANCE_DATA_NAME; + result += " " + alfresco.xforms.constants.FORM_INSTANCE_DATA_NAME; return result; } }); @@ -2940,7 +2992,7 @@ dojo.declare("alfresco.xforms.Repeat", { var img = document.createElement("img"); this.repeatControls[position][images[i].name] = img; - img.setAttribute("src", (alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/" + + img.setAttribute("src", (alfresco.constants.WEBAPP_CONTEXT + "/images/icons/" + images[i].src + ".gif")); img.style.width = "16px"; img.style.height = "16px"; @@ -3042,7 +3094,7 @@ dojo.declare("alfresco.xforms.Repeat", this.headerInsertRepeatItemImage.repeat = this; this._groupHeaderNode.appendChild(this.headerInsertRepeatItemImage); this.headerInsertRepeatItemImage.setAttribute("src", - alfresco_xforms_constants.WEBAPP_CONTEXT + + alfresco.constants.WEBAPP_CONTEXT + "/images/icons/plus.gif"); this.headerInsertRepeatItemImage.style.width = "16px"; this.headerInsertRepeatItemImage.style.height = "16px"; @@ -3226,11 +3278,15 @@ dojo.declare("alfresco.xforms.Repeat", { dojo.debug(this.id + ".handlePrototypeCloned("+ prototypeId +")"); var chibaData = _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.CHIBA_NS, - alfresco_xforms_constants.CHIBA_PREFIX, + alfresco.xforms.constants.CHIBA_NS, + alfresco.xforms.constants.CHIBA_PREFIX, "data"); chibaData = chibaData[chibaData.length - 1]; - dojo.debug(alfresco_xforms_constants.CHIBA_PREFIX + ":data == " + dojo.dom.innerXML(chibaData)); + if (djConfig.isDebug) + { + dojo.debug(alfresco.xforms.constants.CHIBA_PREFIX + + ":data == " + dojo.dom.innerXML(chibaData)); + } var prototypeToClone = dojo.dom.firstElement(chibaData); if (prototypeToClone.getAttribute("id") != prototypeId) { @@ -3283,8 +3339,8 @@ dojo.declare("alfresco.xforms.Trigger", if (typeof this._actions == "undefined") { var actionNode = _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "action")[0]; this._actions = {}; for (var i = 0; i < actionNode.childNodes.length; i++) @@ -3423,9 +3479,9 @@ dojo.declare("alfresco.xforms.XFormsAction", for (var i = 0; i < this.xformsNode.attributes.length; i++) { var attr = this.xformsNode.attributes[i]; - if (attr.nodeName.match(new RegExp("^" + alfresco_xforms_constants.XFORMS_PREFIX + ":"))) + if (attr.nodeName.match(new RegExp("^" + alfresco.xforms.constants.XFORMS_PREFIX + ":"))) { - this.properties[attr.nodeName.substring((alfresco_xforms_constants.XFORMS_PREFIX + ":").length)] = + this.properties[attr.nodeName.substring((alfresco.xforms.constants.XFORMS_PREFIX + ":").length)] = attr.nodeValue; } } @@ -3438,7 +3494,7 @@ dojo.declare("alfresco.xforms.XFormsAction", /** Returns the action type. */ getType: function() { - return this.xformsNode.nodeName.substring((alfresco_xforms_constants.XFORMS_PREFIX + ":").length); + return this.xformsNode.nodeName.substring((alfresco.xforms.constants.XFORMS_PREFIX + ":").length); } }); @@ -3489,26 +3545,26 @@ dojo.declare("alfresco.xforms.Binding", { this.xformsNode = xformsNode; this.id = this.xformsNode.getAttribute("id"); - this.nodeset = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":nodeset"); + this.nodeset = this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":nodeset"); this._readonly = - (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":readonly") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":readonly") == "true()" + (_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":readonly") + ? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":readonly") == "true()" : null); this._required = - (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":required") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":required") == "true()" + (_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":required") + ? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":required") == "true()" : null); this._type = - (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":type") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":type") + (_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":type") + ? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":type") : null); this.constraint = - (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") + (_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":constraint") + ? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":constraint") : null); - this.maximum = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":maxOccurs"); + this.maximum = this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":maxOccurs"); this.maximum = this.maximum == "unbounded" ? Number.MAX_VALUE : parseInt(this.maximum); - this.minimum = parseInt(this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":minOccurs")); + this.minimum = parseInt(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":minOccurs")); this.parent = parent; this.widgets = {}; }, @@ -3553,14 +3609,14 @@ dojo.declare("alfresco.xforms.XForm", /** Makes a request to the XFormsBean to load the xforms document. */ function() { - var req = AjaxHelper.createRequest(this, - "getXForm", - {}, - function(type, data, evt) - { - this.target._loadHandler(data); - }); - AjaxHelper.sendRequest(req); + var req = alfresco.AjaxHelper.createRequest(this, + "getXForm", + {}, + function(type, data, evt, kwArgs) + { + this.target._loadHandler(data); + }); + alfresco.AjaxHelper.sendRequest(req); }, { ///////////////////////////////////////////////////////////////// @@ -3575,21 +3631,16 @@ dojo.declare("alfresco.xforms.XForm", this._bindings = this._loadBindings(this.getModel()); var bindings = this.getBindings(); - for (var i = 0; false && i < bindings.length; i++) - { - dojo.debug("bindings[" + i + "]=" + bindings[i].id + - ", parent = " + (bindings[i].parent - ? bindings[i].parent.id - : 'null')); - } - var alfUI = document.getElementById(alfresco_xforms_constants.XFORMS_UI_DIV_ID); + var alfUI = document.getElementById(alfresco.xforms.constants.XFORMS_UI_DIV_ID); alfUI.style.width = "100%"; var rootGroup = _getElementsByTagNameNS(this.getBody(), - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "group")[0]; + this.rootWidget = new alfresco.xforms.ViewRoot(this, rootGroup); this.rootWidget.render(alfUI); + this.loadWidgets(rootGroup, this.rootWidget); }, @@ -3599,19 +3650,19 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("creating widget for " + xformsNode.nodeName.toLowerCase()); switch (xformsNode.nodeName.toLowerCase()) { - case alfresco_xforms_constants.XFORMS_PREFIX + ":group": + case alfresco.xforms.constants.XFORMS_PREFIX + ":group": return new alfresco.xforms.Group(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":repeat": + case alfresco.xforms.constants.XFORMS_PREFIX + ":repeat": return new alfresco.xforms.Repeat(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":textarea": + case alfresco.xforms.constants.XFORMS_PREFIX + ":textarea": return (new alfresco.xforms.Widget(this, xformsNode).getAppearance() == "minimal" ? new alfresco.xforms.PlainTextEditor(this, xformsNode) : new alfresco.xforms.RichTextEditor(this, xformsNode)); - case alfresco_xforms_constants.XFORMS_PREFIX + ":upload": + case alfresco.xforms.constants.XFORMS_PREFIX + ":upload": return new alfresco.xforms.FilePicker(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":range": + case alfresco.xforms.constants.XFORMS_PREFIX + ":range": return new alfresco.xforms.NumericalRange(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":input": + case alfresco.xforms.constants.XFORMS_PREFIX + ":input": { var type = this.getBinding(xformsNode).getType(); switch (type) @@ -3658,26 +3709,26 @@ dojo.declare("alfresco.xforms.XForm", return new alfresco.xforms.TextField(this, xformsNode); } } - case alfresco_xforms_constants.XFORMS_PREFIX + ":select": + case alfresco.xforms.constants.XFORMS_PREFIX + ":select": return new alfresco.xforms.Select(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":select1": + case alfresco.xforms.constants.XFORMS_PREFIX + ":select1": return (this.getBinding(xformsNode).getType() == "boolean" ? new alfresco.xforms.Checkbox(this, xformsNode) : new alfresco.xforms.Select1(this, xformsNode)); - case alfresco_xforms_constants.XFORMS_PREFIX + ":submit": + case alfresco.xforms.constants.XFORMS_PREFIX + ":submit": return new alfresco.xforms.Submit(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":trigger": + case alfresco.xforms.constants.XFORMS_PREFIX + ":trigger": return new alfresco.xforms.Trigger(this, xformsNode); - case alfresco_xforms_constants.CHIBA_PREFIX + ":data": - case alfresco_xforms_constants.XFORMS_PREFIX + ":label": - case alfresco_xforms_constants.XFORMS_PREFIX + ":alert": + case alfresco.xforms.constants.CHIBA_PREFIX + ":data": + case alfresco.xforms.constants.XFORMS_PREFIX + ":label": + case alfresco.xforms.constants.XFORMS_PREFIX + ":alert": { dojo.debug("ignoring " + xformsNode.nodeName); return null; } - case alfresco_xforms_constants.XFORMS_PREFIX + ":switch": + case alfresco.xforms.constants.XFORMS_PREFIX + ":switch": return new alfresco.xforms.SwitchGroup(this, xformsNode); - case alfresco_xforms_constants.XFORMS_PREFIX + ":case": + case alfresco.xforms.constants.XFORMS_PREFIX + ":case": return new alfresco.xforms.CaseGroup(this, xformsNode); default: throw new Error("unknown type " + xformsNode.nodeName); @@ -3695,7 +3746,7 @@ dojo.declare("alfresco.xforms.XForm", } dojo.debug("loading " + xformsNode.childNodes[i].nodeName + " into " + parentWidget.id); - if (xformsNode.childNodes[i].getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + + if (xformsNode.childNodes[i].getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":prototype") == "true") { dojo.debug(xformsNode.childNodes[i].getAttribute("id") + @@ -3722,7 +3773,7 @@ dojo.declare("alfresco.xforms.XForm", for (var i = 0; i < bind.childNodes.length; i++) { if (bind.childNodes[i].nodeName.toLowerCase() == - alfresco_xforms_constants.XFORMS_PREFIX + ":bind") + alfresco.xforms.constants.XFORMS_PREFIX + ":bind") { var b = new alfresco.xforms.Binding(bind.childNodes[i], parent); result[b.id] = b; @@ -3741,8 +3792,8 @@ dojo.declare("alfresco.xforms.XForm", getModel: function() { return _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "model")[0]; }, @@ -3751,8 +3802,8 @@ dojo.declare("alfresco.xforms.XForm", { var model = this.getModel(); return _getElementsByTagNameNS(model, - alfresco_xforms_constants.XFORMS_NS, - alfresco_xforms_constants.XFORMS_PREFIX, + alfresco.xforms.constants.XFORMS_NS, + alfresco.xforms.constants.XFORMS_PREFIX, "instance")[0]; }, @@ -3760,8 +3811,8 @@ dojo.declare("alfresco.xforms.XForm", getBody: function() { var b = _getElementsByTagNameNS(this.xformsNode, - alfresco_xforms_constants.XHTML_NS, - alfresco_xforms_constants.XHTML_PREFIX, + alfresco.xforms.constants.XHTML_NS, + alfresco.xforms.constants.XHTML_PREFIX, "body"); return b[b.length - 1]; }, @@ -3769,7 +3820,7 @@ dojo.declare("alfresco.xforms.XForm", /** Returns the binding corresponding to the provided xforms node. */ getBinding: function(xformsNode) { - return this._bindings[xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":bind")]; + return this._bindings[xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":bind")]; }, /** Returns all parsed bindings. */ @@ -3792,14 +3843,14 @@ dojo.declare("alfresco.xforms.XForm", instanceId: this.getInstance().getAttribute("id") }; - var req = AjaxHelper.createRequest(this, - "swapRepeatItems", - params, - function(type, data, event) - { - this.target._handleEventLog(data.documentElement) - }); - AjaxHelper.sendRequest(req); + var req = alfresco.AjaxHelper.createRequest(this, + "swapRepeatItems", + params, + function(type, data, event) + { + this.target._handleEventLog(data.documentElement); + }); + alfresco.AjaxHelper.sendRequest(req); }, /** sets the repeat indexes by calling XFormsBean.setRepeatIndeces. */ @@ -3814,28 +3865,28 @@ dojo.declare("alfresco.xforms.XForm", params[repeatIndeces[i].repeat.id] = repeatIndeces[i].index; } params.repeatIds = params.repeatIds.join(","); - var req = AjaxHelper.createRequest(this, - "setRepeatIndeces", - params, - function(type, data, evt) - { - this.target._handleEventLog(data.documentElement); - }); - AjaxHelper.sendRequest(req); + var req = alfresco.AjaxHelper.createRequest(this, + "setRepeatIndeces", + params, + function(type, data, evt) + { + this.target._handleEventLog(data.documentElement); + }); + alfresco.AjaxHelper.sendRequest(req); }, /** Fires an action specified by the id by calling XFormsBean.fireAction. */ fireAction: function(id) { - var req = AjaxHelper.createRequest(this, - "fireAction", - { id: id }, - function(type, data, evt) - { - dojo.debug("fireAction." + type); - this.target._handleEventLog(data.documentElement); - }); - AjaxHelper.sendRequest(req); + var req = alfresco.AjaxHelper.createRequest(this, + "fireAction", + { id: id }, + function(type, data, evt) + { + dojo.debug("fireAction." + type); + this.target._handleEventLog(data.documentElement); + }); + alfresco.AjaxHelper.sendRequest(req); }, /** Sets the value of the specified control id by calling XFormsBean.setXFormsValue. */ @@ -3843,14 +3894,14 @@ dojo.declare("alfresco.xforms.XForm", { value = value == null ? "" : value; dojo.debug("setting value " + id + " = " + value); - var req = AjaxHelper.createRequest(this, - "setXFormsValue", - { id: id, value: value }, - function(type, data, evt) - { - this.target._handleEventLog(data.documentElement); - }); - AjaxHelper.sendRequest(req); + var req = alfresco.AjaxHelper.createRequest(this, + "setXFormsValue", + { id: id, value: value }, + function(type, data, evt) + { + this.target._handleEventLog(data.documentElement); + }); + alfresco.AjaxHelper.sendRequest(req); }, /** Handles the xforms event log resulting from a call to the XFormsBean. */ @@ -3928,8 +3979,8 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("cloning prototype " + originalId); var prototypeNode = _findElementById(this.xformsNode, originalId); //clone = prototypeNode.cloneNode(true); - clone = prototypeNode.ownerDocument.createElement(alfresco_xforms_constants.XFORMS_PREFIX + ":group"); - clone.setAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":appearance", "repeated"); + clone = prototypeNode.ownerDocument.createElement(alfresco.xforms.constants.XFORMS_PREFIX + ":group"); + clone.setAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":appearance", "repeated"); for (var j = 0; j < prototypeNode.childNodes.length; j++) { clone.appendChild(prototypeNode.childNodes[j].cloneNode(true)); @@ -3971,7 +4022,7 @@ dojo.declare("alfresco.xforms.XForm", var e = _findElementById(prototypeClones[prototypeClones.length - 2], originalId); if (e) { - e.setAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":prototype", "true"); + e.setAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":prototype", "true"); } } break; @@ -4070,7 +4121,7 @@ dojo.declare("alfresco.xforms.XForm", { this.submitWidget = null; var invalid = this.rootWidget.getWidgetsInvalidForSubmit(); - _show_error(document.createTextNode(alfresco_xforms_constants.resources["validation_provide_values_for_required_fields"])); + _show_error(document.createTextNode(alfresco.xforms.constants.resources["validation_provide_values_for_required_fields"])); var error_list = document.createElement("ul"); for (var j = 0; j < invalid.length; j++) { @@ -4098,7 +4149,7 @@ dojo.declare("alfresco.xforms.XForm", /** hides the error message display. */ function _hide_errors() { - var errorDiv = document.getElementById(alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); + var errorDiv = document.getElementById(alfresco.xforms.constants.XFORMS_ERROR_DIV_ID); if (errorDiv) { dojo.dom.removeChildren(errorDiv); @@ -4109,13 +4160,13 @@ function _hide_errors() /** shows the error message display. */ function _show_error(msg) { - var errorDiv = document.getElementById(alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); + var errorDiv = document.getElementById(alfresco.xforms.constants.XFORMS_ERROR_DIV_ID); if (!errorDiv) { errorDiv = document.createElement("div"); - errorDiv.setAttribute("id", alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); + errorDiv.setAttribute("id", alfresco.xforms.constants.XFORMS_ERROR_DIV_ID); dojo.html.setClass(errorDiv, "infoText statusErrorText xformsError"); - var alfUI = document.getElementById(alfresco_xforms_constants.XFORMS_UI_DIV_ID); + var alfUI = document.getElementById(alfresco.xforms.constants.XFORMS_UI_DIV_ID); dojo.dom.prependChild(errorDiv, alfUI); } @@ -4130,124 +4181,6 @@ function _show_error(msg) errorDiv.appendChild(msg); } -//////////////////////////////////////////////////////////////////////////////// -// AJAX helpers -//////////////////////////////////////////////////////////////////////////////// - -function AjaxHelper() -{ -} - -/** Creates an ajax request object. */ -AjaxHelper.createRequest = function(target, serverMethod, methodArgs, load, error) -{ - var result = new dojo.io.Request(alfresco_xforms_constants.WEBAPP_CONTEXT + - "/ajax/invoke/XFormsBean." + serverMethod, - "text/xml"); - result.target = target; - result.content = methodArgs; - result.method = "POST"; - result.load = load; - dojo.event.connect(result, "load", function(type, data, evt) - { - AjaxHelper._loadHandler(result); - }); - result.error = error || function(type, e, impl) - { - dojo.debug("error [" + type + "] " + e.message); - if (impl.status == 401) - { - document.getElementById("logout").onclick(); - } - else - { - _show_error(document.createTextNode(e.message)); - AjaxHelper._loadHandler(this); - } - }; - return result; -} - -/** Sends an ajax request object. */ -AjaxHelper.sendRequest = function(req) -{ - AjaxHelper._sendHandler(req); - req.encoding = "utf-8"; - dojo.io.queueBind(req); -} - -/** - * Returns the ajax loader div element. If it hasn't yet been created, it is created. - */ -AjaxHelper._getLoaderElement = function() -{ - var result = document.getElementById(alfresco_xforms_constants.AJAX_LOADER_DIV_ID); - if (result) - { - return result; - } - result = document.createElement("div"); - result.setAttribute("id", alfresco_xforms_constants.AJAX_LOADER_DIV_ID); - dojo.html.setClass(result, "xformsAjaxLoader"); - dojo.html.hide(result); - document.body.appendChild(result); - return result; -} - -/** All pending ajax requests. */ -AjaxHelper._requests = []; - -/** Updates the loader message or hides it if nothing is being loaded. */ -AjaxHelper._updateLoaderDisplay = function() -{ - var ajaxLoader = AjaxHelper._getLoaderElement(); - ajaxLoader.innerHTML = (AjaxHelper._requests.length == 0 - ? alfresco_xforms_constants.resources["idle"] - : (alfresco_xforms_constants.resources["loading"] + - (AjaxHelper._requests.length > 1 - ? " (" + AjaxHelper._requests.length + ")" - : "..."))); - dojo.debug(ajaxLoader.innerHTML); - if (/* djConfig.isDebug && */ AjaxHelper._requests.length != 0) - { - dojo.html.show(ajaxLoader); - } - else - { - dojo.html.hide(ajaxLoader); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// ajax event handlers -//////////////////////////////////////////////////////////////////////////////// - -AjaxHelper._sendHandler = function(req) -{ - AjaxHelper._requests.push(req); - AjaxHelper._updateLoaderDisplay(); -} - -AjaxHelper._loadHandler = function(req) -{ - var index = AjaxHelper._requests.indexOf(req); - if (index != -1) - { - AjaxHelper._requests.splice(index, 1); - } - else - { - var urls = []; - for (var i = 0; i < AjaxHelper._requests.length; i++) - { - urls.push(AjaxHelper._requests[i].url); - } - throw new Error("unable to find " + req.url + - " in [" + urls.join(", ") + "]"); - } - AjaxHelper._updateLoaderDisplay(); -} - //////////////////////////////////////////////////////////////////////////////// // DOM utilities //////////////////////////////////////////////////////////////////////////////// @@ -4298,9 +4231,12 @@ function _getElementsByTagNameNS(parentNode, ns, nsPrefix, tagName) function _evaluateXPath(xpath, contextNode, result_type) { var xmlDocument = contextNode.ownerDocument; - dojo.debug("evaluating xpath " + xpath + - " on node " + contextNode.nodeName + - " in document " + xmlDocument); + if (djConfig.isDebug) + { + dojo.debug("evaluating xpath " + xpath + + " on node " + contextNode.nodeName + + " in document " + xmlDocument); + } var result = null; if (xmlDocument.evaluate) { @@ -4340,7 +4276,11 @@ function _evaluateXPath(xpath, contextNode, result_type) namespaces.push(attr.nodeName + "=\'" + attr.nodeValue + "\'"); } } - dojo.debug("using namespaces " + namespaces.join(",")); + + if (djConfig.isDebug) + { + dojo.debug("using namespaces " + namespaces.join(",")); + } xmlDocument.setProperty("SelectionNamespaces", namespaces.join(' ')); if (result_type == XPathResult.FIRST_ORDERED_NODE_TYPE) { @@ -4357,12 +4297,21 @@ function _evaluateXPath(xpath, contextNode, result_type) if (!XPathResult) { - var XPathResult = {}; - XPathResult.ANY_TYPE = 0; - XPathResult.NUMBER_TYPE = 1; - XPathResult.STRING_TYPE = 2; - XPathResult.BOOEAN_TYPE = 3; - XPathResult.FIRST_ORDERED_NODE_TYPE = 9; + var XPathResult = + { + ANY_TYPE: 0, + NUMBER_TYPE: 1, + STRING_TYPE: 2, + BOOEAN_TYPE: 3, + FIRST_ORDERED_NODE_TYPE: 9 + }; +} +if (!String.prototype.startsWith) +{ + String.prototype.startsWith = function(s) + { + return this.indexOf(s) == 0; + } } if (!Array.prototype.indexOf) @@ -4388,678 +4337,229 @@ if (!Array.prototype.peek) } } +dojo.html.toCamelCase = function(str) +{ + return str.replace(/-./, function(str) { return str.charAt(1).toUpperCase(); }); +} + //////////////////////////////////////////////////////////////////////////////// -// Custom widget implementations. +// tiny mce integration //////////////////////////////////////////////////////////////////////////////// -/** - * The file picker widget. - */ -function FilePickerWidget(uploadId, node, value, readonly, change_callback, resize_callback) -{ - this.uploadId = uploadId; - this.node = node; - this.value = value == null || value.length == 0 ? null : value; - this.readonly = readonly || false; - this.change_callback = change_callback; - this.resize_callback = resize_callback; -} +tinyMCE.init({ + theme: "advanced", + mode: "exact", + width: -1, + auto_resize: false, + force_p_newlines: false, + encoding: "UTF-8", + entity_encoding: "raw", + add_unload_trigger: false, + add_form_submit_trigger: false, + execcommand_callback: "alfresco_TinyMCE_execcommand_callback", + theme_advanced_toolbar_location: "top", + theme_advanced_toolbar_align: "left", + theme_advanced_buttons1: "bold,italic,underline,strikethrough,separator,fontselect,fontsizeselect", + theme_advanced_buttons2: "link,unlink,image,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,undo,redo,separator,forecolor,backcolor", + theme_advanced_buttons3: "", + urlconverter_callback: "alfresco_TinyMCE_urlconverter_callback" +}); -// static methods and properties - -FilePickerWidget._uploads = []; -FilePickerWidget._handleUpload = function(id, fileInput, webappRelativePath, widget) +function alfresco_TinyMCE_urlconverter_callback(href, element, onsave) { - FilePickerWidget._uploads[id] = + dojo.debug("request to convert " + href + " onsave = " + onsave); + if (onsave) { - widget:widget, - path: fileInput.value, - webappRelativePath: webappRelativePath - }; - - handle_upload_helper(fileInput, - id, - FilePickerWidget._upload_completeHandler, - alfresco_xforms_constants.WEBAPP_CONTEXT, - "/ajax/invoke/XFormsBean.uploadFile", - { currentPath: webappRelativePath }); -} - -FilePickerWidget._upload_completeHandler = function(id, path, fileName, fileTypeImage, error) -{ - var upload = FilePickerWidget._uploads[id]; - upload.widget._upload_completeHandler(fileName, - upload.webappRelativePath, - fileTypeImage, - error); -} - -// instance methods and properties - -FilePickerWidget.prototype = { - -getValue: function() -{ - return this.value; -}, - -setValue: function(v) -{ - this.value = (v == null || v.length == 0 ? null : v); - if (this.selectedPathInput) - { - this.selectedPathInput.value = v; - } - - this.change_callback(this); -}, - -setReadonly: function(r) -{ - this.readonly = r; - if (this.selectButton) - { - this.selectButton.disabled = this.readonly; - } - else if (this.readonly) - { - this._showSelectedValue(); - } -}, - -render: function() -{ - this._showSelectedValue(); -}, - -_showStatus: function(text, isError) -{ - var d = this.node.ownerDocument; - if (!this.statusDiv || !this.statusDiv.parentNode) - { - this.statusDiv = d.createElement("div"); - this.statusDiv.setAttribute("id", this.uploadId + "-status"); - this.statusDiv.widget = this; - this.node.insertBefore(this.statusDiv, this.node.firstChild); - dojo.html.setClass(this.statusDiv, "infoText xformsFilePickerStatus"); - if (isError) - { - dojo.html.addClass(this.statusDiv, "statusErrorText"); - } - this.statusDiv.appendChild(d.createTextNode(text)); - this.node.style.height = (parseInt(this.node.style.height) + - dojo.html.getMargin(this.statusDiv).height + - this.statusDiv.offsetHeight) + "px"; - this.resize_callback(this); + return (href && href.startsWith(alfresco.constants.AVM_WEBAPP_URL) + ? href.substring(alfresco.constants.AVM_WEBAPP_URL.length) + : href); } else { - this.statusDiv.firstChild.nodeValue = text; + return (href && href.startsWith("/") + ? alfresco.constants.AVM_WEBAPP_URL + href + : href); } - setTimeout("var _status = document.getElementById('" + this.uploadId + - "-status'); if (_status && _status) { _status.widget._hideStatus(); }", 5000); -}, +} -_hideStatus: function() +function alfresco_TinyMCE_execcommand_callback(editor_id, elm, command, user_interface, value) { - if (this.statusDiv) + if (command == "mceLink") { - var anim = dojo.lfx.html.fadeOut(this.statusDiv, 500); - var _fp_widget = this; - anim.onEnd = function() + // BEGIN COPIED FROM ADVANCED THEME editor_template_src.js + var inst = tinyMCE.getInstanceById(editor_id); + var doc = inst.getDoc(); + var selectedText = (tinyMCE.isMSIE + ? doc.selection.createRange().text + : inst.getSel().toString()); + + if (!tinyMCE.linkElement && + tinyMCE.selectedElement.nodeName.toLowerCase() != "img" && + selectedText.length <= 0) { - if (_fp_widget.statusDiv && _fp_widget.statusDiv.parentNode) + return true; + } + + var href = "", target = "", title = "", onclick = "", action = "insert", style_class = ""; + + if (tinyMCE.selectedElement.nodeName.toLowerCase() == "a") + { + tinyMCE.linkElement = tinyMCE.selectedElement; + } + + // Is anchor not a link + if (tinyMCE.linkElement != null && tinyMCE.getAttrib(tinyMCE.linkElement, 'href') == "") + { + tinyMCE.linkElement = null; + } + + if (tinyMCE.linkElement) + { + href = tinyMCE.getAttrib(tinyMCE.linkElement, 'href'); + target = tinyMCE.getAttrib(tinyMCE.linkElement, 'target'); + title = tinyMCE.getAttrib(tinyMCE.linkElement, 'title'); + onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick'); + style_class = tinyMCE.getAttrib(tinyMCE.linkElement, 'class'); + + // Try old onclick to if copy/pasted content + if (onclick == "") { - _fp_widget.node.style.height = (parseInt(_fp_widget.node.style.height) - - _fp_widget.statusDiv.offsetHeight) + "px"; - dojo.dom.removeChildren(_fp_widget.statusDiv); - dojo.dom.removeNode(_fp_widget.statusDiv); - _fp_widget.resize_callback(_fp_widget); - _fp_widget.statusDiv = null; + onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick'); } - }; - - anim.play(); - } -}, + onclick = tinyMCE.cleanupEventStr(onclick); -_showSelectedValue: function() -{ - var d = this.node.ownerDocument; - dojo.dom.removeChildren(this.node); - this.statusDiv = null; - this.contentDiv = null; - this.addContentDiv = null; + href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);"); - this.node.style.height = "20px"; - this.node.style.lineHeight = this.node.style.height; - this.node.style.position = "relative"; - this.node.style.whiteSpace = "nowrap"; - - this.resize_callback(this); - - this.selectedPathInput = d.createElement("input"); - this.selectedPathInput.type = "text"; - this.selectedPathInput.value = this.value == null ? "" : this.value; - this.node.appendChild(this.selectedPathInput); - - dojo.event.connect(this.selectedPathInput, "onblur", this, this._selectPathInput_changeHandler); - - this.selectButton = d.createElement("input"); - this.selectButton.filePickerWidget = this; - this.selectButton.type = "button"; - this.selectButton.value = this.value == null ? "Select" : "Change"; - this.selectButton.disabled = this.readonly; - this.selectButton.style.margin = "0px 10px 0px 10px"; - this.node.appendChild(this.selectButton); - - this.selectedPathInput.style.width = (1 - - ((this.selectButton.offsetWidth + - dojo.html.getMargin(this.selectButton).width) / - dojo.html.getContentBox(this.node).width)) * 100 + "%"; - dojo.event.browser.addListener(this.selectButton, - "click", - function(event) - { - var w = event.target.filePickerWidget; - w._navigateToNode(w.getValue() || ""); - }); - -}, -_selectPathInput_changeHandler: function(event) -{ - this.setValue(event.target.value); -}, -_navigateToNode: function(path) -{ - var req = AjaxHelper.createRequest(this, - "getFilePickerData", - {}, - function(type, data, evt) - { - this.target._showPicker(data.documentElement); - }); - req.content.currentPath = path; - AjaxHelper.sendRequest(req); -}, - -_showPicker: function(data) -{ - while (this.node.hasChildNodes() && - this.node.lastChild != this.statusDiv) - { - this.node.removeChild(this.node.lastChild); - } - - var d = this.node.ownerDocument; - this.node.style.height = (200 + - (this.statusDiv - ? (parseInt(this.statusDiv.style.height) + - parseInt(this.statusDiv.style.marginTop) + - parseInt(this.statusDiv.style.marginBottom)) - : 0) + "px"); - - this.resize_callback(this); - - var currentPath = data.getElementsByTagName("current-node")[0]; - currentPath = currentPath.getAttribute("webappRelativePath"); - var currentPathName = currentPath.replace(/.*\/([^/]+)/, "$1") - - var headerDiv = d.createElement("div"); - dojo.html.setClass(headerDiv, "xformsFilePickerHeader"); - this.node.appendChild(headerDiv); - headerDiv.appendChild(d.createTextNode("In: ")); - this.headerMenuTriggerLink = d.createElement("a"); - this.headerMenuTriggerLink.filePickerWidget = this; - this.headerMenuTriggerLink.style.textDecoration = "none"; - this.headerMenuTriggerLink.setAttribute("href", "javascript:void(0)"); - this.headerMenuTriggerLink.setAttribute("webappRelativePath", currentPath); - dojo.html.setClass(this.headerMenuTriggerLink, "xformsFilePickerHeaderMenuTrigger"); - headerDiv.appendChild(this.headerMenuTriggerLink); - - dojo.event.connect(this.headerMenuTriggerLink, - "onmouseover", - function(event) - { - event.currentTarget.style.backgroundColor = "#fefefe"; - event.currentTarget.style.borderStyle = "inset"; - }); - dojo.event.connect(this.headerMenuTriggerLink, - "onmouseout", - function(event) - { - var w = event.currentTarget.filePickerWidget; - if (!w.parentPathMenu) - { - event.currentTarget.style.backgroundColor = - event.currentTarget.parentNode.style.backgroundColor; - event.currentTarget.style.borderStyle = "solid"; - } - }); - dojo.event.connect(this.headerMenuTriggerLink, - "onclick", - function(event) - { - var t = event.currentTarget; - var w = t.filePickerWidget; - if (w.parentPathMenu) - { - w._closeParentPathMenu(); - } - else - { - w._openParentPathMenu(t, t.getAttribute("webappRelativePath")); - } - }); - - this.headerMenuTriggerLink.appendChild(d.createTextNode(currentPathName)); - - headerMenuTriggerImage = d.createElement("img"); - this.headerMenuTriggerLink.appendChild(headerMenuTriggerImage); - this.headerMenuTriggerLink.image = headerMenuTriggerImage; - headerMenuTriggerImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/menu.gif"); - headerMenuTriggerImage.style.borderWidth = "0px"; - headerMenuTriggerImage.style.marginLeft = "4px"; - headerMenuTriggerImage.align = "absmiddle"; - - var headerRightDiv = d.createElement("div"); - - var addContentLink = d.createElement("a"); - headerRightDiv.appendChild(addContentLink); - addContentLink.setAttribute("webappRelativePath", currentPath); - addContentLink.filePickerWidget = this; - addContentLink.setAttribute("href", "javascript:void(0)"); - dojo.event.connect(addContentLink, - "onclick", - function(event) - { - var w = event.target.filePickerWidget; - if (w.addContentDiv) - { - w._hideAddContent(); - } - else - { - w._showAddContent(event.target.getAttribute("webappRelativePath")); - } - }); - - var addContentImage = d.createElement("img"); - addContentImage.style.borderWidth = "0px"; - addContentImage.style.margin = "0px 2px 0px 2px"; - addContentImage.align = "absmiddle"; - addContentImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/add.gif"); - addContentLink.appendChild(addContentImage); - - addContentLink.appendChild(d.createTextNode(alfresco_xforms_constants.resources["add_content"])); - - var navigateToParentLink = d.createElement("a"); - headerRightDiv.appendChild(navigateToParentLink); - navigateToParentLink.setAttribute("webappRelativePath", currentPath); - navigateToParentLink.filePickerWidget = this; - navigateToParentLink.setAttribute("href", "javascript:void(0)"); - if (currentPathName != "/") - { - dojo.event.connect(navigateToParentLink, - "onclick", - function(event) - { - var w = event.target.filePickerWidget; - var parentPath = event.target.getAttribute("webappRelativePath"); - parentPath = (parentPath.lastIndexOf("/") == 0 - ? "/" - : parentPath.substring(0, parentPath.lastIndexOf("/"))); - w._navigateToNode(parentPath); - }); - } - - var navigateToParentNodeImage = d.createElement("img"); - navigateToParentNodeImage.style.borderWidth = "0px"; - dojo.html.setOpacity(navigateToParentNodeImage, (currentPathName == "/" ? .3 : 1)); - navigateToParentNodeImage.style.margin = "0px 2px 0px 2px"; - navigateToParentNodeImage.align = "absmiddle"; - navigateToParentNodeImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/up.gif"); - navigateToParentLink.appendChild(navigateToParentNodeImage); - navigateToParentLink.appendChild(d.createTextNode(alfresco_xforms_constants.resources["go_up"])); - - headerRightDiv.style.position = "absolute"; - headerRightDiv.style.height = headerDiv.style.height; - headerRightDiv.style.lineHeight = headerRightDiv.style.height; - headerRightDiv.style.top = "0px"; - headerRightDiv.style.right = "0px"; - headerRightDiv.style.paddingRight = "2px"; - headerDiv.appendChild(headerRightDiv); - - this.contentDiv = d.createElement("div"); - dojo.html.setClass(this.contentDiv, "xformsFilePickerFileList"); - this.node.appendChild(this.contentDiv); - - var footerDiv = d.createElement("div"); - dojo.html.setClass(footerDiv, "xformsFilePickerFooter"); - this.node.appendChild(footerDiv); - - var cancelButton = d.createElement("input"); - cancelButton.type = "button"; - cancelButton.filePickerWidget = this; - - cancelButton.value = alfresco_xforms_constants.resources["cancel"]; - footerDiv.appendChild(cancelButton); - - cancelButton.style.margin = ((.5 * footerDiv.offsetHeight) - - (.5 * cancelButton.offsetHeight)) + "px 0px"; - dojo.event.connect(cancelButton, "onclick", function(event) - { - var w = event.target.filePickerWidget; - w._showSelectedValue(); - }); - this.contentDiv.style.height = (this.node.offsetHeight - - (this.statusDiv ? this.statusDiv.offsetHeight : 0) - - footerDiv.offsetHeight - - headerDiv.offsetHeight - 10) + "px"; - - var childNodes = data.getElementsByTagName("child-node"); - for (var i = 0; i < childNodes.length; i++) - { - if (childNodes[i].nodeType != dojo.dom.ELEMENT_NODE) - { - continue; - } - var webappRelativePath = childNodes[i].getAttribute("webappRelativePath"); - var fileName = webappRelativePath.replace(/.*\/([^/]+)/, "$1"); - var row = this._createRow(fileName, - webappRelativePath, - childNodes[i].getAttribute("type") == "directory", - childNodes[i].getAttribute("image"), - "xformsRow" + (i % 2 ? "Even" : "Odd")); - this.contentDiv.appendChild(row); - } -}, - -_createRow: function(fileName, webappRelativePath, isDirectory, fileTypeImage, rowClass) -{ - var d = this.contentDiv.ownerDocument; - var result = d.createElement("div"); - result.setAttribute("id", fileName + "-row"); - - dojo.html.setClass(result, "xformsFilePickerRow " + rowClass); - dojo.event.browser.addListener(result, - "mouseover", - function(event) - { - var prevHover = event.currentTarget.parentNode.hoverNode; - if (prevHover) - { - dojo.html.removeClass(prevHover, "xformsRowHover"); - } - event.currentTarget.parentNode.hoverNode = event.currentTarget; - dojo.html.addClass(event.currentTarget, "xformsRowHover"); - }, - true); - dojo.event.browser.addListener(result, - "mouseout", - function(event) - { - if (event.relatedTarget && - event.relatedTarget.parentNode == event.currentTarget) - { - return true; - } - dojo.html.removeClass(event.currentTarget, "xformsRowHover"); - }, - true); - var e = d.createElement("img"); - e.align = "absmiddle"; - e.style.margin = "0px 4px 0px 4px"; - e.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + fileTypeImage); - result.appendChild(e); - - if (isDirectory) - { - e = d.createElement("a"); - e.filePickerWidget = this; - e.setAttribute("href", "javascript:void(0)"); - e.setAttribute("webappRelativePath", webappRelativePath); - dojo.event.connect(e, "onclick", function(event) - { - var w = event.target.filePickerWidget; - w._navigateToNode(event.target.getAttribute("webappRelativePath")); - return true; - }); - e.appendChild(d.createTextNode(fileName)); - result.appendChild(e); - } - else - { - result.appendChild(d.createTextNode(fileName)); - } - - e = d.createElement("input"); - e.filePickerWidget = this; - e.type = "button"; - e.name = webappRelativePath; - e.value = "Select"; - result.appendChild(e); - - e.style.position = "absolute"; - e.style.right = "10px"; - e.style.top = (.5 * result.offsetHeight) - (.5 * e.offsetHeight) + "px"; - dojo.event.connect(e, "onclick", function(event) - { - var w = event.target.filePickerWidget; - w.setValue(event.target.name); - w._showSelectedValue(); - }); - return result; -}, - -_hideAddContent: function() -{ - if (this.addContentDiv) - { - dojo.dom.removeChildren(this.addContentDiv); - dojo.dom.removeNode(this.addContentDiv); - this.addContentDiv = null; - } -}, - -_showAddContent: function(currentPath) -{ - if (this.addContentDiv) - { - return; - } - var d = this.node.ownerDocument; - this.addContentDiv = d.createElement("div"); - dojo.html.setClass(this.addContentDiv, "xformsFilePickerAddContent"); - - if (this.contentDiv.firstChild) - { - this.contentDiv.insertBefore(this.addContentDiv, this.contentDiv.firstChild); - } - else - { - this.contentDiv.appendChild(this.addContentDiv); - } - var e = d.createElement("div"); - e.style.marginLeft = "4px"; - this.addContentDiv.appendChild(e); - e.appendChild(d.createTextNode("Upload: ")); - - var fileInputDiv = d.createElement("div"); - this.addContentDiv.appendChild(fileInputDiv); - var fileInput = d.createElement("input"); - fileInput.type = "file"; - fileInput.widget = this; - fileInput.name = this.uploadId + "_file_input"; - fileInput.size = "35"; - fileInput.setAttribute("webappRelativePath", currentPath); - fileInputDiv.appendChild(fileInput); - fileInputDiv.style.position = "absolute"; - fileInputDiv.style.right = "10px"; - fileInputDiv.style.top = (.5 * this.addContentDiv.offsetHeight) - (.5 * fileInputDiv.offsetHeight) + "px"; - - dojo.event.connect(fileInput, - "onchange", - function(event) - { - var w = event.target.widget; - if (w.addContentDiv) - { - var d = w.addContentDiv.ownerDocument; - dojo.dom.removeChildren(w.addContentDiv); - - var fileName = event.target.value.replace(/.*[\/\\]([^\/\\]+)/, "$1"); - w.addContentDiv.appendChild(d.createTextNode(alfresco_xforms_constants.resources["upload"] + ": " + fileName)); - var img = d.createElement("img"); - img.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + - "/images/icons/process_animation.gif"); - img.style.position = "absolute"; - img.style.right = "10px"; - img.style.height = (.5 * w.addContentDiv.offsetHeight) + "px"; - img.style.top = (.25 * w.addContentDiv.offsetHeight) + "px"; - w.addContentDiv.appendChild(img); - } - - FilePickerWidget._handleUpload(w.uploadId, - event.target, - event.target.getAttribute("webappRelativePath"), - w); - }); -}, - -_upload_completeHandler: function(fileName, webappRelativePath, fileTypeImage, error) -{ - if (error) - { - this._showStatus(error, true); - this._hideAddContent(); - this._showAddContent(webappRelativePath); - } - else - { - var nextRow = dojo.dom.nextElement(this.addContentDiv); - var rowClass = (nextRow - ? ("xformsRow" + (dojo.html.hasClass(nextRow, "xformsRowEven") - ? "Odd" - : "Even")) - : "xformsRowEvent"); - var row = this._createRow(fileName, - webappRelativePath == "/" ? "/" + fileName : webappRelativePath + "/" + fileName, - false, - fileTypeImage, - rowClass); - this.contentDiv.replaceChild(row, this.addContentDiv); - this.addContentDiv = null; - } -}, - -_closeParentPathMenu: function() -{ - if (this.parentPathMenu) - { - dojo.dom.removeChildren(this.parentPathMenu); - dojo.dom.removeNode(this.parentPathMenu); - this.parentPathMenu = null; - } - this.headerMenuTriggerLink.style.borderStyle = "solid"; -}, - -_openParentPathMenu: function(target, path) -{ - var d = target.ownerDocument; - this.parentPathMenu = d.createElement("div"); - this.parentPathMenu.filePickerWidget = this; - d.currentParentPathMenu = this.parentPathMenu; - - // handler for closing the menu if the mouse is clicked - // outside of the menu - var parentPathMenu_documentClickHandler = function(event) - { - var t = event.target; - var d = event.target.ownerDocument; - - // always remove - this handler only ever needs to handle a single click - d.removeEventListener("click", parentPathMenu_documentClickHandler, true); - while (t && t != d) - { - if (t == d.currentParentPathMenu || - t == d.currentParentPathMenu.filePickerWidget.headerMenuTriggerLink) + // Use mce_href if defined + mceRealHref = tinyMCE.getAttrib(tinyMCE.linkElement, 'mce_href'); + if (mceRealHref != "") + { + href = mceRealHref; + if (tinyMCE.getParam('convert_urls')) + { + href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);"); + } + } + + action = "update"; + } + + var window_props = { file: alfresco.constants.WEBAPP_CONTEXT + "/jsp/wcm/tiny_mce_link_dialog.jsp", + width: 510 + tinyMCE.getLang('lang_insert_link_delta_width', 0), + height: 400 + tinyMCE.getLang('lang_insert_link_delta_height', 0) }; + var dialog_props = { href: href, + target: target, + title: title, + onclick: onclick, + action: action, + className: style_class, + inline: "yes" }; + tinyMCE.openWindow(window_props, dialog_props); + return true; + } + else if (command == "mceImage") + { + var src = "", alt = "", border = "", hspace = "", vspace = "", width = "", height = "", align = "", + title = "", onmouseover = "", onmouseout = "", action = "insert"; + var img = tinyMCE.imgElement; + var inst = tinyMCE.getInstanceById(editor_id); + + if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img") + { + img = tinyMCE.selectedElement; + tinyMCE.imgElement = img; + } + + if (img) + { + // Is it a internal MCE visual aid image, then skip this one. + if (tinyMCE.getAttrib(img, 'name').indexOf('mce_') == 0) { - // the click is coming from within the component - ignore it return true; } - t = t.parentNode; + + src = tinyMCE.getAttrib(img, 'src'); + alt = tinyMCE.getAttrib(img, 'alt'); + + // Try polling out the title + if (alt == "") + { + alt = tinyMCE.getAttrib(img, 'title'); + } + + // Fix width/height attributes if the styles is specified + if (tinyMCE.isGecko) + { + var w = img.style.width; + if (w != null && w.length != 0) + { + img.setAttribute("width", w); + } + + var h = img.style.height; + if (h != null && h.length != 0) + { + img.setAttribute("height", h); + } + } + + border = tinyMCE.getAttrib(img, 'border'); + hspace = tinyMCE.getAttrib(img, 'hspace'); + vspace = tinyMCE.getAttrib(img, 'vspace'); + width = tinyMCE.getAttrib(img, 'width'); + height = tinyMCE.getAttrib(img, 'height'); + align = tinyMCE.getAttrib(img, 'align'); + onmouseover = tinyMCE.getAttrib(img, 'onmouseover'); + onmouseout = tinyMCE.getAttrib(img, 'onmouseout'); + title = tinyMCE.getAttrib(img, 'title'); + + // Is realy specified? + if (tinyMCE.isMSIE) + { + width = img.attributes['width'].specified ? width : ""; + height = img.attributes['height'].specified ? height : ""; + } + + //onmouseover = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseover)); + //onmouseout = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseout)); + + src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);"); + + // Use mce_src if defined + mceRealSrc = tinyMCE.getAttrib(img, 'mce_src'); + if (mceRealSrc != "") + { + src = mceRealSrc; + + if (tinyMCE.getParam('convert_urls')) + { + src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);"); + } + } + action = "update"; } - d.currentParentPathMenu.filePickerWidget._closeParentPathMenu(); - }; - d.addEventListener("click", parentPathMenu_documentClickHandler, true); - dojo.html.setClass(this.parentPathMenu, "xformsFilePickerParentPathMenu"); - - var left = 0; - var top = 0; - var n = target; - do - { - left += n.offsetLeft;// + parseInt(n.style.marginLeft) + parseInt(n.style.borderLeft); - top += n.offsetTop;// + parseInt(n.style.marginTop) + parseInt(n.style.borderTop); - n = n.parentNode; - } - while (n != this.node); - this.parentPathMenu.style.top = top + target.offsetHeight + "px"; - this.parentPathMenu.style.left = left + "px"; - var parentNodes = null; - if (path == "/") - { - parentNodes = [ "/" ]; + var window_props = { file: alfresco.constants.WEBAPP_CONTEXT + "/jsp/wcm/tiny_mce_image_dialog.jsp", + width: 510 + tinyMCE.getLang('lang_insert_image_delta_width', 0), + height: 400 + (tinyMCE.isMSIE ? 25 : 0) + tinyMCE.getLang('lang_insert_image_delta_height', 0) }; + var dialog_props = { src: src, + alt: alt, + border: border, + hspace: hspace, + vspace: vspace, + width: width, + height: height, + align: align, + title: title, + onmouseover: onmouseover, + onmouseout: onmouseout, + action: action, + inline: "yes" }; + tinyMCE.openWindow(window_props, dialog_props); + return true; } else { - parentNodes = path.split("/"); - parentNodes[0] = "/"; + return false; } - - var pathTextDiv = d.createElement("div"); - pathTextDiv.style.fontWeight = "bold"; - pathTextDiv.style.paddingLeft = "5px"; - - pathTextDiv.appendChild(d.createTextNode(alfresco_xforms_constants.resources["path"])); - this.parentPathMenu.appendChild(pathTextDiv); - var currentPathNodes = []; - for (var i = 0; i < parentNodes.length; i++) - { - if (i != 0) - { - currentPathNodes.push(parentNodes[i]); - } - var path = i == 0 ? "/" : "/" + currentPathNodes.join("/"); - var parentNodeDiv = d.createElement("div"); - parentNodeDiv.setAttribute("webappRelativePath", path); - this.parentPathMenu.appendChild(parentNodeDiv); - parentNodeDiv.style.display = "block"; - parentNodeDiv.style.paddingLeft = (i * 16) + parseInt(pathTextDiv.style.paddingLeft) + "px"; - parentNodeDiv.style.paddingRight = parseInt(pathTextDiv.style.paddingLeft) + "px"; - parentNodeDiv.style.whiteSpace = "nowrap"; - - var parentNodeImage = d.createElement("img"); - parentNodeImage.align = "absmiddle"; - parentNodeImage.style.marginRight = "4px"; - parentNodeDiv.appendChild(parentNodeImage); - parentNodeImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + - "/images/icons/space_small.gif"); - parentNodeDiv.appendChild(parentNodeImage); - parentNodeDiv.appendChild(d.createTextNode(path)); - dojo.event.connect(parentNodeDiv, - "onclick", - function(event) - { - var w = event.currentTarget; - var path = w.getAttribute("webappRelativePath"); - w = w.parentNode; - w.filePickerWidget._closeParentPathMenu(); - w.filePickerWidget._navigateToNode(path); - }); - } - this.node.appendChild(this.parentPathMenu); } -};