001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.ajax;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.Session;
021import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
022import org.apache.wicket.markup.head.IHeaderResponse;
023import org.apache.wicket.markup.head.JavaScriptHeaderItem;
024import org.apache.wicket.markup.html.pages.BrowserInfoForm;
025import org.apache.wicket.protocol.http.request.WebClientInfo;
026import org.apache.wicket.request.IRequestParameters;
027import org.apache.wicket.request.cycle.RequestCycle;
028import org.apache.wicket.util.lang.Args;
029import org.danekja.java.util.function.serializable.SerializableBiConsumer;
030
031/**
032 * A behavior that collects the information to populate
033 * WebClientInfo's ClientProperties by using Ajax. Compared to
034 * {@link AjaxClientInfoBehavior} this class does not use a timer
035 * but the DOM ready "event" to collect browser info.
036 *
037 * @see #onClientInfo(AjaxRequestTarget, WebClientInfo)
038 */
039public class AjaxOnDomReadyClientInfoBehavior extends AbstractDefaultAjaxBehavior
040{
041        private static final long serialVersionUID = 1L;
042
043        @Override
044        protected void respond(AjaxRequestTarget target)
045        {
046                RequestCycle requestCycle = RequestCycle.get();
047
048                IRequestParameters requestParameters = requestCycle.getRequest().getRequestParameters();
049                WebClientInfo clientInfo = newWebClientInfo(requestCycle);
050                clientInfo.getProperties().read(requestParameters);
051                Session.get().setClientInfo(clientInfo);
052
053                onClientInfo(target, clientInfo);
054        }
055
056        protected WebClientInfo newWebClientInfo(RequestCycle requestCycle)
057        {
058                return new WebClientInfo(requestCycle);
059        }
060
061        /**
062         * A callback method invoked when the client info is collected.
063         * 
064         * @param target
065         *          The Ajax request handler
066         * @param clientInfo
067         *          The collected info for the client 
068         */
069        protected void onClientInfo(AjaxRequestTarget target, WebClientInfo clientInfo)
070        {
071        }
072
073        @Override
074        protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
075        {
076                super.updateAjaxAttributes(attributes);
077                attributes.setEventNames("domready");
078                attributes.setMethod(AjaxRequestAttributes.Method.POST);
079                attributes.getDynamicExtraParameters().add("return Wicket.BrowserInfo.collect()");
080        }
081
082        @Override
083        public void renderHead(Component component, IHeaderResponse response)
084        {
085                super.renderHead(component, response);
086
087                response.render(JavaScriptHeaderItem.forReference(BrowserInfoForm.JS));
088                response.render(JavaScriptHeaderItem.forScript(getCallbackScript(), "ajaxOnDomReadyClientInfoBehavior"));
089        }
090
091        /**
092         * Creates an {@link AjaxOnDomReadyClientInfoBehavior} based on lambda expressions
093         *
094         * @param onClientInfo
095         *            the {@code SerializableBiConsumer} which accepts the {@link AjaxRequestTarget} and the
096         *            {@link WebClientInfo}
097         * @return the {@link AjaxOnDomReadyClientInfoBehavior}
098         */
099        public static AjaxOnDomReadyClientInfoBehavior onClientInfo(SerializableBiConsumer<AjaxRequestTarget, WebClientInfo> onClientInfo)
100        {
101                Args.notNull(onClientInfo, "onClientInfo");
102
103                return new AjaxOnDomReadyClientInfoBehavior()
104                {
105
106                        private static final long serialVersionUID = 1L;
107
108                        @Override
109                        protected void onClientInfo(AjaxRequestTarget target, WebClientInfo clientInfo)
110                        {
111                                onClientInfo.accept(target, clientInfo);
112                        }
113                };
114        }
115}