It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

How can i set dynamic values for drop-down (enum) param in the Macro Browser?

This question is related to this.

Hey,

What i have created so far:

public class ExampleMacro implements Macro {
	private final XhtmlContent xhtmlUtils;
	// ResultSet mit der view erstellen
	String sqlQuery = "Select * From city";
	DB getResultSet = new DB();
	ResultSet rs2 = getResultSet.getDB(sqlQuery);
	public ExampleMacro(XhtmlContent xhtmlUtils) {
		this.xhtmlUtils = xhtmlUtils;
	}
	@Override
	public String execute(Map<String, String> parameters, String bodyContent, ConversionContext conversionContext) throws MacroExecutionException {
		StringBuilder builder = new StringBuilder();
		builder.append("<p>");
		builder.append("<div>");
		try {
			rs2.beforeFirst();
			builder.append("<table width=\"50%\">");
			builder.append("<tr><th>ID</th><th>Name</th><th>Population</th></tr>");
			while (rs2.next()) {
				builder.append("<tr>");
				builder.append("<td>").append(rs2.getString("ID")).append("</td><td>").append(rs2.getString("Name")).append("</td><td>")
						.append(rs2.getString("Population")).append("</td>");
				builder.append("</tr>");
			}
			builder.append("</table>");
			builder.append("You've done built yourself a macro! Nice work.");
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		builder.append("</div>");
		builder.append("</p>");
		try {
			return xhtmlUtils.convertStorageToView(builder.toString(), conversionContext);
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			return e.toString();
		} catch (XhtmlException e) {
			// TODO Auto-generated catch block
			return e.toString();
		}
	}
	@Override
	public BodyType getBodyType() {
		return BodyType.RICH_TEXT;
	}
	@Override
	public OutputType getOutputType() {
		return OutputType.INLINE;
	}
}
public class DB {
	public ResultSet getDB(String sqlQuery) {
		String host = "localhost";
		String port = ":8080";
		String table = "classicmodels";
		String url = "jdbc:mysql://" + host + port + "/" + table;
		String usr = "root";
		String pwd = "1234";
		ResultSet rs = null;
		// String sqlQuery = "Select name From city";
		// Load driver
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (Exception e) {
			//log.error("Unable to load Driver: " + e.getMessage(), e);
			System.err.println("MYSQL DRIVER NOT LOADED!");
		}
		// Connect to database, run Query
		try {
			Connection con = DriverManager.getConnection(url, usr, pwd);
			Statement stmt = con.createStatement();
			rs = stmt.executeQuery(sqlQuery);
		} catch (Exception e) {
			//log.error("Unable to connect to " + url + " or run query: " + sqlQuery + ";" + e.getMessage(), e);
			System.err.println("CONNECTION TO '" + url + "' FAILED WITH USER '" + usr + "' AND STATEMENT '" + sqlQuery + "'");
			System.err.println("PASSWORD " + pwd + " FAILED");
		}
		
		return rs;
	}
}
<atlassian-plugin key="${project.groupId}.${project.artifactId}"
	name="${project.name}" plugins-version="2">
	<plugin-info>
		<description>${project.description}</description>
		<version>${project.version}</version>
		<vendor name="${project.organization.name}" url="${project.organization.url}" />
		<param name="plugin-icon">images/pluginIcon.png</param>
		<param name="plugin-logo">images/pluginLogo.png</param>
	</plugin-info>
	<!-- add our i18n resource -->
	<resource type="i18n" name="i18n" location="AWLKRef" />
	<resource type="download" name="images/" location="/images" />
	<!-- add our web resources -->
	<web-resource key="AWLKRef-resources" name="AWLKRef Web Resources">
		<dependency>com.atlassian.auiplugin:ajs</dependency>
		<resource type="download" name="AWLKRef.css" location="/css/AWLKRef.css" />
		<resource type="download" name="AWLKRef.js" location="/js/AWLKRef.js" />
		<resource type="download" name="images/" location="/images" />
		<context>AWLKRef</context>
	</web-resource>
	<!-- publish our component <component key="myPluginComponent" class="de.company.confluence.plugins.MyPluginComponentImpl" 
		public="true"> <interface>de.company.confluence.plugins.MyPluginComponent</interface> 
		</component> -->
	<!-- import from the product container -->
	<component-import key="applicationProperties"
		interface="com.atlassian.sal.api.ApplicationProperties" />
	<!-- This is a plugin module type. Note that <parameters/> is a blank field. 
		This is because your particular macro doesn't accept input. -->
	<xhtml-macro name="tutorial-confluence-macro-demo"
		class="de.markant.confluence.plugins.ExampleMacro"
		icon="/download/resources/${project.groupId}.${project.artifactId}/images/markantlogo.PNG"
		key="my-macro">
		<description>This Macro can display Content from DB</description>
		<category name="external-content" />
		<parameters>
			<!--<parameter name="Suche" type="string"></parameter>-->
			<parameter name="Select" type="enum">
				<value name="citynames"/>
			</parameter>
			<!-- <parameter name="content_input" type="confluence-content" />
			<parameter name="space_input" type="spacekey" /> -->
		</parameters>

</atlassian-plugin>

As you see i make a table with the content from the DB.

My next step is to let the user search for the names of the citys and get out just the selected city´s id, name and population. How can i set dynamic content to a Drop-Down param?

How can i get the names to select in the dropdown menu? 

Is it better to do this with JavaScript or in the Java code? The Problem is i didnt use JS much before, so im completely overwhelmed with this. Didnt anyone made a dropdownlist with dynamic content before?

 

Maybe @Felix Grund (Scandio), @Nic Brough [Adaptavist], @Jamie Echlin [Adaptavist] or @Joe Clark [Atlassian] can help me out.

(If i should not use the mention funktion, please say so.)

 

Thank you in advance and best regards,

J.D.

2 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

1 vote
Answer accepted

0.1 Note: This is not an answers, but i need it to attach content. 


Found these JS´s:

maxcrobrowser.PNG

Those three are the important ones i think:

AJS.MacroBrowser = AJS.MacroBrowser || {};
(function($) {
    var jsOverrides = {}; // todo pending remove this private member. instance approach?
    var loadMacroMetadataPromise;
    function onGoingPreloadRequest() {
        return loadMacroMetadataPromise && loadMacroMetadataPromise.state() === "pending";
    }
    /**
     *
     * @param metadata
     * @param mode
     */
     var fetchMetaDataAndLoadMacro = function(metadata, mode) {
        var options = {
                id: metadata.macroName,
                successCallback: function (data) {
                    if(data && data.details) {
                        data.details = AJS.MacroBrowser.Model.transformMetaDataDefault(data.details);
                    }
                    AJS.MacroBrowser.Editor.loadMacroInBrowser(data.details, mode);
                    fetchMetaDataAndLoadMacro.displayDetails();
                    AJS.MacroBrowser.Preview.previewMacro(data.details);
                },
                errorCallback: function (err) {
                    AJS.trigger("analytics", {name: "macro-browser.fetch-metadata-error"});
                    alert(AJS.I18n.getText("macro.browser.load.error.message"));
                    fetchMetaDataAndLoadMacro.displayDetails();
                }
        };
        if (metadata.alternateId){
            options.alternateId = metadata.alternateId;
        }
        fetchMetaDataAndLoadMacro.setUI(mode, metadata.title);
        AJS.MacroBrowser.Rest.fetchMacroMetadataDetails(options);
    };
    fetchMetaDataAndLoadMacro.setUI = function(mode, title) {
        var placeHolderTitle = mode=="edit" ? t.editTitle : t.insertTitle;
        $("#macro-insert-container").hide();
        AJS.MacroBrowser.UI.updateButtonText(mode);
        AJS.MacroBrowser.UI.enableSaveButton(false);
        AJS.MacroBrowser.dialog.gotoPage(1).addHeader(placeHolderTitle.replace(/\{0\}/, title));
        AJS.MacroBrowser.dialog.show();
        AJS.MacroBrowser.UI.showBrowserSpinner(true);
    };
    fetchMetaDataAndLoadMacro.displayDetails = function() {
        AJS.MacroBrowser.UI.showBrowserSpinner(false);
        AJS.MacroBrowser.UI.enableSaveButton(false);
        $("#macro-insert-container").show();
        AJS.MacroBrowser.UI.focusOnMacroDetailsFirstInput();
    };
    var t = AJS.MacroBrowser;
        // this is absolutely horrible.
        // we should go with instance objects instead of singleton
    t.reset = function () {
        loadMacroMetadataPromise && loadMacroMetadataPromise.resolve && loadMacroMetadataPromise.resolve();
        loadMacroMetadataPromise = null;
        this.initMacroBrowserAfterRequest = null;
        this.initData = null;
        this.hasInit = false;
        this.metadataList = [];
        this.aliasMap = {};
        this.fields = {};
        jsOverrides = {};
        //this.jsOverrides = jsOverrides;
        this.Macros = jsOverrides;
    };
    t.jsOverrides = jsOverrides;
    /**
     * @deprecated Since 3.3. Macros is an ambiguous name, use getMacroJsOverride and setMacroJsOverride.
     */
    t.Macros= jsOverrides;
    t.getMacroJsOverride = function (macroName) {
            return jsOverrides[macroName];
    };
    t.setMacroJsOverride = function (macroName, override) {
            return jsOverrides[macroName] = override;
    };
    t.hasInit = false;
    t.metadataList = [];
    t.aliasMap= {}; // maps each alias to the corresponding macro name
    t.fields= {}; // stores fields for a given macro form.
    /**
     * Checks and returns true if all the required macro parameters have values.
     * It disables the insert/preview buttons if false.
     *
     * @returns {*}
     */
    t.processRequiredParameters = function() {
        return AJS.MacroBrowser.Editor.processRequiredParameters();
    };
    /**
     * Called when a parameter field value changes.
     */
    t.paramChanged = function () {
        // TODO - Could be used to preview?
        AJS.MacroBrowser.Editor.processRequiredParameters();
    };
    // Loads the given macro json in the browser's insert macro page.
    // Exposed to plugins (don't remove)
    t.loadMacroInBrowser = function(metadata, mode) {
        AJS.MacroBrowser.Editor.loadMacroInBrowser (metadata, mode);
    };
    // Constructs the macro markup from the insert macro page
    t.getMacroDefinitionFromForm = function(metadata) {
        AJS.MacroBrowser.Editor.getMacroDefinitionFromForm(metadata);
    };
    /**
     * Returns a Map of all parameter values from the form, including the default parameter value which has a zero
     * length string as a key.
     * @param macroParamDetails meta data about each parameter in the macro
     */
    t.getMacroParametersFromForm = function(macro) {
        AJS.MacroBrowser.Editor.getMacroParametersFromForm(macro);
    };
    // Makes an ajax request to render the macro markup and updates the preview
    // Moved to different namespace. This is just a facade.
    t.previewMacro = function(macro) {
        AJS.MacroBrowser.Preview.previewMacro(macro);
    };
    // This gets called on the preview window's onload to re-adjust the height of the frame
    t.previewOnload = function(body) {
        var selectedMacroName = AJS.MacroBrowser.dialog.activeMetadata.macroName;
        var jsOverride = jsOverrides[selectedMacroName];
        if (jsOverride && jsOverride.postPreview) {
            jsOverride.postPreview(AJS.$("#macro-preview-iframe")[0], AJS.MacroBrowser.dialog.activeMetadata);
        }
        AJS.Editor.disableFrame(body);
        // open all links in a new window
        $(body).click(function(e) {
            if (e.target.tagName.toLowerCase() === "a") {
                var a = e.target;
                var link = $(e.target).attr("href");
                if (link && link.indexOf("#") != 0 && link.indexOf(window.location) == -1) {
                    window.open(link, '_blank').focus();
                }
                return false;
            }
        });
    };
    /**
     * Returns the macro metadata object for a given macro name.
     *
     * Call jsOverride.getMacroDetailsFromSelectedMacro instead of this method for macros such as "gadget" that map
     * multiple macros to a single name.
     *
     * @param macroName macro name to search metadata for
     */
    t.getMacroMetadata = function (macroName) {
        for (var i = 0, len = this.metadataList.length; i < len; i++) {
            var metadata = this.metadataList[i];
            if (metadata.macroName == macroName) {
                return metadata;
            }
        }
        return null;
    };
    /**
     * @since 5.6
     */
    t.getMetadataPromise = function() {
        return loadMacroMetadataPromise;
    };
    /**
     * Called when the user either clicks the Macro Browser button or clicks Edit in a
     * macro placeholder in the RTE.
     *
     * Note that the macro browser is not initialsed/loaded until opened for the first time.
     *
     * @param settings macro browser settings include:
     *      presetMacroMetadata : the metadata for a preset macro to load into the macro browser
     *      selectedHtml : string of selected HTML from RTE when no macro selected
     *      selectedText: the text contents of the selected HTML from the RTE when no macro selected
     *      onComplete : function to call when Macro Browser's "Insert" button is pressed
     *      onCancel : function to call when Macro Browser is closed when incomplete
     *      searchText : text to filter on if opening to the "Select Macro" page, if omitted no filter is done
     *      selectedCategory: the category name that should be selected by default
     */
    t.open = function(settings) {
        if (!settings) {
            settings = {};
            AJS.log("No settings to open the macro browser.");
        }
        var t = AJS.MacroBrowser;
        // if there is a custom editor for this macro, launch that instead
        var macro = settings.selectedMacro;
        if (!macro && settings.presetMacroMetadata) {
            macro = {
                name: settings.presetMacroMetadata.macroName
            };
        }
        if (macro && macro.name){
            var jsOverride = t.getMacroJsOverride(macro.name);
            if (jsOverride && typeof jsOverride.opener == "function"){
                jsOverride.opener(macro);
                return;
            }
        }
        if (!t.hasInit) { // init the macro browser for the first time
            AJS.debug("init macro browser");
            AJS.MacroBrowser.UI.showBrowserSpinner(true);
            if ((t.initData !== null) && $.isEmptyObject(t.initData)) {
                // the only case where we set initData={} is when we got an error on preloading from the rest endpoint
                // try preloading again..
                AJS.trigger("analytics", {name: "macro-browser.init-reattempt"});
                AJS.logError('Macro browser preload failed. Trying again...');
                t.initMacroBrowserAfterRequest = settings;
                t.preLoadMacro();
                return;
            }
            else if (t.initData) { // preloading completed
                t.initBrowser();
            }
            else { // ajax request not returned yet; set a flag to init the browser later
                AJS.trigger("analytics", {name: "macro-browser.init-overlap"});
                AJS.debug('Waiting for macro browser preloading...');
                t.initMacroBrowserAfterRequest = settings;
                return;
            }
        }
        t.openMacroBrowser(settings);
    };
    /**
     * Open the Macro Browser Dialog, either to a specific macro or the selection page depending on
     * the settings parameter.
     * This method must be called after the dialog has been initialised
     *
     * @param {Object} settings.presetMacroName
     * @param {Object} settings.selectedCategory
     */
    t.openMacroBrowser = function(settings) {
        var t = AJS.MacroBrowser;
        t.settings = settings;
        t.selectedMacroDefinition = settings.selectedMacro;
        var selectedMacroName = (t.selectedMacroDefinition && t.selectedMacroDefinition.name) ||
                settings.presetMacroName;
        // Preset macro overrides everything, just use it if present
        if (settings.presetMacroName)
            settings.presetMacroMetadata = t.getMacroMetadata(settings.presetMacroName);
        var metadata = settings.presetMacroMetadata;
        if (!metadata) {
            var selectedMacro = settings.selectedMacro;
            if (selectedMacro) {
                // Editing an existing macro - find metadata for it
                selectedMacroName = selectedMacro.name.toLowerCase();
                selectedMacroName = t.aliasMap[selectedMacroName] || selectedMacroName;
                var jsOverride = jsOverrides[selectedMacroName];
                if (jsOverride) {
                    if (typeof jsOverride.updateSelectedMacro == "function") {
                        jsOverride.updateSelectedMacro(selectedMacro);
                    }
                    // Could be a gadget (or other) macro that has a custom metadata lookup function
                    if (typeof jsOverride.getMacroDetailsFromSelectedMacro == "function") {
                        metadata = jsOverride.getMacroDetailsFromSelectedMacro(t.metadataList, selectedMacro);
                    }
                }
                if (!metadata) {
                    metadata = t.getMacroMetadata(selectedMacroName);
                }
            }
        }
        // todo: get a reference to the back button, or create functions to show/hide the button
        // those functions should go on UI?
        var backButton = $("#macro-browser-dialog").find("button.back");
        if (metadata) {
            AJS.debug("Open macro browser to edit macro: "+ metadata.macroName);
            backButton.hide();
            //todo: should we remove this replicateSelectMacro method and use fetchMetaDataAndLoadMacro?
            t.replicateSelectMacro(metadata, settings.mode || "edit");
        }
        // todo: using selectedMacroName var, which is declared above inside an if??
        else if (selectedMacroName) {
            // the user chose to edit a macro but no metadata was available
            backButton.show();
            // todo:  move to UI namespace??
            t.dialog.overrideLastTab();
            t.dialog.gotoPage(2);
            t.showBrowserDialog();
        } else {
            backButton.show();
            if(settings.selectedCategory) {
                // todo: extract category selection to function
                var categoryIndex = $('#select-macro-page .dialog-page-menu button').index($('#category-button-' + settings.selectedCategory));
                if(categoryIndex < 0) {
                    categoryIndex = 0;
                }
                t.dialog.overrideLastTab();
                t.dialog.gotoPanel(0, categoryIndex);
            }
            else {
                t.dialog.gotoPage(0);
            }
            t.showBrowserDialog();
            // If non-blank searchText has been passed in, filter on it
            t.dialog.searcher.focusAndSearch(settings.searchText);
        }
    };
    t.showBrowserDialog = function() {
        AJS.MacroBrowser.dialog.show();
        AJS.MacroBrowser.UI.showBrowserSpinner(false);
    };
    // Called when dialog is closed by Inserting/Saving.
    t.complete = function (dialog) {
        if (!$("#macro-browser-dialog .dialog-button-panel .ok").is(":visible:not(:disabled)")) {
            // If triggered by enter key but not ready to complete, ignore.
            return;
        }
        var t = AJS.MacroBrowser;
        var metadata = t.dialog.activeMetadata;
        var jsOverride = jsOverrides[metadata.macroName];
        if (jsOverride && jsOverride.manipulateMarkup) {
            jsOverride.manipulateMarkup(metadata);
        }
        var macroDefinition = AJS.MacroBrowser.Editor.getMacroDefinitionFromForm(metadata);
        t.close();
        if (t.settings.onComplete) {
            t.settings.onComplete(macroDefinition);
        }
    };
    /**
     * Called when dialog is closed by various cancel buttons or via Esc key.
     * @returns {boolean}
     */
    t.cancel = function() {
        var t = AJS.MacroBrowser;
        t.close();
        if (typeof t.settings.onCancel == "function") {
            t.settings.onCancel();
        }
        return false;
    };
    t.close = function() {
        var t = this;
        t.unknownParams = {};
        t.fields = {};
        t.dialog.hide();
    };
    /**
     * Replicates the user behaviour of selecting a macro and displaying the insert macro page
     * @param metadata
     * @param mode
     */
    t.replicateSelectMacro = function (metadata, mode) {
        fetchMetaDataAndLoadMacro(metadata, mode);
    };
    /**
     * Loads the categories and macros into the dialog
     * @returns {boolean}
     */
    t.initBrowser = function() {
        var t = AJS.MacroBrowser,
            data = t.initData;
        // 1 . validation
        if (!data.categories || !AJS.MacroBrowser.metadataList.length) {
            AJS.trigger("analytics", {name: "macro-browser.init-browser-error"});
            alert(AJS.I18n.getText("macro.browser.load.error.message"));
            AJS.MacroBrowser.UI.showBrowserSpinner(false);
            return false;
        }
        // 2. Save state
        t.editTitle = data.editTitle;
        t.insertTitle = data.insertTitle;

        // 3. Prepare data
        //--
        // sort the categories and macros
        // Skip the hidden category unless option is set, in which case append it to end of array.
        var hiddenCat;
        data.categories = $.map(data.categories, function (cat) {
            if (cat.name == "hidden-macros") {
                hiddenCat = cat;
                return null;
            }
            return cat;
        });
        data.categories.sort(function(one, two) {
            return (one.displayName.toLowerCase() > two.displayName.toLowerCase() ? 1 : -1);
        });
        if (hiddenCat && AJS.params.showHiddenUserMacros) {
            data.categories.push(hiddenCat);
        }
        //--

        // 4. Build UI
        t.dialog = AJS.MacroBrowser.UI.createDialog ({
            title: data.title,
            categories: data.categories,
            macros : t.metadataList,
            onClickMacroSummary: function(e, metadata) {
                e.preventDefault();
                fetchMetaDataAndLoadMacro(metadata, "insert");
            },
            onSubmit : t.complete,
            onCancel : t.cancel
        });
        t.hasInit = true;
        return true;
    };
    /**
     * Search macro name, title and description for the given text.
     * @param text (required) text to search on
     * @param options options to pass to the AJS.filterBySearch method
     * @return array of macro summaries matching the search text.
     */
    t.searchSummaries = function (text, options) {
        options = $.extend({
            splitRegex: /[\s\-]+/
        }, options);
        return AJS.filterBySearch(this.metadataList, text, options);
    };
    /**
     * Convenience method to return the macro body. This will be one of -
     * - the text in the body textarea on the macro browser dialog
     * - currently selected text in the editor
     * - the current body if editing an existing macro (disregarding any editor selection)
     * - empty String if neither previous case applies.
     */
    t.getMacroBody = function () {
        var t = AJS.MacroBrowser;
        var body = "";
        if ($("#macro-insert-container .macro-body-div textarea").length) {
            body = $("#macro-insert-container .macro-body-div textarea").val();
        } else if (t.selectedMacroDefinition) {
            if (t.selectedMacroDefinition.body) {
                body = t.selectedMacroDefinition.body;
            }
        } else if (t.dialog.activeMetadata) {
            body = t.dialog.activeMetadata.formDetails.body.content; // this is encoded as appropriate for the current macro
        }
        return body;
    };
    /**
     * Checks if a normally-hidden macro should be displayed in the UI or not.
     * @param macro - a macro summary
     */
    t.isHiddenMacroShown = function (macro) {
        return AJS.params.showHiddenUserMacros && macro.pluginKey == "_-user-macro-_";
    };
    /**
     * Returns true if the metadata indicates that there are required parameters for this macro
     */
    t.hasRequiredParameters = function (macroMetadata) {
        return macroMetadata.anyParameterRequired;
    };
    /**
     * Provide a CSV of macroNames to include only these macros. Has to be called before preLoadMacro() runs.
     *
     * E.g. "code, cheese"
     *
     * @param whitelist
     */
    t.setWhitelist = function (whitelist) {
        AJS.MacroBrowser.whitelist = whitelist;
    };
    /**
     * Preloads macro metadata
     * @return promise
     */
    t.preLoadMacro = function () {
        var t = AJS.MacroBrowser;
        t.initData = null; // flag async request started
        if (onGoingPreloadRequest()) {
            return loadMacroMetadataPromise;
        }
        loadMacroMetadataPromise = AJS.MacroBrowser.Rest.loadMacroMetadata({
            // todo: currently you can either have a whitelist or drop the details.  Both is to-be-implemented
            data: t.whitelist ? { whitelist: t.whitelist } : { detailed: false },
            successCallback: function(data) {
                t.initData = data;
                AJS.MacroBrowser.Model.loadMacros(data.macros);
                if (t.initMacroBrowserAfterRequest) { // we have an existing "open browser" command in the queue waiting for the preloading operation to complete
                    t.initBrowser();
                    t.openMacroBrowser(t.initMacroBrowserAfterRequest);
                }
            },
            errorCallback: function(e) {
                AJS.trigger("analytics", {name: "macro-browser.preload-error"});
                AJS.logError("Error requesting macro browser metadata:");
                AJS.logError(e);
                t.initData = {}; // empty initData is used as an error flag in the "open" method
            }
        });
    };
})(AJS.$);
/**
 * Namespace to organize common methods related to the macro editor
 */
AJS.MacroBrowser = AJS.MacroBrowser || {};
AJS.MacroBrowser.Editor = (function ($) {
    function loadMacroInBrowser (metadata, mode) {
        if (!metadata || !metadata.formDetails) {
            AJS.trigger("analytics", {name: "macro-browser.unknown-macro-error"});
            alert(AJS.I18n.getText("macro.browser.unknown.macro.message"));
            return;
        }
        var t = AJS.MacroBrowser,
                detail = metadata.formDetails,
                macroName = detail.macroName,
                jsOverride = t.jsOverrides[macroName],
                selectedMacro = t.settings.selectedMacro,
                selectedMacroElement = tinymce.confluence.macrobrowser.editedMacroDiv;
        if (macroName){
            var jsOverride = t.getMacroJsOverride(macroName);
            if (jsOverride && typeof jsOverride.opener == "function"){
                t.close();
                jsOverride.opener({ name: macroName });
                return;
            }
        }
        $("#save-warning-span").addClass("hidden"); // gadgets may have put it in this state
        // Macro description and documentation link
        $("#macro-insert-container .macro-name").val(macroName);
        var macroDescription = metadata.extendedDescription ? metadata.extendedDescription : metadata.description;
        var macroDesc = $(Confluence.Templates.MacroBrowser.macroDescription({ description: macroDescription })),
            macroParametersForm = $("#macro-insert-container .macro-input-fields form").html(macroDesc);
        if (detail.documentationLink) {
            var doco = $(Confluence.Templates.MacroBrowser.macroDocLink({ href: detail.documentationLink}));
            macroDesc.append(doco);
        } else if (!macroDesc.text()) { // remove the div and its padding style
            macroDesc.remove();
        }
        if (detail.body && detail.body.bodyType != "NONE" && (selectedMacroElement && $(selectedMacroElement).hasClass("editor-inline-macro"))) { // only enable editing of the body in the macro browser for inline body macros
            var pluginKey = metadata.pluginKey;
            if (detail.body.label == AJS.MacroBrowser.Utils.makeDefaultKey(pluginKey, macroName, "body", "label")) {
                detail.body.label = "";
            }
            if (detail.body.description == AJS.MacroBrowser.Utils.makeDefaultKey(pluginKey, macroName, "body", "desc")) {
                detail.body.description = "";
            }
            var body = makeBodyDiv(detail.body, t.selectedMacroDefinition);
            if (body) {
                macroParametersForm.append(body);
            }
        }
        // Parameters may have dependencies so all fields need to be created before values are set.
        $(detail.parameters).each(function() {
            macroParametersForm.append(makeParameterDiv(metadata, this, jsOverride));
        });
        var selectedParams = selectedMacro ? $.extend({}, selectedMacro.params) : {}; // make a copy
        // Fully-implemented macros may have JS overrides defined in a Macro object.
        if (jsOverride && typeof jsOverride.beforeParamsSet == "function") {
            selectedParams = jsOverride.beforeParamsSet(selectedParams, !selectedMacro);
        }
        $(detail.parameters).each(function() {
            var param = this,
                    value;
            if (param.name == "") {
                value = t.selectedMacroDefinition ? t.selectedMacroDefinition.defaultParameterValue : param.defaultValue;
            } else {
                value = selectedParams[param.name];
            }
            if (value != null) {
                delete selectedParams[param.name];
            } else {
                // try looking for aliased parameters
                $(param.aliases).each(function() {
                    if (selectedParams[this]) {
                        value = selectedParams[this];
                        delete selectedParams[this];
                    }
                });
            }
            if (value == null) {
                value = param.defaultValue;
            }
            if (value != null) {
                t.fields[param.name].setValue(value);
            }
        });
        // Any remaining "selectedParameters" are unknown for the current Macro details.
        t.unknownParams = selectedParams;
        // open all links in a new window
        $("a", macroParametersForm).click(function() {
            window.open(this.href, '_blank').focus();
            return false;
        });
        if (!$("#macro-browser-dialog:visible").length) {
            t.showBrowserDialog();
        }
        var macroData = {};
        $.extend(true, macroData, metadata); // clone the metadata to a new object
        // for safety ensure that we have a 'formDetails', containing a body.
        if (!macroData.formDetails) macroData.formDetails = {};
        if (!macroData.formDetails.body) macroData.formDetails.body = {};
        t.dialog.activeMetadata = macroData; // This is important to getMacroBody.
        // do we have have selected text for the macro body or are we editing an existing macro (in which case any selected text is ignored)
        if (t.settings.selectedMacro) {
            macroData.formDetails.body.content = t.settings.selectedMacro.body;
        } else if (macroData.formDetails.body.bodyType && macroData.formDetails.body.bodyType.toLowerCase() == "plain_text") {
            macroData.formDetails.body.content = t.settings.selectedText;
        } else {
            macroData.formDetails.body.content = t.settings.selectedHtml;
        }
    }
    function getMacroParametersFromForm (metadata) {
        return getMacroDefinitionFromForm(metadata).params;
    }
    function getMacroDefinitionFromForm (metadata) {
        var macroName = $("#macro-insert-container").find(".macro-name").val(); // todo: why don't we get this from the metadata?
        var defaultParameterValue,
                t = AJS.MacroBrowser,
                sharedParameters = {};
        var parameters = getMacroParametersFromFormFields(metadata, sharedParameters);
        if (parameters[""])
            defaultParameterValue = parameters[""];
        $.extend(parameters, t.unknownParams); // apply unknown parameters
        parameters = applyjsOverrides(macroName, parameters, metadata, sharedParameters);
        return {
            name : macroName,
            bodyHtml : t.getMacroBody(),
            params : parameters,
            defaultParameterValue: defaultParameterValue
        };
    }
    function processRequiredParameters() {
        var blankRequiredInputs = $("#macro-insert-container .macro-param-div.required .macro-param-input")
            .filter(function() {
                var val = $(this).val();
                return (val == null || val == "");
            });
        var hasAllRequiredData = (blankRequiredInputs.length == 0);
        var disabled = hasAllRequiredData ? "" : "disabled";
        var classFn = disabled ? "addClass" : "removeClass";
        $("#macro-browser-dialog button.ok").prop("disabled", disabled);
        $("#macro-browser-dialog .macro-preview-header .refresh-link").prop("disabled", disabled)[classFn]("disabled");
        return hasAllRequiredData;
    }

    // private functions
    /**
     * Apply jsOverrides for a macroName
     *
     * @param macroName
     * @param parameters
     * @param macro
     * @param sharedParameters
     * @returns {*} parameters
     */
    function applyjsOverrides(macroName, parameters, macro, sharedParameters) {
        var jsOverride = AJS.MacroBrowser.getMacroJsOverride(macroName);
        if (jsOverride && typeof jsOverride.beforeParamsRetrieved == "function") {
            parameters = jsOverride.beforeParamsRetrieved(parameters, macro, sharedParameters);
        }
        return parameters;
    }
    /**
     * Get value from the input element according to input type (input text, checkbox, etc)
     * @param $element jQuery input element
     * @returns {*}
     */
    function extractValueFromInputElement($element) {
        var paramVal = $element.val();
        if ($element.attr("type") == "checkbox") {
            paramVal = "" + $element.prop("checked"); //will return 'true' if checked property is not empty
        }
        return paramVal;
    }
    /**
     * Fill parameters and shared parameters according to form values
     * @param metadata
     * @param sharedParameters
     * @returns {{}}
     */
    function getMacroParametersFromFormFields(metadata, sharedParameters) {
        var parameters = {};
        for (var i = 0, l = metadata.formDetails.parameters.length; i < l; i++) {
            var parameter = metadata.formDetails.parameters[i];
            var paramVal = extractValueFromInputElement($("#macro-param-" + parameter.name));
            if (paramVal) {
                // the shared property is used by gadgets in jsOverrides
                if (parameter.shared) {
                    sharedParameters[parameter.name] = paramVal;
                }
                if (parameter.hidden ||
                        (!parameter.defaultValue || parameter.defaultValue != paramVal)) {
                    // only add the parameter value if its not the default
                    parameters[parameter.name] = paramVal;
                }
            }
        }
        return parameters;
    }
    /**
     * Creates a div for a macro body.
     *
     * @param macroBodyFormComponent
     * @param macroDefinition
     * @returns {*|jQuery|HTMLElement}
     */
    function makeBodyDiv (macroBodyFormComponent, macroDefinition) {
        var t = AJS.MacroBrowser,
            bodyDiv = $(Confluence.Templates.MacroBrowser.macroBody()),
            bodyTextareaValue;
        if (macroDefinition) { // we are editing an existing macro
            bodyTextareaValue = macroDefinition.body;
        } else { // check if there is selected text in the editor
            bodyTextareaValue = t.settings.selectedText;
        }
        $("textarea", bodyDiv).val(bodyTextareaValue || "");
        if (macroBodyFormComponent.label) {
            $("label", bodyDiv).text(macroBodyFormComponent.label);
        }
        if (macroBodyFormComponent.description) {
            bodyDiv.append(Confluence.Templates.MacroBrowser.macroParameterDesc({ description: macroBodyFormComponent.description }));
        }
        if(macroBodyFormComponent.hidden) {
            bodyDiv.hide();
        }
        return bodyDiv;
    }
    /**
     * Creates a div for a single macro parameter.
     *
     * @param metadata
     * @param param
     * @param jsOverride
     * @returns {*}
     */
    function makeParameterDiv (metadata, param, jsOverride) {
        var t = AJS.MacroBrowser, field;
        var type = param.type.name;
        // Plugin point - other JS files can define more specific field-builders based on macro name, param name and
        // type.
        if (jsOverride) {
            var builder = jsOverride.fields && jsOverride.fields[type];
            if (builder && typeof builder != "function") {
                // Types can be overridden for specific parameters - so the "type" object contains a "name" function.
                builder = builder[param.name];
            }
            if (typeof builder == "function") {
                field = builder.call(jsOverride, param);
            }
        }
        // If no override specific to the macro, look for general overrides specific to the parameter type.
        if (!field) {
            if (!(type in t.ParameterFields && typeof t.ParameterFields[type] == "function")) {
                type = "string";
            }
            field = t.ParameterFields[type](param);
        }
        t.fields[param.name] = field;
        var paramDiv = field.paramDiv;
        var input = field.input;
        var paramId = "macro-param-" + param.name;
        paramDiv.attr("id", "macro-param-div-" + param.name);
        input.addClass("macro-param-input").attr("id", paramId);
        if (param.hidden) {
            paramDiv.hide();
        }
        // Use param label and desc or correct fallback.
        var pluginKey = metadata.pluginKey;
        if (param.displayName == AJS.MacroBrowser.Utils.makeDefaultKey(pluginKey, metadata.macroName, "param", param.name, "label")) {
            param.displayName = param.name;
        }
        if (param.description == AJS.MacroBrowser.Utils.makeDefaultKey(pluginKey, metadata.macroName, "param", param.name, "desc")) {
            param.description = "";
        }
        var labelText = param.displayName;
        if (param.required) {
            labelText += " *";
            paramDiv.addClass("required");  // set class against div, not input, to allow styling of label if nec
        }
        $("label", paramDiv).attr("for", paramId).text(labelText);
        if (param.description) {
            paramDiv.append(Confluence.Templates.MacroBrowser.macroParameterDesc({ description: param.description }));
        }
        return paramDiv;
    }
    return {
        /**
         * Loads the given macro json in the browser's insert macro page.
         *
         * @param metadata
         * @param mode "insert" or "edit"
         */
        loadMacroInBrowser: loadMacroInBrowser,
        /**
         * Returns a Map of all parameter values from the form, including the default parameter value which has a zero
         * length string as a key.
         * @param metadata meta data about each parameter in the macro
         */
        getMacroParametersFromForm: getMacroParametersFromForm,
        /**
         * Constructs the macro markup from the insert macro page
         *
         * @param {Object} metadata detailed metadata about the macro.  Includes form details etc.
         * @returns {{name: (*|jQuery), bodyHtml: *, params: {}, defaultParameterValue: *}}
         */
        getMacroDefinitionFromForm: getMacroDefinitionFromForm,
        /**
         * Checks and returns true if all the required macro parameters have values.
         * It disables the insert/preview buttons if false.
         *
         * @returns {boolean}
         */
        processRequiredParameters: processRequiredParameters
    };
}(AJS.$));
/**
 * Returns an object wrapper for a parameter-div jQuery object and the input in
 * that div that stores the internal parameter value (as opposed to the display
 * field, although they may be the same).
 */
AJS.MacroBrowser.Field = function (paramDiv, input, options) {
    options = options || {};
    var setValue = options.setValue || function (value) {
        input.val(value);
    };
    var getValue = options.getValue || function () {
        return input.val();
    };
    
    input.change(options.onchange || AJS.MacroBrowser.paramChanged);
    return {
        paramDiv : paramDiv,
        input : input,
        setValue : setValue,
        getValue : getValue
    };
};
/**
 * ParameterFields defines default "type" logic for fields in the Macro
 * Browser's Insert/Edit Macro form.
 * 
 * Each method in this object corresponds to a parameter type as defined in the
 * MacroParameterType enum.
 */
AJS.MacroBrowser.ParameterFields = (function ($) { 
   /**
     * Update the dependencies of the identified parameter with the supplied value.
     */
    var updateDependencies = function (paramName, dependencies, value) {
        if (dependencies && dependencies.length) {
            for ( var i = 0, length = dependencies.length; i < length; i++) {
                AJS.MacroBrowser.fields[dependencies[i]] && AJS.MacroBrowser.fields[dependencies[i]].dependencyUpdated(paramName, value);
            }
        }
    };
    return {
        "updateDependencies" : updateDependencies,
    	
        "username" : function(param, options) {
            options = options || {};
            var className = param.multiple ? "autocomplete-multiuser" : "autocomplete-user";
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameter());
            var input = AJS.$("input[type='text']", paramDiv);
            input.addClass(className).attr("data-none-message", AJS.I18n.getText("macro.browser.smartfields.not.found"));
            // CONF-16859 - check if mandatory params are now filled
            if (param.required) {
                input.keyup(AJS.MacroBrowser.processRequiredParameters);
            }
            if (param.multiple) {
                Confluence.Binder.autocompleteMultiUser(paramDiv);
                options.setValue = function (value) {
                    input.val(value);
                    var values = value.split(','),
                        requests = [],
                        users = [];
                    // unfortunately there is no rest api to get me a list of users, however since its not a common case
                    // to edit macros with multiple users, going to call the existing api for each user
                    for (var i=0,l=values.length; i<l; i++) {
                        var request = function(username) {
                            return $.getJSON(Confluence.getContextPath() + "/rest/prototype/1/user/non-system/" + username)
                                .done(function(user){
                                    if (user && user.name) {
                                        users.push({id: user.name, text: user.displayName, imgSrc: user.avatarUrl});
                                    }
                                }).fail(function(response) {
                                    AJS.logError("Cannot parse user data for macro browser field with: " + response);
                                    users.push({id: username, text: AJS.I18n.getText("unknown.name",username), imgSrc: Confluence.getContextPath() + "/images/icons/profilepics/default.png"})
                                });
                        };
                        requests.push(request(values[i]));
                    }
                    // wait for all requests to finish, whether they passed/failed and then populate the field value
                    $.when.apply($, _.map(requests, function (aRequest) {
                        var monitor = $.Deferred();
                        aRequest.always(function () {
                            monitor.resolve();
                        });
                        return monitor.promise();
                    })).done(function () {
                        if (users.length) {
                            input.auiSelect2('data', users);
                        }
                    });
                };
            }
            else {
                input.bind("selected.autocomplete-content", function(e, data) {
                    if (options.onselect) {
                        options.onselect(data.selection);
                    }
                    else if(options.setValue) {
                        options.setValue(data.content.username);
                    }
                    else {
                        updateDependencies(param.name, options.dependencies, input.val());
                        (typeof options.onchange == "function") && options.onchange.apply(input);
                    }
                });
                AJS.Confluence.Binder.autocompleteUserOrGroup(paramDiv);
            }
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        },
        "spacekey" : function(param, options) {
            // for multple space keys just use a String field at the moment
            if (param.multiple) {
                return AJS.MacroBrowser.ParameterFields["string"](param, options);
            }
            options = options || {};
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameter());
            var input = AJS.$("input[type='text']", paramDiv);
            input.addClass("autocomplete-space")
                 .attr("data-template", "{key}")
                 .attr("data-none-message", AJS.I18n.getText("macro.browser.smartfields.not.found"));
            // CONF-16859 - check if mandatory params are now filled
            if (param.required) {
                input.keyup(AJS.MacroBrowser.processRequiredParameters);
            }
            input.bind("selected.autocomplete-content", function(e, data) {
              if (options.onselect) {
                  options.onselect(data.selection);
              }
              else if(options.setValue) {
                  options.setValue(data.content.key);
              }
              else {
                  updateDependencies(param.name, options.dependencies, input.val());
                  (typeof options.onchange == "function") && options.onchange.apply(input);
              }
            });
            AJS.Confluence.Binder.autocompleteSpace(paramDiv);
            return AJS.MacroBrowser.Field(paramDiv, input);
        },
        "attachment" : function (param, options) {
            if (param.multiple) {
                return AJS.MacroBrowser.ParameterFields["string"](param,
                        options);
            }
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameterSelect());
            var input = AJS.$("select", paramDiv);
            options = options || {};
            options.setValue = options.setValue || function(value) {
                // check if the value being set is in the list of options
                // if not then add it as a new option - with an indication that
                // it is not a valid choice for this select box
                var foundOption = false;
                //Don't use a JQuery filter of "[value=" +value+"]" since value is un-escaped user-data
                input.find("option").each(function() {
                    if (this.value == value) {
                        foundOption = true;
                        return false;
                    }
                });
                if (!foundOption) {
                    input.append(AJS.$("<option/>").attr("value", value).text(value + " (" + AJS.I18n.getText("macro.browser.smartfields.not.found") + ")"));
                    input.tempValue = value;
                } else {
                    delete input.tempValue;
                }
                
                // CONF-15415 : Spurious error thrown in IE6
                try {
                    input.val(value);
                } catch (err) {
                    AJS.logError(err);
                }
                input.change();
            };
            var field = AJS.MacroBrowser.Field(paramDiv, input, options);
            field.updateDependencies = updateDependencies;
            field.getData = function(req) {
            	if (!((req.title && req.spaceKey) || req.pageId || req.draftId)) {
            		AJS.log("Not enough parameters to send attachmentsearch request");
                    return;	// not enough content info to get attachments
            	}
                var currentValue = input.tempValue || input.val();
                if (options.fileTypes) {
                    req.fileTypes = options.fileTypes;
                }
                
                var url = AJS.params.contextPath + (req.draftId ? "/json/draftattachmentsearch.action" : "/json/attachmentsearch.action");
                $.getJSON(url, req, function(data) {
                    if (data.error) {
                        return;
                    }
                    $("option", input).remove();
                    var attachments = data.attachments;
                    // if there are no attachments on the page then populate the options with
                    // a message stating this
                    if (!attachments || !attachments.length) {
                        // AJS.log("attachment - No attachments so creating message. tempValue = " + input.tempValue);
                        input.append(AJS.$("<option/>").attr("value", "").html(AJS.I18n.getText("macro.browser.smartfields.no.attachments")));
                        if (input.tempValue) {
                            options.setValue(input.tempValue);
                        }
                    } else {
                        for (var i = 0, length = attachments.length; i < length; i++) {
                            input.append(AJS.$("<option/>").attr("value", attachments[i].name).text(attachments[i].name));
                        }
                        currentValue = currentValue || input.tempValue;
                        options.setValue(currentValue || attachments[0].name);
                    }
                    //in IE9 only the first character of the selected option is shown, force a redraw
                    input.attr("style", "");
                });
            };
            return field;
        },
        "confluence-content" : function (param, options) {
    
            // If multiple confluence-content field then only return a String at the moment
            if (param.multiple) {
                return AJS.MacroBrowser.ParameterFields["string"](param, options);
            }
            options = options || {};
            param.options = param.options || {};
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameter()),
                input = AJS.$("input[type='text']", paramDiv)
                        .attr("data-none-message", AJS.I18n.getText("macro.browser.smartfields.not.found"))
                        .attr("data-template", ""); // no template as some logic is required to build the value
            // CONF-16859 - check if mandatory params are filled on keypresses in this field.
            if (param.required) {
                input.keyup(AJS.MacroBrowser.processRequiredParameters);
            }
            // CONF-15438 - update any dependencies of the field when it is changed
            options.onchange = options.onchange || function (e) {
                var val = input.val();
                updateDependencies(param.name, options.dependencies, val);
            };
            options.setValue = options.setValue || function (value) {
                input.val(value);
                (typeof options.onchange == "function") && options.onchange.apply(input);
            };
            
