You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/02/26 00:28:31 UTC
[3/24] git commit: ISIS-349, ISIS-350: jgrowl integration,
error page for exceptions
ISIS-349, ISIS-350: jgrowl integration, error page for exceptions
implemented.
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/345f22fb
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/345f22fb
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/345f22fb
Branch: refs/heads/dan/ISIS-233-ro
Commit: 345f22fbfb56de82b41721fbb49d4fc0fcdc7f23
Parents: 4ad06ff
Author: Dan Haywood <da...@apache.org>
Authored: Thu Feb 21 19:30:10 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Thu Feb 21 19:30:10 2013 +0000
----------------------------------------------------------------------
.../integration/wicket/WebRequestCycleForIsis.java | 38 +-
.../viewer/wicket/model/models/ActionModel.java | 29 ++-
.../ui/components/widgets/cssmenu/CssMenuItem.java | 7 +-
.../viewer/wicket/ui/feedback/JGrowlBehavior.java | 101 ++++
.../isis/viewer/wicket/ui/pages/PageAbstract.css | 37 ++
.../isis/viewer/wicket/ui/pages/PageAbstract.html | 20 +-
.../isis/viewer/wicket/ui/pages/PageAbstract.java | 38 ++-
.../viewer/wicket/ui/pages/action/ActionPage.java | 1 +
.../viewer/wicket/ui/pages/error/ErrorPage.css | 81 ++++
.../viewer/wicket/ui/pages/error/ErrorPage.html | 60 +++
.../viewer/wicket/ui/pages/error/ErrorPage.java | 71 +++
.../isis/viewer/wicket/ui/pages/jquery.jgrowl.css | 136 ++++++
.../isis/viewer/wicket/ui/pages/jquery.jgrowl.js | 352 +++++++++++++++
13 files changed, 934 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
index a135449..debf3ff 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
@@ -19,16 +19,19 @@
package org.apache.isis.viewer.wicket.viewer.integration.wicket;
-import org.apache.log4j.Logger;
-import org.apache.wicket.protocol.http.WebSession;
-import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
-import org.apache.wicket.request.cycle.RequestCycle;
-
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.session.IsisSession;
import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+import org.apache.isis.viewer.wicket.ui.pages.error.ErrorPage;
+import org.apache.log4j.Logger;
+import org.apache.wicket.core.request.handler.PageProvider;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
+import org.apache.wicket.request.cycle.RequestCycle;
/**
* Isis-specific implementation of the Wicket's {@link WebRequestCycle},
@@ -39,18 +42,6 @@ public class WebRequestCycleForIsis /*extends WebRequestCycle*/ extends Abstract
private static final Logger LOG = Logger.getLogger(WebRequestCycleForIsis.class);
-// public WebRequestCycleForIsis(final WebApplication application, final WebRequest request, final Response response) {
-// super(application, request, response);
-// }
-//
-// /**
-// * Convenience, downcasts.
-// */
-// @Override
-// public AuthenticatedWebSessionForIsis getWebSession() {
-// return (AuthenticatedWebSessionForIsis) super.getWebSession();
-// }
-
private AuthenticatedWebSessionForIsis getWebSession() {
return (AuthenticatedWebSessionForIsis) WebSession.get();
}
@@ -82,7 +73,6 @@ public class WebRequestCycleForIsis /*extends WebRequestCycle*/ extends Abstract
commitTransactionIfAny();
getIsisContext().closeSessionInstance();
}
- //super.onEndRequest();
}
private void commitTransactionIfAny() {
@@ -96,6 +86,11 @@ public class WebRequestCycleForIsis /*extends WebRequestCycle*/ extends Abstract
}
}
+ @Override
+ public IRequestHandler onException(RequestCycle cycle, Exception ex) {
+ return new RenderPageRequestHandler(new PageProvider(new ErrorPage(ex)));
+ }
+
/**
* Factored out so can be overridden in testing.
*/
@@ -103,13 +98,6 @@ public class WebRequestCycleForIsis /*extends WebRequestCycle*/ extends Abstract
return IsisContext.getInstance();
}
-// /**
-// * Simply downcasts superclass' implementation, for convenience of callers.
-// */
-// @Override
-// protected WebClientInfo newClientInfo() {
-// return (WebClientInfo) super.newClientInfo();
-// }
protected IsisTransactionManager getTransactionManager() {
return IsisContext.getTransactionManager();
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index 0fbe844..aed3834 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -19,18 +19,24 @@
package org.apache.isis.viewer.wicket.model.models;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import org.apache.wicket.Component;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.isis.applib.ApplicationException;
import org.apache.isis.applib.Identifier;
+import org.apache.isis.core.commons.exceptions.IsisApplicationException;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
@@ -433,12 +439,31 @@ public class ActionModel extends BookmarkableModel<ObjectAdapter> {
return results;
}
+
+ // TODO: hacky!!
+ public static ThreadLocal<String> applicationError = new ThreadLocal<String>();
+
private ObjectAdapter executeAction() {
final ObjectAdapter targetAdapter = getTargetAdapter();
final ObjectAdapter[] arguments = getArgumentsAsArray();
final ObjectAction action = getActionMemento().getAction();
- final ObjectAdapter results = action.execute(targetAdapter, arguments);
- return results;
+ try {
+ final ObjectAdapter results = action.execute(targetAdapter, arguments);
+ return results;
+ } catch(RuntimeException ex) {
+ final ApplicationException appEx = getApplicationExceptionIfAny(ex);
+ if(appEx != null) {
+ applicationError.set(appEx.getMessage());
+ return null;
+ }
+ throw ex;
+ }
+ }
+
+ private ApplicationException getApplicationExceptionIfAny(Exception ex) {
+ Iterable<ApplicationException> appEx = Iterables.filter(Throwables.getCausalChain(ex), ApplicationException.class);
+ Iterator<ApplicationException> iterator = appEx.iterator();
+ return iterator.hasNext() ? iterator.next() : null;
}
public String getReasonInvalidIfAny() {
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
index 541c5f9..3a1e3f0 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
@@ -48,6 +48,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
import org.apache.isis.core.progmodel.facets.actions.bulk.BulkFacet;
import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.ui.feedback.JGrowlBehavior;
import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
import org.apache.isis.viewer.wicket.ui.util.Components;
import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
@@ -229,6 +230,8 @@ public class CssMenuItem implements Serializable {
final LinkAndLabel linkAndLabel = cssMenuLinkFactory.newLink(null, objectAction, PageAbstract.ID_MENU_LINK);
+ linkAndLabel.getLink().add(new JGrowlBehavior());
+
final AbstractLink link = linkAndLabel.getLink();
final String actionLabel = linkAndLabel.getLabel();
@@ -262,8 +265,8 @@ public class CssMenuItem implements Serializable {
// hide link...
Components.permanentlyHide(markupContainer, ID_MENU_LINK);
// ... and show label, along with disabled reason
- label.add(new AttributeModifier("title", true, Model.of(this.getDisabledReason())));
- label.add(new AttributeModifier("class", true, Model.of("disabled")));
+ label.add(new AttributeModifier("title", Model.of(this.getDisabledReason())));
+ label.add(new AttributeModifier("class", Model.of("disabled")));
markupContainer.add(label);
return label;
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/feedback/JGrowlBehavior.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/feedback/JGrowlBehavior.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/feedback/JGrowlBehavior.java
new file mode 100644
index 0000000..24fdb98
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/feedback/JGrowlBehavior.java
@@ -0,0 +1,101 @@
+package org.apache.isis.viewer.wicket.ui.feedback;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.models.ActionModel;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+
+/**
+ * Attach to any component to display jGrowl messages.
+ *
+ * Displays only session-level messages. If you need component-level messages,
+ * see http://pastebin.com/f6db2ec0e for an example. Basically, instead of
+ * Session.get().getFeedbackMessages(), you would call
+ * getComponent().getFeedbackMessage().
+ *
+ * Requires the following be included: "jquery.js", "jquery.ui.all.js",
+ * "jquery.jgrowl.js", "jquery.jgrowl.css". These can be downloaded from
+ * http://plugins.jquery.com/files/jGrowl-1.2.0.tgz.
+ *
+ * @author jsinai Based on an example by Alex Objelean, see the above link.
+ */
+public class JGrowlBehavior extends AbstractDefaultAjaxBehavior {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Displays an info message that is sticky. The default is non-sticky.
+ * Sample usage: session.getFeedbackMessages().add(new FeedbackMessage(null,
+ * "my message", JGrowlBehavior.INFO_STICKY));
+ */
+ public static final int INFO_STICKY = 250;
+
+ @Override
+ protected void respond(AjaxRequestTarget target) {
+ final String feedbackMsg = renderFeedback();
+ if (!StringUtils.isEmpty(feedbackMsg)) {
+ target.appendJavaScript(feedbackMsg);
+ }
+ }
+
+ @Override
+ public void renderHead(Component component, IHeaderResponse response) {
+ super.renderHead(component, response);
+ final String feedbackMsg = renderFeedback();
+ if (!StringUtils.isEmpty(feedbackMsg)) {
+ response.render(OnDomReadyHeaderItem.forScript(feedbackMsg));
+ }
+ }
+
+ private String renderFeedback() {
+
+ final StringBuilder buf = new StringBuilder();
+
+ for (String info : IsisContext.getMessageBroker().getMessages()) {
+ addJGrowlCall(info, "INFO", false, buf);
+ }
+
+ for (String warning : IsisContext.getMessageBroker().getWarnings()) {
+ addJGrowlCall(warning, "WARNING", true, buf);
+ }
+
+ try {
+ final String error = ActionModel.applicationError.get();
+ if(error!=null) {
+ addJGrowlCall(error, "ERROR", true, buf);
+ }
+ } finally {
+ ActionModel.applicationError.remove();
+ }
+
+ return buf.toString();
+ }
+
+ void addJGrowlCall(final String msg, final String cssClassSuffix, boolean sticky, final StringBuilder buf) {
+ buf.append("$.jGrowl(\"").append(msg).append('\"');
+ buf.append(", {");
+ buf.append("theme: \'jgrowl-").append(cssClassSuffix).append("\'");
+ if (sticky) {
+ buf.append(", sticky: true");
+ }
+ buf.append("}");
+ buf.append(");");
+ }
+
+ boolean isSticky(final FeedbackMessage message) {
+ return message.getLevel() > FeedbackMessage.INFO;
+ }
+
+ String messageFor(final FeedbackMessage message) {
+ return (message.getMessage() == null) ? StringUtils.EMPTY : message.getMessage().toString();
+ }
+
+ String levelFor(final FeedbackMessage message) {
+ return (message.getLevel() == INFO_STICKY) ? "INFO" : message.getLevelAsString();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
index e24076b..1cdadb5 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
@@ -689,3 +689,40 @@ div.actionPanelHeaderNew .actions {
+div#jGrowl {
+ margin-top: 55px;
+ margin-right: 25px;
+ color: white;
+ font-size: larger;
+ opacity: .90;
+ filter: alpha(opacity = 90);
+}
+
+div#jGrowl div.jgrowl-ERROR {
+ background-color: #BF0B0B;
+}
+div#jGrowl div.jgrowl-WARNING {
+ background-color: orange;
+}
+div#jGrowl div.jgrowl-INFO {
+ background-color: #20B5C2;
+}
+div#jGrowl div.jgrowl-WARNING {
+ background-color: orange;
+}
+div#jGrowl div.jGrowl-closer {
+ background-color: #F0EFEA;
+ color: #46423C;
+ font-size: small;
+}
+
+/*
+colors
+#413D37 - dark banner
+#46423C - dark (writing?)
+#E4E4DB - page background
+#20B5C2 - accent
+#BF0B0B - jgrowl error
+#00477F - dark blue
+#F0EFEA - bookmark background
+*/
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
index d3da481..f5bbc65 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
@@ -22,13 +22,14 @@
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
xml:lang="en"
lang="en">
- <head>
+ <wicket:head>
+ <wicket:link>
+ <link href="cssreset.css" rel="stylesheet" type="text/css"/>
+ <link href="PageAbstract.css" rel="stylesheet" type="text/css"/>
+ <link href="jquery.jgrowl.css" rel="stylesheet" type="text/css"/>
+ </wicket:link>
<title wicket:id="pageTitle"></title>
- <wicket:link>
- <link href="cssreset.css" rel="stylesheet" type="text/css"/>
- <link href="PageAbstract.css" rel="stylesheet" type="text/css"/>
- </wicket:link>
- </head>
+ </wicket:head>
<body>
<div id="container" class="page">
@@ -60,7 +61,12 @@
<div class="clear"/>
</div>
-
+
+ <form wicket:id="form">
+ <input type="submit" value="Normal OK"/>
+ <input type="submit" value="Ajax OK" wicket:id="ajaxbutton"/>
+ </form>
+
<div id="footer">
<div class="links">
powered by: <a href="http://isis.apache.org">Apache Isis</a>
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
index d4d59da..5c283a3 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
@@ -36,20 +36,26 @@ import org.apache.isis.viewer.wicket.ui.ComponentFactory;
import org.apache.isis.viewer.wicket.ui.ComponentType;
import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
+import org.apache.isis.viewer.wicket.ui.feedback.JGrowlBehavior;
import org.apache.isis.viewer.wicket.ui.pages.about.AboutPage;
import org.apache.isis.viewer.wicket.ui.pages.login.WicketSignInPage;
-
import org.apache.log4j.Logger;
import org.apache.wicket.RestartResponseAtInterceptPageException;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.head.CssReferenceHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
import com.google.inject.Inject;
import com.google.inject.name.Named;
@@ -99,6 +105,7 @@ public abstract class PageAbstract extends WebPage {
@Named("applicationJs")
private String applicationJs;
+
public PageAbstract(final PageParameters pageParameters, final ComponentType... childComponentIds) {
try {
addApplicationActionsComponent();
@@ -106,6 +113,7 @@ public abstract class PageAbstract extends WebPage {
this.pageParameters = pageParameters;
addHomePageLinkAndApplicationName();
addUserName();
+ addNotificationPanel();
addLogoutLink();
addAboutLink();
add(new Label(ID_PAGE_TITLE, PageParameterNames.PAGE_TITLE.getStringFrom(pageParameters, applicationName)));
@@ -118,9 +126,12 @@ public abstract class PageAbstract extends WebPage {
}
}
+ private static final JavaScriptResourceReference JQUERY_JGROWL_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.jgrowl.js");
+
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
+ response.render(JavaScriptReferenceHeaderItem.forReference(JQUERY_JGROWL_JS));
if(applicationCss != null) {
response.render(CssReferenceHeaderItem.forUrl(applicationCss));
}
@@ -164,6 +175,31 @@ public abstract class PageAbstract extends WebPage {
});
}
+ private void addNotificationPanel() {
+ Form<?> form = new Form("form") {
+
+ @Override
+ protected void onSubmit() {
+ Session.get().error("Test error");
+ Session.get().warn("Test warning");
+ Session.get().info("Test info");
+ Session.get().getFeedbackMessages().add(new FeedbackMessage(null, "Test sticky info", JGrowlBehavior.INFO_STICKY));
+ }
+ };
+ add(form);
+
+ AjaxButton b = new AjaxButton("ajaxbutton", form) {
+
+ @Override
+ protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
+ target.add(form);
+ }
+ };
+ form.add(b);
+ form.add(new JGrowlBehavior());
+
+ }
+
/**
* As provided in the {@link #PageAbstract(ComponentType) constructor}.
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/action/ActionPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/action/ActionPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/action/ActionPage.java
index 8aaddd0..bfbb8fe 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/action/ActionPage.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/action/ActionPage.java
@@ -27,6 +27,7 @@ import org.apache.isis.applib.annotation.ActionSemantics;
import org.apache.isis.viewer.wicket.model.models.ActionModel;
import org.apache.isis.viewer.wicket.model.models.ActionModel.Mode;
import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.feedback.JGrowlBehavior;
import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
/**
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.css
new file mode 100644
index 0000000..1685bf1
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.css
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+.errorPage {
+ margin-left: 50px;
+ margin-right: 50px;
+ margin-top: 50px;
+}
+
+.errorPage #message {
+ background:#FFFFFF;
+ border-radius:4px;
+ -moz-border-radius:4px;
+ -webkit-border-radius:4px;
+ padding: 15px;
+ display: block;
+ text-align:center;
+ font-size:1.2em;
+}
+
+ .errorPage .errorDetail {
+ margin-top: 30px;
+}
+
+.errorPage .heading {
+ border-radius:4px;
+ -moz-border-radius:4px;
+ -webkit-border-radius:4px;
+ background-color:#F0EFEA;
+
+ display:block;
+ font-style:normal !important;
+
+ padding:1px 6px 1px 6px;
+}
+
+.errorPage .heading span {
+ display:block;
+ font-style:normal !important;
+ padding:3px 3px 3px 3px;
+ text-transform: uppercase;
+ font-size: 0.8em;
+ text-transform:uppercase;
+ font-weight:bold;
+}
+
+.errorPage .heading:hover {
+ background-color:#FFFFFF;
+ cursor: pointer;
+}
+
+.errorPage h3 {
+ font-size: larger;
+}
+
+.errorPage .exceptionMessage {
+ margin-top: 30px;
+}
+
+ .errorPage .exceptionStackTrace {
+ margin-top: 30px;
+}
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.html
new file mode 100644
index 0000000..76adce9
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.html
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
+ xml:lang="en"
+ lang="en">
+ <wicket:head>
+ <wicket:link>
+ <link href="ErrorPage.css" rel="stylesheet" type="text/css"/>
+ </wicket:link>
+<script type="text/javascript">
+ jQuery(document).ready(function() {
+ jQuery(".errorPage .content").hide();
+ //toggle the componenet with class msg_body
+ jQuery(".errorPage .heading").click(function()
+ {
+ jQuery(this).next(".errorPage .content").slideToggle(500);
+ });
+ });
+</script>
+ </wicket:head>
+ <body>
+ <wicket:extend>
+ <div class="errorPage">
+ <span id="message">Sorry, an unexpected error occurred.</span>
+ <div class="errorDetail">
+ <div class="heading"><span>Show detail</span></div>
+ <div class="content">
+ <div class="exceptionMessage">
+ <h3>Message:</h3>
+ <p wicket:id="message">Message goes here</p>
+ </div>
+ <div class="exceptionStackTrace">
+ <h3>Stack trace:</h3>
+ <p wicket:id="stackTrace">Stacktrace goes here</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </wicket:extend>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
new file mode 100644
index 0000000..3147f8d
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/error/ErrorPage.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.pages.error;
+
+import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
+import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+import com.google.common.base.Throwables;
+
+/**
+ * Web page representing the home page (showing a welcome message).
+ */
+@AuthorizeInstantiation("org.apache.isis.viewer.wicket.roles.USER")
+public class ErrorPage extends PageAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_MESSAGE = "message";
+ private static final String ID_STACK_TRACE = "stackTrace";
+
+ public ErrorPage(Exception ex) {
+ super(new PageParameters());
+ add(new Label(ID_MESSAGE, ex.getMessage()));
+ add(new Label(ID_STACK_TRACE, stackTraceAsString(ex)));
+ }
+
+ private static String stackTraceAsString(Throwable ex) {
+ StringBuilder buf = new StringBuilder();
+ appendStackTrace(ex, buf);
+ Throwable cause = ex.getCause();
+ while(cause != null) {
+ buf.append("\n\nCaused by:\n");
+ appendStackTrace(cause, buf);
+ cause = cause.getCause();
+ }
+ return buf.toString();
+ }
+
+ private static void appendStackTrace(Throwable ex, StringBuilder buf) {
+ for (StackTraceElement el : ex.getStackTrace()) {
+ buf. append(el.getClassName())
+ .append(el.getMethodName())
+ .append("(")
+ .append(el.getFileName())
+ .append(":")
+ .append(el.getLineNumber())
+ .append(")\n")
+ ;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.css
new file mode 100644
index 0000000..dbfde23
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.css
@@ -0,0 +1,136 @@
+
+div.jGrowl {
+ z-index: 9999;
+ color: #fff;
+ font-size: 12px;
+}
+
+/** Special IE6 Style Positioning **/
+div.ie6 {
+ position: absolute;
+}
+
+div.ie6.top-right {
+ right: auto;
+ bottom: auto;
+ left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
+ top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
+}
+
+div.ie6.top-left {
+ left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
+ top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
+}
+
+div.ie6.bottom-right {
+ left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
+ top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
+}
+
+div.ie6.bottom-left {
+ left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
+ top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
+}
+
+div.ie6.center {
+ left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
+ top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
+ width: 100%;
+}
+
+/** Normal Style Positions **/
+div.jGrowl {
+ position: absolute;
+}
+
+body > div.jGrowl {
+ position: fixed;
+}
+
+div.jGrowl.top-left {
+ left: 0px;
+ top: 0px;
+}
+
+div.jGrowl.top-right {
+ right: 0px;
+ top: 0px;
+}
+
+div.jGrowl.bottom-left {
+ left: 0px;
+ bottom: 0px;
+}
+
+div.jGrowl.bottom-right {
+ right: 0px;
+ bottom: 0px;
+}
+
+div.jGrowl.center {
+ top: 0px;
+ width: 50%;
+ left: 25%;
+}
+
+/** Cross Browser Styling **/
+div.center div.jGrowl-notification, div.center div.jGrowl-closer {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+div.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer {
+ background-color: #000;
+ opacity: .85;
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)";
+ filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=85);
+ zoom: 1;
+ width: 235px;
+ padding: 10px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ font-size: 1em;
+ text-align: left;
+ display: none;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+
+div.jGrowl div.jGrowl-notification {
+ min-height: 40px;
+}
+
+div.jGrowl div.jGrowl-notification,
+div.jGrowl div.jGrowl-closer {
+ margin: 10px;
+}
+
+div.jGrowl div.jGrowl-notification div.jGrowl-header {
+ font-weight: bold;
+ font-size: .85em;
+}
+
+div.jGrowl div.jGrowl-notification div.jGrowl-close {
+ z-index: 99;
+ float: right;
+ font-weight: bold;
+ font-size: 1em;
+ cursor: pointer;
+}
+
+div.jGrowl div.jGrowl-closer {
+ padding-top: 4px;
+ padding-bottom: 4px;
+ cursor: pointer;
+ font-size: .9em;
+ font-weight: bold;
+ text-align: center;
+}
+
+/** Hide jGrowl when printing **/
+@media print {
+ div.jGrowl {
+ display: none;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/345f22fb/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.js
new file mode 100644
index 0000000..cd15d4a
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.jgrowl.js
@@ -0,0 +1,352 @@
+/**
+ * jGrowl 1.2.10
+ *
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * Written by Stan Lemon <st...@gmail.com>
+ * Last updated: 2013.02.14
+ *
+ * jGrowl is a jQuery plugin implementing unobtrusive userland notifications. These
+ * notifications function similarly to the Growl Framework available for
+ * Mac OS X (http://growl.info).
+ *
+ * To Do:
+ * - Move library settings to containers and allow them to be changed per container
+ *
+ * Changes in 1.2.10
+ * - Fix beforeClose to be called in click event
+ *
+ * Changes in 1.2.9
+ * - Fixed BC break in jQuery 2.0 beta
+ *
+ * Changes in 1.2.8
+ * - Fixes for jQuery 1.9 and the MSIE6 check, note that with jQuery 2.0 support
+ * jGrowl intends to drop support for IE6 altogether
+ *
+ * Changes in 1.2.6
+ * - Fixed js error when a notification is opening and closing at the same time
+ *
+ * Changes in 1.2.5
+ * - Changed wrapper jGrowl's options usage to "o" instead of $.jGrowl.defaults
+ * - Added themeState option to control 'highlight' or 'error' for jQuery UI
+ * - Ammended some CSS to provide default positioning for nested usage.
+ * - Changed some CSS to be prefixed with jGrowl- to prevent namespacing issues
+ * - Added two new options - openDuration and closeDuration to allow
+ * better control of notification open and close speeds, respectively
+ * Patch contributed by Jesse Vincet.
+ * - Added afterOpen callback. Patch contributed by Russel Branca.
+ *
+ * Changes in 1.2.4
+ * - Fixed IE bug with the close-all button
+ * - Fixed IE bug with the filter CSS attribute (special thanks to gotwic)
+ * - Update IE opacity CSS
+ * - Changed font sizes to use "em", and only set the base style
+ *
+ * Changes in 1.2.3
+ * - The callbacks no longer use the container as context, instead they use the actual notification
+ * - The callbacks now receive the container as a parameter after the options parameter
+ * - beforeOpen and beforeClose now check the return value, if it's false - the notification does
+ * not continue. The open callback will also halt execution if it returns false.
+ * - Fixed bug where containers would get confused
+ * - Expanded the pause functionality to pause an entire container.
+ *
+ * Changes in 1.2.2
+ * - Notification can now be theme rolled for jQuery UI, special thanks to Jeff Chan!
+ *
+ * Changes in 1.2.1
+ * - Fixed instance where the interval would fire the close method multiple times.
+ * - Added CSS to hide from print media
+ * - Fixed issue with closer button when div { position: relative } is set
+ * - Fixed leaking issue with multiple containers. Special thanks to Matthew Hanlon!
+ *
+ * Changes in 1.2.0
+ * - Added message pooling to limit the number of messages appearing at a given time.
+ * - Closing a notification is now bound to the notification object and triggered by the close button.
+ *
+ * Changes in 1.1.2
+ * - Added iPhone styled example
+ * - Fixed possible IE7 bug when determining if the ie6 class shoudl be applied.
+ * - Added template for the close button, so that it's content could be customized.
+ *
+ * Changes in 1.1.1
+ * - Fixed CSS styling bug for ie6 caused by a mispelling
+ * - Changes height restriction on default notifications to min-height
+ * - Added skinned examples using a variety of images
+ * - Added the ability to customize the content of the [close all] box
+ * - Added jTweet, an example of using jGrowl + Twitter
+ *
+ * Changes in 1.1.0
+ * - Multiple container and instances.
+ * - Standard $.jGrowl() now wraps $.fn.jGrowl() by first establishing a generic jGrowl container.
+ * - Instance methods of a jGrowl container can be called by $.fn.jGrowl(methodName)
+ * - Added glue preferenced, which allows notifications to be inserted before or after nodes in the container
+ * - Added new log callback which is called before anything is done for the notification
+ * - Corner's attribute are now applied on an individual notification basis.
+ *
+ * Changes in 1.0.4
+ * - Various CSS fixes so that jGrowl renders correctly in IE6.
+ *
+ * Changes in 1.0.3
+ * - Fixed bug with options persisting across notifications
+ * - Fixed theme application bug
+ * - Simplified some selectors and manipulations.
+ * - Added beforeOpen and beforeClose callbacks
+ * - Reorganized some lines of code to be more readable
+ * - Removed unnecessary this.defaults context
+ * - If corners plugin is present, it's now customizable.
+ * - Customizable open animation.
+ * - Customizable close animation.
+ * - Customizable animation easing.
+ * - Added customizable positioning (top-left, top-right, bottom-left, bottom-right, center)
+ *
+ * Changes in 1.0.2
+ * - All CSS styling is now external.
+ * - Added a theme parameter which specifies a secondary class for styling, such
+ * that notifications can be customized in appearance on a per message basis.
+ * - Notification life span is now customizable on a per message basis.
+ * - Added the ability to disable the global closer, enabled by default.
+ * - Added callbacks for when a notification is opened or closed.
+ * - Added callback for the global closer.
+ * - Customizable animation speed.
+ * - jGrowl now set itself up and tears itself down.
+ *
+ * Changes in 1.0.1:
+ * - Removed dependency on metadata plugin in favor of .data()
+ * - Namespaced all events
+ */
+(function($) {
+ /** Compatibility holdover for 1.9 to check IE6 **/
+ var $ie6 = (function(){
+ return false === $.support.boxModel && $.support.objectAll && $support.leadingWhitespace;
+ })();
+
+ /** jGrowl Wrapper - Establish a base jGrowl Container for compatibility with older releases. **/
+ $.jGrowl = function( m , o ) {
+ // To maintain compatibility with older version that only supported one instance we'll create the base container.
+ if ( $('#jGrowl').size() == 0 )
+ $('<div id="jGrowl"></div>').addClass( (o && o.position) ? o.position : $.jGrowl.defaults.position ).appendTo('body');
+
+ // Create a notification on the container.
+ $('#jGrowl').jGrowl(m,o);
+ };
+
+
+ /** Raise jGrowl Notification on a jGrowl Container **/
+ $.fn.jGrowl = function( m , o ) {
+ if ( $.isFunction(this.each) ) {
+ var args = arguments;
+
+ return this.each(function() {
+ var self = this;
+
+ /** Create a jGrowl Instance on the Container if it does not exist **/
+ if ( $(this).data('jGrowl.instance') == undefined ) {
+ $(this).data('jGrowl.instance', $.extend( new $.fn.jGrowl(), { notifications: [], element: null, interval: null } ));
+ $(this).data('jGrowl.instance').startup( this );
+ }
+
+ /** Optionally call jGrowl instance methods, or just raise a normal notification **/
+ if ( $.isFunction($(this).data('jGrowl.instance')[m]) ) {
+ $(this).data('jGrowl.instance')[m].apply( $(this).data('jGrowl.instance') , $.makeArray(args).slice(1) );
+ } else {
+ $(this).data('jGrowl.instance').create( m , o );
+ }
+ });
+ };
+ };
+
+ $.extend( $.fn.jGrowl.prototype , {
+
+ /** Default JGrowl Settings **/
+ defaults: {
+ pool: 0,
+ header: '',
+ group: '',
+ sticky: false,
+ position: 'top-right',
+ glue: 'after',
+ theme: 'default',
+ themeState: 'highlight',
+ corners: '10px',
+ check: 250,
+ life: 3000,
+ closeDuration: 'normal',
+ openDuration: 'normal',
+ easing: 'swing',
+ closer: true,
+ closeTemplate: '×',
+ closerTemplate: '<div>[ close all ]</div>',
+ log: function(e,m,o) {},
+ beforeOpen: function(e,m,o) {},
+ afterOpen: function(e,m,o) {},
+ open: function(e,m,o) {},
+ beforeClose: function(e,m,o) {},
+ close: function(e,m,o) {},
+ animateOpen: {
+ opacity: 'show'
+ },
+ animateClose: {
+ opacity: 'hide'
+ }
+ },
+
+ notifications: [],
+
+ /** jGrowl Container Node **/
+ element: null,
+
+ /** Interval Function **/
+ interval: null,
+
+ /** Create a Notification **/
+ create: function( message , o ) {
+ var o = $.extend({}, this.defaults, o);
+
+ /* To keep backward compatibility with 1.24 and earlier, honor 'speed' if the user has set it */
+ if (typeof o.speed !== 'undefined') {
+ o.openDuration = o.speed;
+ o.closeDuration = o.speed;
+ }
+
+ this.notifications.push({ message: message , options: o });
+
+ o.log.apply( this.element , [this.element,message,o] );
+ },
+
+ render: function( notification ) {
+ var self = this;
+ var message = notification.message;
+ var o = notification.options;
+
+ // Support for jQuery theme-states, if this is not used it displays a widget header
+ o.themeState = (o.themeState == '') ? '' : 'ui-state-' + o.themeState;
+
+ var notification = $('<div/>')
+ .addClass('jGrowl-notification ' + o.themeState + ' ui-corner-all' + ((o.group != undefined && o.group != '') ? ' ' + o.group : ''))
+ .append($('<div/>').addClass('jGrowl-close').html(o.closeTemplate))
+ .append($('<div/>').addClass('jGrowl-header').html(o.header))
+ .append($('<div/>').addClass('jGrowl-message').html(message))
+ .data("jGrowl", o).addClass(o.theme).children('div.jGrowl-close').bind("click.jGrowl", function() {
+ $(this).parent().trigger('jGrowl.beforeClose');
+ })
+ .parent();
+
+
+ /** Notification Actions **/
+ $(notification).bind("mouseover.jGrowl", function() {
+ $('div.jGrowl-notification', self.element).data("jGrowl.pause", true);
+ }).bind("mouseout.jGrowl", function() {
+ $('div.jGrowl-notification', self.element).data("jGrowl.pause", false);
+ }).bind('jGrowl.beforeOpen', function() {
+ if ( o.beforeOpen.apply( notification , [notification,message,o,self.element] ) != false ) {
+ $(this).trigger('jGrowl.open');
+ }
+ }).bind('jGrowl.open', function() {
+ if ( o.open.apply( notification , [notification,message,o,self.element] ) != false ) {
+ if ( o.glue == 'after' ) {
+ $('div.jGrowl-notification:last', self.element).after(notification);
+ } else {
+ $('div.jGrowl-notification:first', self.element).before(notification);
+ }
+
+ $(this).animate(o.animateOpen, o.openDuration, o.easing, function() {
+ // Fixes some anti-aliasing issues with IE filters.
+ if ($.support.opacity === false)
+ this.style.removeAttribute('filter');
+
+ if ( $(this).data("jGrowl") != null ) // Happens when a notification is closing before it's open.
+ $(this).data("jGrowl").created = new Date();
+
+ $(this).trigger('jGrowl.afterOpen');
+ });
+ }
+ }).bind('jGrowl.afterOpen', function() {
+ o.afterOpen.apply( notification , [notification,message,o,self.element] );
+ }).bind('jGrowl.beforeClose', function() {
+ if ( o.beforeClose.apply( notification , [notification,message,o,self.element] ) != false )
+ $(this).trigger('jGrowl.close');
+ }).bind('jGrowl.close', function() {
+ // Pause the notification, lest during the course of animation another close event gets called.
+ $(this).data('jGrowl.pause', true);
+ $(this).animate(o.animateClose, o.closeDuration, o.easing, function() {
+ if ( $.isFunction(o.close) ) {
+ if ( o.close.apply( notification , [notification,message,o,self.element] ) !== false )
+ $(this).remove();
+ } else {
+ $(this).remove();
+ }
+ });
+ }).trigger('jGrowl.beforeOpen');
+
+ /** Optional Corners Plugin **/
+ if ( o.corners != '' && $.fn.corner != undefined ) $(notification).corner( o.corners );
+
+ /** Add a Global Closer if more than one notification exists **/
+ if ( $('div.jGrowl-notification:parent', self.element).size() > 1 &&
+ $('div.jGrowl-closer', self.element).size() == 0 && this.defaults.closer != false ) {
+ $(this.defaults.closerTemplate).addClass('jGrowl-closer ' + this.defaults.themeState + ' ui-corner-all').addClass(this.defaults.theme)
+ .appendTo(self.element).animate(this.defaults.animateOpen, this.defaults.speed, this.defaults.easing)
+ .bind("click.jGrowl", function() {
+ $(this).siblings().trigger("jGrowl.beforeClose");
+
+ if ( $.isFunction( self.defaults.closer ) ) {
+ self.defaults.closer.apply( $(this).parent()[0] , [$(this).parent()[0]] );
+ }
+ });
+ };
+ },
+
+ /** Update the jGrowl Container, removing old jGrowl notifications **/
+ update: function() {
+ $(this.element).find('div.jGrowl-notification:parent').each( function() {
+ if ( $(this).data("jGrowl") != undefined && $(this).data("jGrowl").created != undefined &&
+ ($(this).data("jGrowl").created.getTime() + parseInt($(this).data("jGrowl").life)) < (new Date()).getTime() &&
+ $(this).data("jGrowl").sticky != true &&
+ ($(this).data("jGrowl.pause") == undefined || $(this).data("jGrowl.pause") != true) ) {
+
+ // Pause the notification, lest during the course of animation another close event gets called.
+ $(this).trigger('jGrowl.beforeClose');
+ }
+ });
+
+ if ( this.notifications.length > 0 &&
+ (this.defaults.pool == 0 || $(this.element).find('div.jGrowl-notification:parent').size() < this.defaults.pool) )
+ this.render( this.notifications.shift() );
+
+ if ( $(this.element).find('div.jGrowl-notification:parent').size() < 2 ) {
+ $(this.element).find('div.jGrowl-closer').animate(this.defaults.animateClose, this.defaults.speed, this.defaults.easing, function() {
+ $(this).remove();
+ });
+ }
+ },
+
+ /** Setup the jGrowl Notification Container **/
+ startup: function(e) {
+ this.element = $(e).addClass('jGrowl').append('<div class="jGrowl-notification"></div>');
+ this.interval = setInterval( function() {
+ $(e).data('jGrowl.instance').update();
+ }, parseInt(this.defaults.check));
+
+ if ($ie6) {
+ $(this.element).addClass('ie6');
+ }
+ },
+
+ /** Shutdown jGrowl, removing it and clearing the interval **/
+ shutdown: function() {
+ $(this.element).removeClass('jGrowl').find('div.jGrowl-notification').remove();
+ clearInterval( this.interval );
+ },
+
+ close: function() {
+ $(this.element).find('div.jGrowl-notification').each(function(){
+ $(this).trigger('jGrowl.beforeClose');
+ });
+ }
+ });
+
+ /** Reference the Defaults Object for compatibility with older versions of jGrowl **/
+ $.jGrowl.defaults = $.fn.jGrowl.prototype.defaults;
+
+})(jQuery);