distrib/gitblit.properties | ●●●●● patch | view | raw | blame | history | |
docs/04_design.mkd | ●●●●● patch | view | raw | blame | history | |
docs/04_releases.mkd | ●●●●● patch | view | raw | blame | history | |
resources/clippy.swf | patch | view | raw | blame | history | |
src/com/gitblit/wicket/panels/ObjectContainer.java | ●●●●● patch | view | raw | blame | history | |
src/com/gitblit/wicket/panels/RepositoryUrlPanel.html | ●●●●● patch | view | raw | blame | history | |
src/com/gitblit/wicket/panels/RepositoryUrlPanel.java | ●●●●● patch | view | raw | blame | history | |
src/com/gitblit/wicket/panels/ShockWaveComponent.java | ●●●●● patch | view | raw | blame | history |
distrib/gitblit.properties
@@ -121,6 +121,13 @@ # SINCE 0.5.0 web.allowZipDownloads = true # Use Clippy (Flash solution) to provide a copy-to-clipboard button. # If false, a button with a more primitive JavaScript-based prompt box will # offer a 3-step (click, ctrl+c, enter) copy-to-clipboard alternative. # # SINCE 0.8.0 web.allowFlashCopyToClipboard = true # Default number of entries to include in RSS Syndication links # # SINCE 0.5.0 docs/04_design.mkd
@@ -11,6 +11,7 @@ The following dependencies are bundled with Gitblit. - [Bootstrap](http://twitter.github.com/bootstrap) (Apache 2.0) - [Clippy](https://github.com/mojombo/clippy) (MIT) - [google-code-prettify](http://code.google.com/p/google-code-prettify) (Apache 2.0) - [Commons Daemon](http://commons.apache.org/daemon) (Apache 2.0) - magnifying glass search icon courtesy of [Gnome](http://gnome.org) (Creative Commons CC-BY) docs/04_releases.mkd
@@ -15,7 +15,9 @@ **New:** *web.timeFormat = HH:mm* **New:** *web.datestampLongFormat = EEEE, MMMM d, yyyy* - fixed: several a bugs in FileUserService related to cleaning up old repository permissions on a rename or delete - added: primitive technique for manual *copy to clipboard* of the primary repository url - added: optional flash-based 1-step *copy to clipboard* of the primary repository url - added: javascript-based 3-step (click, ctrl+c, enter) *copy to clipboard* of the primary repository url **New:** *web.allowFlashCopyToClipboard = true* - improved: empty repositories now link to the *empty repository* page which gives some direction to the user for the next step in using Gitblit. This page displays the primary push/clone url of the repository and gives sample syntax for the git command-line client. (issue 31) - improved: unit testing framework has been migrated to JUnit4 syntax and the test suite has been redesigned to run all unit tests, including rpc, federation, and git push/clone tests resources/clippy.swfBinary files differ
src/com/gitblit/wicket/panels/ObjectContainer.java
New file @@ -0,0 +1,160 @@ /* * 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 com.gitblit.wicket.panels; import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.ResourceReference; import org.apache.wicket.Response; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.protocol.http.ClientProperties; import org.apache.wicket.protocol.http.WebRequestCycle; import org.apache.wicket.protocol.http.WebSession; import org.apache.wicket.protocol.http.request.WebClientInfo; import org.apache.wicket.request.ClientInfo; import org.apache.wicket.util.value.IValueMap; import com.gitblit.wicket.WicketUtils; /** * https://cwiki.apache.org/WICKET/object-container-adding-flash-to-a-wicket-application.html */ public abstract class ObjectContainer extends WebMarkupContainer { private static final long serialVersionUID = 1L; // Some general attributes for the object tag: private static final String ATTRIBUTE_CONTENTTYPE = "type"; private static final String ATTRIBUTE_CLASSID = "classid"; private static final String ATTRIBUTE_CODEBASE = "codebase"; // This is used for browser specific adjustments private ClientProperties clientProperties = null; public ObjectContainer(String id) { super(id); } // Set an attribute/property public abstract void setValue(String name, String value); // Get an attribute/property public abstract String getValue(String name); // Set the object's content type protected abstract String getContentType(); // Set the object's clsid (for IE) protected abstract String getClsid(); // Where to get the browser plugin (for IE) protected abstract String getCodebase(); // Object's valid attribute names protected abstract List<String> getAttributeNames(); // Object's valid parameter names protected abstract List<String> getParameterNames(); // Utility function to get the URL for the object's data protected String resolveResource(String src) { // if it's an absolute path, return it: if (src.startsWith("/") || src.startsWith("http://") || src.startsWith("https://")) return (src); // use the parent container class to resolve the resource reference Component parent = getParent(); if (parent instanceof Fragment) { // must check for fragment, otherwise we end up in Wicket namespace parent = parent.getParent(); } if (parent != null) { ResourceReference resRef = new ResourceReference(parent.getClass(), src, false); return (urlFor(resRef).toString()); } return (src); } public void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); // get the attributes from the html-source IValueMap attributeMap = tag.getAttributes(); // set the content type String contentType = getContentType(); if (contentType != null && !"".equals(contentType)) attributeMap.put(ATTRIBUTE_CONTENTTYPE, contentType); // set clsid and codebase for IE if (getClientProperties().isBrowserInternetExplorer()) { String clsid = getClsid(); String codeBase = getCodebase(); if (clsid != null && !"".equals(clsid)) attributeMap.put(ATTRIBUTE_CLASSID, clsid); if (codeBase != null && !"".equals(codeBase)) attributeMap.put(ATTRIBUTE_CODEBASE, codeBase); } // add all attributes for (String name : getAttributeNames()) { String value = getValue(name); if (value != null) attributeMap.put(name, value); } } public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) { Response response = getResponse(); response.write("\n"); // add all object's parameters: for (String name : getParameterNames()) { String value = getValue(name); if (value != null) { response.write("<param name=\""); response.write(name); response.write("\" value=\""); response.write(value); response.write("\"/>\n"); } } super.onComponentTagBody(markupStream, openTag); } // shortcut to the client properties: protected ClientProperties getClientProperties() { if (clientProperties == null) { ClientInfo clientInfo = WebSession.get().getClientInfo(); if (clientInfo == null || !(clientInfo instanceof WebClientInfo)) { clientInfo = new WebClientInfo((WebRequestCycle) getRequestCycle()); WebSession.get().setClientInfo(clientInfo); } clientProperties = ((WebClientInfo) clientInfo).getProperties(); } return (clientProperties); } } src/com/gitblit/wicket/panels/RepositoryUrlPanel.html
@@ -8,6 +8,25 @@ </wicket:head> <wicket:panel> <span wicket:id="repositoryUrl" style="color: blue;">[repository url]</span><span style="padding-left:5px;"><span class="btn" style="padding:0px 3px;vertical-align:middle;"><img wicket:id="copyIcon" style="padding-top:1px;"></img></span></span> <span wicket:id="repositoryUrl" style="color: blue;">[repository url]</span><span wicket:id="copyFunction"></span> <!-- Plain JavaScript manual copy & paste --> <wicket:fragment wicket:id="jsPanel"> <span class="btn" style="padding:0px 3px 0px 3px;vertical-align:middle;"> <img wicket:id="copyIcon" style="padding-top:1px;"></img> </span> </wicket:fragment> <!-- flash-based button-press copy & paste --> <wicket:fragment wicket:id="clippyPanel"> <object style="padding:0px 2px;vertical-align:middle;" wicket:id="clippy" width="110" height="14" bgcolor="#ffffff" quality="high" wmode="transparent" allowScriptAccess="always"></object> </wicket:fragment> </wicket:panel> </html> src/com/gitblit/wicket/panels/RepositoryUrlPanel.java
@@ -17,7 +17,11 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.image.ContextImage; import org.apache.wicket.markup.html.panel.Fragment; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.WicketUtils; public class RepositoryUrlPanel extends BasePanel { @@ -27,9 +31,22 @@ public RepositoryUrlPanel(String wicketId, String url) { super(wicketId); add(new Label("repositoryUrl", url)); if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { // clippy: flash-based copy & paste Fragment fragment = new Fragment("copyFunction", "clippyPanel", this); String baseUrl = WicketUtils.getGitblitURL(getRequest()); ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf"); clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(url)); fragment.add(clippy); add(fragment); } else { // javascript: manual copy & paste with modal browser prompt dialog Fragment fragment = new Fragment("copyFunction", "jsPanel", this); ContextImage img = WicketUtils.newImage("copyIcon", "clipboard_13x13.png"); WicketUtils.setHtmlTooltip(img, "Manual Copy to Clipboard"); img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", url)); add(img); fragment.add(img); add(fragment); } } } src/com/gitblit/wicket/panels/ShockWaveComponent.java
New file @@ -0,0 +1,205 @@ /* * 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 com.gitblit.wicket.panels; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.wicket.Response; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; import org.apache.wicket.util.value.IValueMap; /** * https://cwiki.apache.org/WICKET/object-container-adding-flash-to-a-wicket-application.html * * @author Jan Kriesten * @author manuelbarzi * @author James Moger * */ public class ShockWaveComponent extends ObjectContainer { private static final long serialVersionUID = 1L; private static final String CONTENTTYPE = "application/x-shockwave-flash"; private static final String CLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; private static final String CODEBASE = "http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0"; // valid attributes private static final List<String> attributeNames = Arrays.asList(new String[] { "classid", "width", "height", "codebase", "align", "base", "data", "flashvars" }); // valid parameters private static final List<String> parameterNames = Arrays.asList(new String[] { "devicefont", "movie", "play", "loop", "quality", "bgcolor", "scale", "salign", "menu", "wmode", "allowscriptaccess", "seamlesstabbing", "flashvars" }); // combined options (to iterate over them) private static final List<String> optionNames = new ArrayList<String>(attributeNames.size() + parameterNames.size()); static { optionNames.addAll(attributeNames); optionNames.addAll(parameterNames); } private Map<String, String> attributes; private Map<String, String> parameters; public ShockWaveComponent(String id) { super(id); attributes = new HashMap<String, String>(); parameters = new HashMap<String, String>(); } public ShockWaveComponent(String id, String movie) { this(id); setValue("movie", movie); } public ShockWaveComponent(String id, String movie, String width, String height) { this(id); setValue("movie", movie); setValue("width", width); setValue("height", height); } public void setValue(String name, String value) { // IE and other browsers handle movie/data differently. So movie is used // for IE, whereas // data is used for all other browsers. The class uses movie parameter // to handle url and // puts the values to the maps depending on the browser information String parameter = name.toLowerCase(); if ("data".equals(parameter)) parameter = "movie"; if ("movie".equals(parameter) && !getClientProperties().isBrowserInternetExplorer()) attributes.put("data", value); if (attributeNames.contains(parameter)) attributes.put(parameter, value); else if (parameterNames.contains(parameter)) parameters.put(parameter, value); } public String getValue(String name) { String parameter = name.toLowerCase(); String value = null; if ("data".equals(parameter)) { if (getClientProperties().isBrowserInternetExplorer()) return null; parameter = "movie"; } if (attributeNames.contains(parameter)) value = attributes.get(parameter); else if (parameterNames.contains(parameter)) value = parameters.get(parameter); // special treatment of movie to resolve to the url if (value != null && parameter.equals("movie")) value = resolveResource(value); return value; } public void onComponentTag(ComponentTag tag) { // get options from the markup IValueMap valueMap = tag.getAttributes(); // Iterate over valid options for (String s : optionNames) { if (valueMap.containsKey(s)) { // if option isn't set programmatically, set value from markup if (!attributes.containsKey(s) && !parameters.containsKey(s)) setValue(s, valueMap.getString(s)); // remove attribute - they are added in super.onComponentTag() // to // the right place as attribute or param valueMap.remove(s); } } super.onComponentTag(tag); } public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) { super.onComponentTagBody(markupStream, openTag); Response response = getResponse(); // add all object's parameters in embed tag too: response.write("<embed"); addParameter(response, "type", CONTENTTYPE); for (String name : getParameterNames()) { String value = getValue(name); if (value != null) { name = "movie".equals(name) ? "src" : name; addParameter(response, name, value); } } for (String name : getAttributeNames()) { if ("width".equals(name) || "height".equals(name)) { String value = getValue(name); if (value != null) { addParameter(response, name, value); } } } response.write(" />\n"); } private void addParameter(Response response, String name, String value) { response.write(" "); response.write(name); response.write("=\""); response.write(value); response.write("\""); } @Override protected String getClsid() { return CLSID; } @Override protected String getCodebase() { return CODEBASE; } @Override protected String getContentType() { return CONTENTTYPE; } @Override protected List<String> getAttributeNames() { return attributeNames; } @Override protected List<String> getParameterNames() { return parameterNames; } }