            input.bind("selected.autocomplete-content", function(e, data) {
                var datePathPrefix = "";
                if (param.options.includeDatePath == "true" && data.content.type == "blogpost") {
                    var splitDate = data.content.createdDate.date.split("-");
                    datePathPrefix = "/" + splitDate[0] + "/" + splitDate[1]  + "/" + splitDate[2].substring(0, 2) + "/";
                }
                var spaceKey = data.content.space && data.content.space.key;
                var isSpaceKeyNeeded = (spaceKey && spaceKey != AJS.Meta.get('space-key'));
                if (data.content.title.indexOf(":") != -1) {
                    isSpaceKeyNeeded = true;
                }
                var markup = (isSpaceKeyNeeded ? (spaceKey + ":") : "") + datePathPrefix + data.content.title;
                input.val(markup);
                if (options.onselect) {
                  options.onselect(data.selection);
                }
                else {
                  options.setValue(markup, input);
                }
            });
            if (param.options.spaceKey) {
                if (param.options.spaceKey.toLowerCase() == "@self") {
                    param.options.spaceKey = AJS.Meta.get('space-key');
                }
                input.attr("data-spacekey", param.options.spaceKey);
            }
            var type = param.options.type;
            if (typeof type == "string") {
                if(type == "page") {
                    input.addClass("autocomplete-page");
                    AJS.Confluence.Binder.autocompletePage(paramDiv);
                }
                else if (type == "blogpost") {
                    input.addClass("autocomplete-blogpost");
                    AJS.Confluence.Binder.autocompleteBlogpost(paramDiv);
                }
                else if (type == "attachment") {
                    input.addClass("autocomplete-attachment");
                    AJS.Confluence.Binder.autocompleteAttachment(paramDiv);
                }
            }
            else { // default to pages and blogs
                input.addClass("autocomplete-confluence-content");
                AJS.Confluence.Binder.autocompleteConfluenceContent(paramDiv);
            }
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        },
    
        /**
         * Default field for all unknown types.
         */
        "string" : function (param, options) {
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameter());
            var input = $("input", paramDiv);
            if (param.required) {
                input.keyup(AJS.MacroBrowser.processRequiredParameters);
            }
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        },
        /**
         * A checkbox - assumes not true means false, not null.
         */
        "boolean" : function (param, options) {
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameterBoolean());
            var input = $("input", paramDiv);
            options = options || {};
            options.setValue = options.setValue || function (value) {
                if (/true/i.test(value) ||
                    (/true/i.test(param.defaultValue) && !(/false/i).test(value))) {
                    input.prop("checked", true);
                }
            };
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        },
        "enum" : function (param, options) {
            if (param.multiple) {
                return AJS.MacroBrowser.ParameterFields["string"](param, options);
            }
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameterSelect());
            var input = $("select", paramDiv);
            if (!(param.required || param.defaultValue)) {
                input.append(AJS.$("<option/>").attr("value", ""));
            }
            $(param.enumValues).each(function() {
                input.append(AJS.$("<option/>").attr("value", this).html("" + this));
            });
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        },
        /**
         * Like a "string" field but hidden.
         */
        "_hidden" : function (param, options) {
            var paramDiv = $(Confluence.Templates.MacroBrowser.macroParameterHidden()).hide();
            var input = $("input", paramDiv);
            return AJS.MacroBrowser.Field(paramDiv, input, options);
        }
    
    };
})(AJS.$);

