提交 4613b15c 编写于 作者: J Jesse Glick

Split out ui-samples-plugin into its own repo.

上级 89149277
......@@ -5,8 +5,6 @@
<excludeFromCompile>
<directory url="file://$PROJECT_DIR$/core/target/generated-sources/annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/core/target/generated-test-sources/test-annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/ui-samples-plugin/target/generated-sources/annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/ui-samples-plugin/target/generated-test-sources/test-annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/cli/target/generated-sources/annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/cli/target/generated-test-sources/test-annotations" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/maven-plugin/target/generated-sources/annotations" includeSubdirectories="true" />
......@@ -42,7 +40,6 @@
<module name="jenkins-core" />
<module name="jenkins-test-harness" />
<module name="jenkins-war" />
<module name="ui-samples-plugin" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
......@@ -53,7 +50,6 @@
<module name="maven-plugin" target="1.6" />
<module name="plugin" target="1.5" />
<module name="pom" target="1.6" />
<module name="ui-samples-plugin" target="1.6" />
</bytecodeTargetLevel>
</component>
<component name="JavacSettings">
......
......@@ -7,7 +7,6 @@
<file url="file://$PROJECT_DIR$/maven-plugin" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/plugins" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/test" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/ui-samples-plugin" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/war" charset="UTF-8" />
</component>
</project>
......
......@@ -4,7 +4,6 @@
<excludes>
<directory url="file://$PROJECT_DIR$/maven-plugin/src/main/resources" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/core/src/main/resources" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/ui-samples-plugin/src/main/resources" includeSubdirectories="true" />
</excludes>
</component>
</project>
......
......@@ -63,6 +63,8 @@ Upcoming changes</a>
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-8957">issue 8957</a>)
<li class='rfe'>
Split matrix authorization strategies into an independent plugin.
<li class='rfe'>
UI Samples plugin fully separated from core. To view samples during plugin development or at any other time, just install from the update center.
<li class=bug>
SCM polling sometimes broken since 1.527 due to a change in how environment variables are calculated.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-19307">issue 19307</a>)
......
......@@ -48,7 +48,6 @@ THE SOFTWARE.
<modules>
<module>core</module>
<module>ui-samples-plugin</module>
<module>war</module>
<module>test</module>
<module>cli</module>
......
<!--
The MIT License
Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi,
Daniel Dyer, Erik Ramfelt, Stephen Connolly, Tom Huybrechts
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>1.535-SNAPSHOT</version>
</parent>
<artifactId>ui-samples-plugin</artifactId>
<packaging>hpi</packaging>
<name>Jenkins UI sample plugin</name>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<!-- UI-samples plugin is also used as a test bed for automatic test injection -->
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-war</artifactId>
<type>war</type>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!--
Since new versions need to overwrite old versions, it's better
not to have version number in the .hpi file name.
-->
<finalName>${project.artifactId}</finalName>
<defaultGoal>package</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource><!-- copy all Java source files as resources -->
<directory>src/main/java</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-hpi-plugin</artifactId>
<!-- version specified in grandparent pom -->
<extensions>true</extensions>
<configuration>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>maven-stapler-plugin</artifactId>
<!-- version specified in grandparent pom -->
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.jvnet.localizer</groupId>
<artifactId>maven-localizer-plugin</artifactId>
<!-- version specified in grandparent pom -->
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<fileMask>Messages.properties</fileMask>
<outputDirectory>target/generated-sources/localizer</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.model.AutoCompletionCandidates;
import org.kohsuke.stapler.QueryParameter;
/**
* Adding auto-completion to the text box.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class AutoCompleteTextBox extends UISample {
@Override
public String getDescription() {
return "Provide auto-completion to the text box";
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
/**
* This method provides auto-completion items for the 'state' field.
* Stapler finds this method via the naming convention.
*
* @param value
* The text that the user entered.
*/
public AutoCompletionCandidates doAutoCompleteState(@QueryParameter String value) {
AutoCompletionCandidates c = new AutoCompletionCandidates();
for (String state : STATES)
if (state.toLowerCase().startsWith(value.toLowerCase()))
c.add(state);
return c;
}
}
private static final String[] STATES = new String[]{
"Alabama",
"Alaska",
"Arizona",
"Arkansas",
"California",
"Colorado",
"Connecticut",
"Delaware",
"Florida",
"Georgia",
"Hawaii",
"Idaho",
"Illinois",
"Indiana",
"Iowa",
"Kansas",
"Kentucky",
"Louisiana",
"Maine",
"Maryland",
"Massachusetts",
"Michigan",
"Minnesota",
"Mississippi",
"Missouri",
"Montana",
"Nebraska",
"Nevada",
"New Hampshire",
"New Jersey",
"New Mexico",
"New York",
"North Carolina",
"North Dakota",
"Ohio",
"Oklahoma",
"Oregon",
"Pennsylvania",
"Rhode Island",
"South Carolina",
"South Dakota",
"Tennessee",
"Texas",
"Utah",
"Vermont",
"Virginia",
"Washington",
"West Virginia",
"Wisconsin",
"Wyoming"
};
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
@Extension
public class CopyButton extends UISample {
@Override
public String getDescription() {
return "A small button to copy text into a clipboard";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(
new SourceFile("index.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import hudson.util.XStream2;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* @author Alan.Harder@oracle.com
*/
@Extension
public class DropdownList extends UISample {
@Override
public String getDescription() {
return "Show different form elements based on choice in a &lt;select> control";
}
public Fruit getFruit() {
// Could return currently configured/saved item here to initialized form with this data
return null;
}
public DescriptorExtensionList<Fruit,Descriptor<Fruit>> getFruitDescriptors() {
return Jenkins.getInstance().<Fruit,Descriptor<Fruit>>getDescriptorList(Fruit.class);
}
// Process form data and show it as serialized XML
public void doSubmit(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
// stapler-class in form data tells Stapler which Fruit subclass to use
Fruit fruit = req.bindJSON(Fruit.class, req.getSubmittedForm().getJSONObject("fruit"));
rsp.setContentType("text/plain");
new XStream2().toXML(fruit, rsp.getWriter());
}
@Override
public List<SourceFile> getSourceFiles() {
List<SourceFile> list = new java.util.ArrayList<SourceFile>(super.getSourceFiles());
list.add(new SourceFile("Apple/config.jelly"));
list.add(new SourceFile("Banana/config.jelly"));
return list;
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
public static abstract class Fruit implements ExtensionPoint, Describable<Fruit> {
protected String name;
protected Fruit(String name) { this.name = name; }
public Descriptor<Fruit> getDescriptor() {
return Jenkins.getInstance().getDescriptor(getClass());
}
}
public static class FruitDescriptor extends Descriptor<Fruit> {
public FruitDescriptor(Class<? extends Fruit> clazz) {
super(clazz);
}
public String getDisplayName() {
return clazz.getSimpleName();
}
}
public static class Apple extends Fruit {
private int seeds;
@DataBoundConstructor public Apple(int seeds) {
super("Apple");
this.seeds = seeds;
}
@Extension public static final FruitDescriptor D = new FruitDescriptor(Apple.class);
}
public static class Banana extends Fruit {
private boolean yellow;
@DataBoundConstructor public Banana(boolean yellow) {
super("Banana");
this.yellow = yellow;
}
@Extension public static final FruitDescriptor D = new FruitDescriptor(Banana.class);
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.util.ComboBoxModel;
import hudson.util.ListBoxModel;
import org.kohsuke.stapler.QueryParameter;
/**
* Combo box that changes the contents based on the values of other controls.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class DynamicComboBox extends UISample {
@Override
public String getDescription() {
return "Updates the contents of a combo box control dynamically based on selections of other controls";
}
// these getter methods should return the current value, which form the initial selection.
public String getAlbum() {
return "3";
}
public String getTitle() {
return "Rocker";
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
/**
* This method determines the values of the album drop-down list box.
*/
public ListBoxModel doFillAlbumItems() {
ListBoxModel m = new ListBoxModel();
m.add("Yellow Submarine","1");
m.add("Abbey Road","2");
m.add("Let It Be","3");
return m;
}
/**
* This method determines the values of the song title combo box.
* Note that it takes the album information as a parameter, so the contents
* of the combo box changes depending on the currently selected album.
*/
public ComboBoxModel doFillTitleItems(@QueryParameter int album) {
switch (album) {
case 1:
return new ComboBoxModel("Yellow Submarine","Only a Northern Song","All You Need Is Love");
case 2:
return new ComboBoxModel("Come Together","Something","I Want You");
case 3:
return new ComboBoxModel("The One After 909","Rocker","Get Back");
default:
// if no value is selected in the album, we'll get 0
return new ComboBoxModel();
}
}
}
}
\ No newline at end of file
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.util.ListBoxModel;
import org.kohsuke.stapler.QueryParameter;
import static java.util.Arrays.asList;
/**
* Example of a dynamic drop-down list box that changes the contents dynamically based on the values of other controls.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class DynamicDropDownListBox extends UISample {
@Override
public String getDescription() {
return "Updates the contents of a &lt;select> control dynamically based on selections of other controls";
}
// these getter methods should return the current value, which form the initial selection.
public String getCountry() {
return "USA";
}
public String getState() {
return "USA:B";
}
public String getCity() {
return "USA:B:Z";
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
public ListBoxModel doFillStateItems(@QueryParameter String country) {
ListBoxModel m = new ListBoxModel();
for (String s : asList("A","B","C"))
m.add(String.format("State %s in %s", s, country),
country+':'+s);
return m;
}
public ListBoxModel doFillCityItems(@QueryParameter String country, @QueryParameter String state) {
ListBoxModel m = new ListBoxModel();
for (String s : asList("X","Y","Z"))
m.add(String.format("City %s in %s %s", s, state, country),
state+':'+s);
return m;
}
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.RelativePath;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.util.FormValidation;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* How to access values of the nearby input fields when you do form field validation.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class FormFieldValidationWithContext extends UISample {
private List<State> states = new ArrayList<State>(Arrays.asList(
new State("California",new City("Sacramento"), Arrays.asList(new City("San Francisco"),new City("Los Angeles"))),
new State("New York",new City("New York"), Arrays.asList(new City("Albany"),new City("Ithaca")))
));
public FormFieldValidationWithContext() {
}
@DataBoundConstructor
public FormFieldValidationWithContext(List<State> states) {
this.states = states;
}
@Override
public String getDescription() {
return "How to access values of the nearby input fields when you do form field validation";
}
public List<State> getStates() {
return states;
}
@Override
public List<SourceFile> getSourceFiles() {
List<SourceFile> r = super.getSourceFiles();
r.add(new SourceFile("City/config.groovy"));
r.add(new SourceFile("State/config.groovy"));
return r;
}
public static class State extends AbstractDescribableImpl<State> {
/*
I'm lazy and just exposing fields as opposed to getter/setter.
Jenkins doesn't care and works correctly either way.
*/
public String name;
public City capital;
public List<City> cities;
@DataBoundConstructor
public State(String name, City capital, List<City> cities) {
this.name = name;
this.capital = capital;
this.cities = cities;
}
@Extension
public static class DescriptorImpl extends Descriptor<State> {
@Override
public String getDisplayName() {
return "";
}
public FormValidation doCheckName(@QueryParameter String value,
@RelativePath("capital") @QueryParameter String name) {
/*
@RelativePath("capital") @QueryParameter
... is short for
@RelativePath("capital") @QueryParameter("name")
... and thus can be thought of "capital/name"
so this matches the current city name entered as the capital of this state
*/
return FormValidation.ok("Are you sure " + name + " is a capital of " + value + "?");
}
}
}
public static class City extends AbstractDescribableImpl<City> {
public String name;
@DataBoundConstructor
public City(String name) {
this.name = name;
}
@Extension
public static class DescriptorImpl extends Descriptor<City> {
@Override
public String getDisplayName() {
return "";
}
public FormValidation doCheckName(@QueryParameter String value,
@RelativePath("..") @QueryParameter String name) {
/*
@RelativePath("..") @QueryParameter
... is short for
@RelativePath("..") @QueryParameter("name")
... and thus can be thought of "../name"
in the UI, fields for city is wrapped inside those of state, so "../name" binds
to the name field in the state.
*/
if (name==null || value==null || value.contains(name)) return FormValidation.ok();
return FormValidation.warning("City name doesn't contain "+name);
}
}
}
@Extension
public static class DescriptorImpl extends UISampleDescriptor {
}
}
/*
* The MIT License
*
* Copyright 2013 Jesse Glick.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.XmlFile;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.util.FormApply;
import hudson.util.ListBoxModel;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.StaplerRequest;
@Extension public final class HeteroList extends UISample {
@Override public String getDescription() {
return "Show a heterogeneous list of subitems with different data bindings for radio buttons and checkboxes";
}
@Override public List<SourceFile> getSourceFiles() {
return super.getSourceFiles();
// TODO add others
}
@Extension public static final class DescriptorImpl extends UISampleDescriptor {}
public XmlFile getConfigFile() {
return new XmlFile(new File(Jenkins.getInstance().getRootDir(), "stuff.xml"));
}
private Config config;
public HeteroList() throws IOException {
XmlFile xml = getConfigFile();
if (xml.exists()) {
xml.unmarshal(this);
}
}
public Config getConfig() {
return config;
}
public void setConfig(Config config) {
this.config = config;
}
public HttpResponse doConfigSubmit(StaplerRequest req) throws ServletException, IOException {
config = null; // otherwise bindJSON will never clear it once set
req.bindJSON(this, req.getSubmittedForm());
getConfigFile().write(this);
return FormApply.success(".");
}
public static final class Config extends AbstractDescribableImpl<Config> {
private final List<Entry> entries;
@DataBoundConstructor public Config(List<Entry> entries) {
this.entries = entries != null ? new ArrayList<Entry>(entries) : Collections.<Entry>emptyList();
}
public List<Entry> getEntries() {
return Collections.unmodifiableList(entries);
}
@Extension public static class DescriptorImpl extends Descriptor<Config> {
@Override public String getDisplayName() {return "";}
}
}
public static abstract class Entry extends AbstractDescribableImpl<Entry> {}
public static final class SimpleEntry extends Entry {
private final String text;
@DataBoundConstructor public SimpleEntry(String text) {
this.text = text;
}
public String getText() {
return text;
}
@Extension public static class DescriptorImpl extends Descriptor<Entry> {
@Override public String getDisplayName() {
return "Simple Entry";
}
}
}
public static final class ChoiceEntry extends Entry {
private final String choice;
@DataBoundConstructor public ChoiceEntry(String choice) {
this.choice = choice;
}
public String getChoice() {
return choice;
}
@Extension public static class DescriptorImpl extends Descriptor<Entry> {
@Override public String getDisplayName() {
return "Choice Entry";
}
public ListBoxModel doFillChoiceItems() {
return new ListBoxModel().add("good").add("bad").add("ugly");
}
}
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
@Extension
public class InpageNavigationWithBreadcrumb extends UISample {
@Override
public String getDescription() {
return "Adds in-page navigation with extra breadcrumb";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(
new SourceFile("index.groovy"),
new SourceFile("header.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import org.kohsuke.stapler.bind.JavaScriptMethod;
/**
* "Export" Java objects to JavaScript in the browser as a proxy object, so that
* you can make ajax-calls to the server later.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class JavaScriptProxy extends UISample {
private int i;
@Override
public String getDescription() {
return "Use JavaScript proxy objects to access server-side Java objects from inside the browser.";
}
/**
* The annotation exposes this method to JavaScript proxy.
*/
@JavaScriptMethod
public int increment(int n) {
return i+=n;
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* Define portions of view fragments in separate methods/classes to improve reuse.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class ModularizeViewScript extends UISample {
@Override
public String getDescription() {
return "Define portions of view fragments in separate methods/classes to improve reuse";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(new SourceFile("index.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import jenkins.model.ModelObjectWithChildren;
import jenkins.model.ModelObjectWithContextMenu;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* @author Kohsuke Kawaguchi
*/
@Extension
public class NavigationContextMenu extends UISample implements ModelObjectWithContextMenu, ModelObjectWithChildren {
@Override
public String getDescription() {
return "Integrate with navigational context menu to provider quick access around object graph";
}
/**
* This method is called via AJAX to obtain the context menu for this model object.
*/
public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
if (false) {
// this implementation is suffice for most ModelObjects. It uses sidepanel.jelly/.groovy to
// generate the context menu
return new ContextMenu().from(this,request,response);
} else {
// otherwise you can also programatically create them.
// see the javadoc for various convenience methods to add items
return new ContextMenu()
.add("http://jenkins-ci.org/","Jenkins project")
.add("http://www.cloudbees.com/","CloudBees")
.add(new MenuItem().withContextRelativeUrl("/").withStockIcon("gear.png").withDisplayName("top page"));
}
}
public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
// You implement this method in much the same way you do doContextMenu
return new ContextMenu()
.add("http://yahoo.com/","Yahoo")
.add("http://google.com/","Google")
.add("http://microsoft.com/","Microsoft");
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
@Extension
public class NotificationBar extends UISample {
@Override
public String getDescription() {
return "Notification bar shows a transient message on the top of the page";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(
new SourceFile("index.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
@Extension
public class ProgressBar extends UISample {
@Override
public String getDescription() {
return "Shows you how to use the progress bar widget that's used in the executor view and other places";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(
// new SourceFile(getClass().getSimpleName() + ".java"), // nothing interesting in the Java source file
new SourceFile("index.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
/*
* The MIT License
*
* Copyright 2012 Jesse Glick.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.LinkedList;
import java.util.List;
import jenkins.util.ProgressiveRendering;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@Extension
public class ProgressivelyRendered extends UISample {
@Override public String getDescription() {
return "Shows how to use progressively rendered content to avoid overloading the server with a slow HTTP request.";
}
public ProgressiveRendering factor(final String numberS) {
return new ProgressiveRendering() {
final List<Integer> newFactors = new LinkedList<Integer>();
@Override protected void compute() throws Exception {
int number = Integer.parseInt(numberS); // try entering a nonnumeric value!
// Deliberately inefficient:
for (int i = 1; i <= number; i++) {
if (canceled()) {
return;
}
if (i % 1000000 == 0) {
Thread.sleep(10); // take a breather
}
if (number % i == 0) {
synchronized (this) {
newFactors.add(i);
}
}
progress(((double) i) / number);
}
}
@Override protected synchronized JSON data() {
JSONArray r = new JSONArray();
for (int i : newFactors) {
r.add(i);
}
newFactors.clear();
return new JSONObject().accumulate("newfactors", r);
}
};
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import hudson.model.RootAction;
import jenkins.model.ModelObjectWithContextMenu;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import java.util.List;
/**
* Entry point to all the UI samples.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class Root implements RootAction, ModelObjectWithContextMenu {
public String getIconFileName() {
return "gear.png";
}
public String getDisplayName() {
return "UI Samples";
}
public String getUrlName() {
return "ui-samples";
}
public UISample getDynamic(String name) {
for (UISample ui : getAll())
if (ui.getUrlName().equals(name))
return ui;
return null;
}
public List<UISample> getAll() {
return UISample.all();
}
public List<UISample> getAllGroovy() {
return UISample.getGroovySamples();
}
public List<UISample> getAllOther() {
return UISample.getOtherSamples();
}
public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
return new ContextMenu().addAll(getAll());
}
}
package jenkins.plugins.ui_samples;
import hudson.Extension;
import java.util.Arrays;
import java.util.List;
/**
* Syntax-highlighted text area (powered by CodeMirror).
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class SyntaxHighlightedTextArea extends UISample {
@Override
public String getDescription() {
return "Syntax-highlighted text area powered by CodeMirror";
}
public List<SourceFile> getSourceFiles() {
// TODO: generate this from index
return Arrays.asList(new SourceFile(getClass().getSimpleName() + ".java"),
new SourceFile("index.groovy"));
}
@Extension
public static final class DescriptorImpl extends UISampleDescriptor {
}
}
package jenkins.plugins.ui_samples;
import static org.apache.commons.io.IOUtils.copy;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Action;
import hudson.model.Describable;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* @author Kohsuke Kawaguchi
*/
public abstract class UISample implements ExtensionPoint, Action, Describable<UISample> {
public String getIconFileName() {
return "gear.png";
}
public String getUrlName() {
return getClass().getSimpleName();
}
/**
* Default display name.
*/
public String getDisplayName() {
return getClass().getSimpleName();
}
/**
* Source files associated with this sample.
*/
public List<SourceFile> getSourceFiles() {
List<SourceFile> r = new ArrayList<SourceFile>();
r.add(new SourceFile(getClass().getSimpleName()+".java"));
for (String name : new String[]{"index.jelly","index.groovy"}) {
SourceFile s = new SourceFile(name);
if (s.resolve()!=null)
r.add(s);
}
return r;
}
/**
* Binds {@link SourceFile}s into URL.
*/
public void doSourceFile(StaplerRequest req, StaplerResponse rsp) throws IOException {
String name = req.getRestOfPath().substring(1); // Remove leading /
for (SourceFile sf : getSourceFiles())
if (sf.name.equals(name)) {
sf.doIndex(rsp);
return;
}
rsp.sendError(rsp.SC_NOT_FOUND);
}
/**
* Returns a paragraph of natural text that describes this sample.
* Interpreted as HTML.
*/
public abstract String getDescription();
public UISampleDescriptor getDescriptor() {
return (UISampleDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass());
}
/**
* Returns all the registered {@link UISample}s.
*/
public static ExtensionList<UISample> all() {
return Jenkins.getInstance().getExtensionList(UISample.class);
}
public static List<UISample> getGroovySamples() {
List<UISample> r = new ArrayList<UISample>();
for (UISample uiSample : UISample.all()) {
for (SourceFile src : uiSample.getSourceFiles()) {
if (src.name.contains("groovy")) {
r.add(uiSample);
break;
}
}
}
return r;
}
public static List<UISample> getOtherSamples() {
List<UISample> r = new ArrayList<UISample>();
OUTER:
for (UISample uiSample : UISample.all()) {
for (SourceFile src : uiSample.getSourceFiles()) {
if (src.name.contains("groovy")) {
continue OUTER;
}
}
r.add(uiSample);
}
return r;
}
/**
* @author Kohsuke Kawaguchi
*/
public class SourceFile {
public final String name;
public SourceFile(String name) {
this.name = name;
}
public URL resolve() {
return UISample.this.getClass().getResource(
(name.endsWith(".jelly") || name.endsWith(".groovy")) ? UISample.this.getClass().getSimpleName()+"/"+name : name);
}
/**
* Serves this source file.
*/
public void doIndex(StaplerResponse rsp) throws IOException {
rsp.setContentType("text/plain;charset=UTF-8");
copy(resolve().openStream(),rsp.getOutputStream());
}
}
}
package jenkins.plugins.ui_samples;
import hudson.model.Descriptor;
/**
* @author Kohsuke Kawaguchi
*/
public abstract class UISampleDescriptor extends Descriptor<UISample> {
@Override
public String getDisplayName() {
return clazz.getSimpleName();
}
}
<div>
Demonstration of UI controls available in Jenkins based on Stapler, Jelly, Groovy and etc.
</div>
<!--
~ The MIT License
~
~ Copyright (c) 2010, InfraDNA, Inc.
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="Dynamic ComboBox Sample">
<form>
<table>
<f:entry title="U.S. State" field="state">
<f:textbox />
</f:entry>
</table>
</form>
</s:sample>
</j:jelly>
package jenkins.plugins.ui_samples.CopyButton;
import lib.JenkinsTagLib
import lib.LayoutTagLib
def st=namespace("jelly:stapler")
t=namespace(JenkinsTagLib.class)
l=namespace(LayoutTagLib.class)
namespace("/lib/samples").sample(title:_("Copy Button")) {
raw(_("blurb"))
div(style:"margin:2em") {
text("Copy this text! ")
l.copyButton(message:"text copied",text:"here comes ABC",container:"DIV")
}
raw(_("aboutContainerElement"))
}
blurb=\
<tt>l.copyButton</tt> tag creates a small button that allows users to paste text into the clipboard. \
Browsers make it unbelievably hard to do this simple task, so that's why we use a tag to encapsulate it. \
The tag requires two mandatory attributes. One is <tt>text</tt>, which represents the text to be copied into the clipboard. \
The other is <tt>message</tt>, which represents a message to be displayed upon the successful copying into the clipboard.
aboutContainerElement=\
According to <a href="http://code.google.com/p/zeroclipboard/wiki/Instructions#Gluing">ZeroClipboard documentation</a>, \
which is what we use for the copying, it is desirable to have an outer block element that houses a button, to improve \
the accuracy of positioning a hidden flash movie. This can be specified as a CSS selector in the <tt>container</tt> attribute. \
Note that you do not need to set the <tt>position:relative</tt> manually, as this tag will automatically set it.
\ No newline at end of file
<!--
The MIT License
Copyright (c) 2004-2010, Sun Microsystems, Inc., Alan Harder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Seeds">
<f:textbox clazz="number" name="seeds" value="${fruit.seeds}"/>
</f:entry>
</j:jelly>
<!--
The MIT License
Copyright (c) 2004-2010, Sun Microsystems, Inc., Alan Harder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="">
<f:checkbox name="yellow" checked="${fruit.yellow}" title="Yellow?"/>
</f:entry>
</j:jelly>
<!--
The MIT License
Copyright (c) 2004-2010, Oracle Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="Dropdown List Sample">
<form action="submit" method="post">
<table>
<j:set var="currentFruit" value="${it.fruit}"/>
<!-- getJSONObject("fruit") in java code gets data for this block -->
<!-- A @DataBoundConstructor with parameter "Fruit fruit" can also be used -->
<f:dropdownList name="fruit" title="Fruits">
<!-- Loop through available fruit types -->
<j:forEach var="descriptor" items="${it.fruitDescriptors}" varStatus="loop">
<!-- Set "fruit" only if it matches this descriptor -->
<j:set var="fruit" value="${descriptor==currentFruit.descriptor?currentFruit:null}"/>
<f:dropdownListBlock title="${descriptor.displayName}" value="${loop.index}"
selected="${fruit!=null}" staplerClass="${descriptor.clazz.name}">
<!-- Include config.jelly for this fruit type -->
<st:include page="${descriptor.configPage}" from="${descriptor}"/>
</f:dropdownListBlock>
</j:forEach>
</f:dropdownList>
<f:entry title="" >
<f:submit value="Submit"/>
</f:entry>
</table>
</form>
</s:sample>
</j:jelly>
<!--
The MIT License
Copyright (c) 2004-2010, Oracle Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="Dynamic ComboBox Sample">
<form>
<table>
<f:entry title="Beatles Album" field="album">
<f:select />
</f:entry>
<f:entry title="Title" field="title">
<f:combobox />
</f:entry>
</table>
</form>
</s:sample>
</j:jelly>
<!--
The MIT License
Copyright (c) 2004-2010, Oracle Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="Dynamic Drop DownList Box Sample">
<form>
<table>
<f:entry title="Country" field="country">
<f:textbox />
</f:entry>
<f:entry title="State" field="state">
<f:select />
</f:entry>
<f:entry title="City" field="city">
<f:select />
</f:entry>
</table>
</form>
</s:sample>
</j:jelly>
package jenkins.plugins.ui_samples.FormFieldValidationWithContext.City;
def f = namespace(lib.FormTagLib)
f.entry(title:"City Name", field:"name") {
f.textbox()
}
package jenkins.plugins.ui_samples.FormFieldValidationWithContext.State;
def f = namespace(lib.FormTagLib)
f.entry(title:"State Name", field:"name") {
f.textbox()
}
f.nested {
table {
f.section(title:"Capital city") {
f.property(field:"capital")
}
f.entry(title:"Other cities") {
f.repeatableProperty(field:"cities")
}
}
}
package jenkins.plugins.ui_samples.FormFieldValidationWithContext;
import lib.JenkinsTagLib
import lib.FormTagLib
def f=namespace(FormTagLib.class)
t=namespace(JenkinsTagLib.class)
namespace("/lib/samples").sample(title:_("Context-sensitive form validation")) {
p {
raw(_("blurb.context"))
raw(_("blurb.otheruse"))
raw(_("blurb.contrived"))
}
f.form {
f.entry(title:"States") {
f.repeatableProperty(field:"states")
}
}
}
blurb.context=\
Form field validation can access values of the nearby input controls, which is useful for performing \
complex context sensitive form validation.
blurb.otheruse=\
The same technique can be also used for auto-completion, populating combobox/listbox, and so on.
blurb.contrived=\
The example below is bit contrived, but all the input elements are named 'name' (for city name and state name), \
and we use <code>@RelativePath</code> so that the validation of the state name refers to the capital name, \
and the validation of the city name refers to the state name.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2013 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry field="choice" title="Choice">
<f:select/>
</f:entry>
<!-- TODO figure out if f:radioBlock can also be used for form binding: Failed to instantiate class java.lang.String from {"value":"good"} -->
</j:jelly>
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2013 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:section title="Entries">
<f:block>
<f:repeatableHeteroProperty field="entries" hasHeader="true"/>
</f:block>
</f:section>
</j:jelly>
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2013 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry field="text" title="Text">
<f:textbox/>
</f:entry>
</j:jelly>
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2013 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
<l:layout title="Configure">
<l:main-panel>
<h1>Configuration</h1>
<f:form action="configSubmit" name="config" method="post">
<j:set var="instance" value="${it}"/>
<j:set var="descriptor" value="${it.descriptor}"/>
<f:optionalProperty field="config" title="Enable Configuration"/>
<f:bottomButtonBar>
<f:submit value="${%Save}"/>
<f:apply/>
</f:bottomButtonBar>
</f:form>
</l:main-panel>
</l:layout>
</j:jelly>
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2013 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:s="/lib/samples">
<s:sample title="Hetero List Sample">
<p>
<a href="configure">Configure me!</a>
</p>
<j:if test="${it.configFile.exists()}">
<p>
Current configuration:
</p>
<pre>
${it.configFile.asString()}
</pre>
</j:if>
</s:sample>
</j:jelly>
package jenkins.plugins.ui_samples.InpageNavigationWithBreadcrumb
def l=namespace(lib.LayoutTagLib.class)
// put them under your l.layout
l.breadcrumb(title:"Click me! Click me!",id:"id-of-breadcrumb-item")
package jenkins.plugins.ui_samples.InpageNavigationWithBreadcrumb;
import lib.JenkinsTagLib
def st=namespace("jelly:stapler")
t=namespace(JenkinsTagLib.class)
namespace("/lib/samples").sample(title:_("In-page navigation via breadcrumb")) {
raw(_("blurb"))
script """
Event.observe(window,"load",function(){
var menu = new breadcrumbs.ContextMenu();
menu.add('#section1',rootURL+"/images/24x24/gear.png","Section 1")
menu.add('#section2',rootURL+"/images/24x24/gear.png","Section 2")
breadcrumbs.attachMenu('id-of-breadcrumb-item',menu);
});
"""
}
blurb=You can add arbitrary additional items to the breadcrumb bar (see above), and associate menus with them. \
This mechanism is convenient for adding anchors to a large page and provide quick access to the key parts. \
A very typical place where you want to do this is in the configuration page. There's a &lt;f:breadcrumb-config-outline> \
tag specifically for this use case, which parses &lt;f:section>s and use that to build the context menu. \
See the freestyle job configuration page for an example of using this tag.
\ No newline at end of file
<!--
The MIT License
Copyright (c) 2011, CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="AJAX with JavaScript Proxy">
<p>
In Jenkins, you can export arbitrary server-side Java object to JavaScript via a proxy,
then invoke their methods from JavaScript. See <a href="http://wiki.jenkins-ci.org/display/JENKINS/AJAX+with+JavaScript+proxy">the Wiki</a> for more details.
In this sample, we call a method on the server to increment a counter. This object is a singleton,
so you'll see the same counter value across all the browsers.
</p>
<st:bind var="a" value="${it}"/>
<div id="msg" />
<script>
window.setInterval(function () {
a.increment(1, function(t) {
document.getElementById('msg').innerHTML = t.responseObject();
})
},1000);
</script>
</s:sample>
</j:jelly>
package jenkins.plugins.ui_samples.ModularizeViewScript
import org.kohsuke.stapler.jelly.groovy.JellyBuilder
import jenkins.util.groovy.AbstractGroovyViewModule
namespace("/lib/samples").sample(title:_("Define View Fragments Elsewhere")) {
// normally this is how you generate tags,
// but these are actually just a syntax sugar for method calls to the "builder" object (which is set as the delegate of the script for you)
h2("One")
div (style:"border:1px solid blue") {
p("some pointless text")
}
// so all we need to do is to pass around this delegate object and then you can generate fragments
// from elsewhere
new SomeGenerator(builder).generateSomeFragment()
}
// I defined this class here just to make the sample concise.
// this class can be defined anywhere, and typically you'd do this somewhere in your src/main/groovy
class SomeGenerator extends AbstractGroovyViewModule {
SomeGenerator(JellyBuilder builder) {
super(builder)
}
def generateSomeFragment() {
h2("Two")
div(style:"background-color:gray; padding:2em") {
p("Hello") // once inside a closure, no explicit 'b.' reference is needed. this is just like other Groovy builders
// calling other methods
generateMoreFragment("Testing generation");
}
}
def generateMoreFragment(String msg) {
h2(msg);
f.textarea();
}
}
package jenkins.plugins.ui_samples.NavigationContextMenu;
import lib.JenkinsTagLib
def st=namespace("jelly:stapler")
t=namespace(JenkinsTagLib.class)
def example(html) {
tr {
td {
text(html)
}
td {
raw(html)
}
}
}
namespace("/lib/samples").sample(title:_("Navigational context menu integration")) {
raw(_("blurb"))
h2(_("Defining context menu"))
raw(_("blurb.define"))
h2(_("Breadcrumb integration"))
raw(_("blurb.breadcrumb"))
h2(_("Model hyperlink"))
raw(_("blurb.modelLink"))
table(border:1) {
example "<a href='.' class='model-link'>self</a>"
example "<a href='..' class='model-link'>up</a>"
}
raw(_("blurb.modelLink.inside"))
table(border:1) {
example "<a href='.' class='model-link inside'>self</a>"
example "<a href='..' class='model-link inside'>up</a>"
}
raw(_("blurb.tltr"))
table(border:1) {
example "<a href='.' class='model-link tl-tr'>self</a>"
example "<a href='..' class='model-link tl-tr'>up</a>"
}
}
blurb=<p>Jenkins consists of a large and complex graph of domain objects (<tt>ModelObject</tt>), where each node in the graph is a web page and edges are hyperlinks. \
To help users navigate quickly on this graph, Jenkins provides a mechanism to attach context menus to model objects, \
which can be used to hop multiple edges without going through individual hyperlinks.
blurb.define=<p>To define a context menu on <tt>ModelObject</tt>, implement <a href="http://javadoc.jenkins-ci.org/byShortName/ModelObjectWithContextMenu"><tt>ModelObjectWithContextMenu</tt></a>. \
See <a href="sourceFile/NavigationContextMenu.java">the example</a> for how to implement this method.
blurb.breadcrumb=<p>Implementing <tt>ModelObjectWithContextMenu</tt> is sufficient for the core to show the context menu \
for your model object in the breadcrumb. Hover your mouse over the breadcrumb of this page to see context menu \
associated with this sample. \
<p> \
In addition, implementing \
<a href="http://javadoc.jenkins-ci.org/byShortName/ModelObjectWithChildren"><tt>ModelObjectWithChildren</tt></a> \
enables you to show children of your model object in the breadcrumb when you click the \u2018>\u2019 icon that separates \
breadcrumb items.
blurb.modelLink=<p>By adding CSS class "model-link" to the &lt;a> tags pointing to model objects with context menu, \
you can enable the context menu support to that hyperlink. For example:
blurb.modelLink.inside=\
<p>Unless the hyperlink appears inline, it is often better to pre-allocate a space for the context menu anchor \
that appears when the mouse hovers over. To do this, also add the 'inside' CSS element. For example:
blurb.tltr=<p>By default, context menu appears below the link ,but this is inconvenient when model links line up in a vertical list. \
Add additional "tl-tr" CSS class (read it as 'top-left of the context menu to top-right of the target anchor) to \
make context menu appear on the right.
\ No newline at end of file
package jenkins.plugins.ui_samples.NotificationBar;
import lib.JenkinsTagLib
def st=namespace("jelly:stapler")
t=namespace(JenkinsTagLib.class)
namespace("/lib/samples").sample(title:_("Notification Bar")) {
raw(_("blurb"))
raw("To show a notification bar, call <tt>notificationBar.show('message')</tt>")
button(onclick:"notificationBar.show('This is a notification');", "Show a notification bar")
raw(_("blurb.hide"))
button(onclick:"notificationBar.hide();", "Hide it now")
raw(_("blurb.stock"))
button(onclick:"notificationBar.show('it worked!', notificationBar.OK );", "OK")
button(onclick:"notificationBar.show('something went wrong',notificationBar.WARNING);", "WARNING")
button(onclick:"notificationBar.show('something went wrong',notificationBar.ERROR);", "ERROR")
}
blurb=<p>Notification bar shows a message that disappears in a few seconds. \
It is typically used to provide feedback for asynchronous operations.
blurb.hide=<p>A notification bar will auto-hide itself, but you can programmatically hide it via <tt>notificationBar.hide()</tt>
blurb.stock=<p>For typical notifications, there are several pre-defined option set available as constants that you can use as <tt>notificationBar.show(msg,notificationBar.OK)</tt>
\ No newline at end of file
package jenkins.plugins.ui_samples.ProgressBar;
import lib.JenkinsTagLib
def st=namespace("jelly:stapler")
t=namespace(JenkinsTagLib.class)
namespace("/lib/samples").sample(title:_("Progress Bar")) {
// in this sample, we add extra margin around them
style(".progress-bar {margin:1em;}")
p("This page shows you how to use the progress bar widget")
p("The 'pos' parameter controls the degree of progress, 0-100")
t.progressBar(pos:30)
t.progressBar(pos:60)
t.progressBar(pos:90)
p("-1 will draw the progress bar in the 'indeterminate' state");
t.progressBar(pos:-1)
p("The 'red' parameter turns the progress bar to red. Used to indicate that it's overdue")
t.progressBar(pos:99, red:true)
t.progressBar(pos:-1, red:true)
p("Tooltip can be added with the 'tooltip' parameter. It can contain arbitrary HTML. Hover your mouse below to see.")
t.progressBar(pos:70, tooltip:"Allows <b>arbitrary</b> html")
p("Hyperlink can be added with the 'href' pointer. Click the progress bar below")
t.progressBar(pos:70, href:"http://jenkins-ci.org/")
}
<!--
The MIT License
Copyright 2012 Jesse Glick.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<s:sample title="Progressively Rendered">
<p>
Shows how to do something slow on the server while displaying progress.
</p>
<j:set var="number" value="${request.getParameter('number')}"/>
<form method="POST" action=".">
Enter a big number: <input name="number" type="text" value="${number}"/> <input name="Find Factors" type="submit"/>
</form>
<j:if test="${number != null}">
<script>
function display(r) {
for (var i = 0; r.newfactors.length > i; i++) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(r.newfactors[i]));
$(factors).appendChild(li);
}
}
</script>
<p>Factors of ${number}:</p>
<l:progressiveRendering handler="${it.factor(number)}" callback="display" tooltip="Factoring…"/>
<ul id="factors"/>
</j:if>
</s:sample>
</j:jelly>
<!--
The MIT License
Copyright (c) 2004-2010, Oracle Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:s="/lib/samples">
<l:layout title="UI Samples">
<l:main-panel>
<h1>UI Samples</h1>
<h2>Groovy Templates</h2>
<table>
<j:forEach var="s" items="${it.allGroovy}">
<t:summary icon="document.gif"
href="${s.urlName}" iconOnly="true">
<div class="link"><a href="${href}">${s.displayName}</a></div>
<div style="color:gray; text-decoration:none;">
<j:out value="${s.description}"/>
</div>
</t:summary>
</j:forEach>
</table>
<h2>Jelly Templates</h2>
<table>
<j:forEach var="s" items="${it.allOther}">
<t:summary icon="document.gif"
href="${s.urlName}" iconOnly="true">
<div class="link"><a href="${href}">${s.displayName}</a></div>
<div style="color:gray; text-decoration:none;">
<j:out value="${s.description}"/>
</div>
</t:summary>
</j:forEach>
</table>
</l:main-panel>
</l:layout>
</j:jelly>
def st=namespace("jelly:stapler")
namespace("/lib/samples").sample(title:_("Syntax Highlighted Text Area")) {
p("CodeMirror can be used to turn ordinary text area into syntax-highlighted content-assistable text area")
// this loads the necessary JavaScripts, if it hasn't loaded already
// the first we load is the mode definition file (mode as in Emacs mode)
// the second is the theme.
//
// for other modes, look for "clike.js" in your IDE and see adjacent folders.
st.adjunct(includes:"org.kohsuke.stapler.codemirror.mode.clike.clike")
st.adjunct(includes:"org.kohsuke.stapler.codemirror.theme.default")
// TODO: adjunct tag doesn't work because 'wroteHEAD' is not set correctly
// TODO: provide abstraction that hides CSS hookup
// this text area is what we convert to the super text area
// we use CSS class to hook up the initialization script. In this particular demo,
// the ID attribute can be used, but in more general case (such as when you use this in your Builder, etc.,
// a single web page may end up containing multiple instances of such text area, so the CSS class works better.
textarea("class":"my-groovy-textbox", style:"width:100%; height:10em")
// see CodeMirror web site for more about how to control the newly instantiated text area.
script("""
Behaviour.specify("TEXTAREA.my-groovy-textbox", "SyntaxHighlightedTextArea", 0, function(e) {
var w = CodeMirror.fromTextArea(e,{
mode:"text/x-groovy",
lineNumbers: true
}).getWrapperElement();
w.setAttribute("style","border:1px solid black; margin-top: 1em; margin-bottom: 1em")
});
""")
}
<!--
The MIT License
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Alan Harder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<st:documentation>
Page layout for UI samples and variable bindings that emulate the form environment.
<st:attribute name="title" use="required">
Page title
</st:attribute>
</st:documentation>
<j:set var="instance" value="${it}" />
<j:set var="descriptor" value="${it.descriptor}" />
<l:layout title="${title}">
<st:include page="header" optional="true" />
<l:main-panel>
<h1>${title}</h1>
<p>
<j:out value="${it.description}"/>
</p>
<h3>Source Files</h3>
<ul>
<j:forEach var="f" items="${it.sourceFiles}">
<li><a href="sourceFile/${f.name}">${f.name}</a></li>
</j:forEach>
</ul>
<h3>Sample</h3>
<d:invokeBody/>
</l:main-panel>
</l:layout>
</j:jelly>
......@@ -452,14 +452,12 @@ THE SOFTWARE.
<name>stapler.resourcePath</name>
<value>
../core/src/main/resources;
../ui-samples-plugin/src/main/resources;
</value>
</systemProperty>
<systemProperty>
<!-- enable the plugins in main by default -->
<name>hudson.bundled.plugins</name>
<value><!-- run "mvn install" once will generate the.hpl -->
${basedir}/../ui-samples-plugin/target/test-classes/the.hpl,
${project.build.directory}/${project.build.finalName}/WEB-INF/plugins/*.hpi
</value>
</systemProperty>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册