Hi JD,

if you take a look into the documentation, there is a JS-Approach descirbed for hidden parameters. But this might work for enums too.

Regards

Steve

Thanks for that, are there any docs for the JavaScript stuff? Methods etc Thanks

Mh okay currently i have this from the tut: AJS.MacroBrowser.getMacroJsOvveride("my-macro").fields.enum = { "select" : function(param) { var parameterField = AJS.MacroBrowser.ParameterFields["select"] (param, {}); if (!parameterField.getValue()) { parameterField.setValue('hidden field value'); } return parameterField; } }; How do i know what ParameterFields is and what to enter?

Can you explain this code to me?

Take a look in the source-code : confluence-project/confluence-plugins/confluence-editor-plugins/confluence-macro-browser/src/main/resources/js/ There should be all the specific js-functions with an explanation. Regards Steve

Okay thanks, where do i find it when i use the sdk?

You need a valid license, then you can download it via http://my.atlassian.com

Ty, posted 3 of the js as an "answer".

The Problem is i didnt use JS much before, so im completely overwhelmed with this. Didnt anyone made a dropdownlist with dynamic content before?

Community showcase
Posted in Jira Software

Metrics Fun: 2019 in Review

Hello, Atlassian Community!  I thought it would be fun to do something different for my teams' last retrospective of 2019 so I'm planning to do a "year in review" with info-graphics.  Wha...

219 views 4 3
Join discussion

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you