Commits

Don Brown committed bdfcfc6

Initial commit

Comments (0)

Files changed (9)

+target
+.*.iml
+.*.ipr
+.*.iws
+.*~
+To avoid future confusion, we recommend that you include a license with your plugin.
+This file is simply a reminder.
+
+For a template license you can have a look at: http://www.opensource.org/licenses/
+
+Atlassian releases most of its modules under a BSD license: http://www.opensource.org/licenses/bsd-license.php
+You have successfully created a plugin using the Confluence plugin archetype!
+
+Here are the SDK commands you'll use immediately:
+
+* atlas-run   -- installs this plugin into Confluence and starts it on http://localhost:1990/confluence
+* atlas-debug -- same as atlas-run, but allows a debugger to attach at port 5005
+* atlas-cli   -- after atlas-run or atlas-debug, opens a Maven command line window:
+                 - 'pi' reinstalls the plugin into the running Confluence instance
+* atlas-help  -- prints description for all commands in the SDK
+
+Full documentation is always available at:
+
+http://confluence.atlassian.com/display/DEVNET/Developing+your+Plugin+using+the+Atlassian+Plugin+SDK
+<?xml version="1.0" encoding="UTF-8"?>
+
+<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>
+    <groupId>com.atlassian.labs</groupId>
+    <artifactId>confluence-annotate-plugin</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <organization>
+        <name>Example Company</name>
+        <url>http://www.example.com/</url>
+    </organization>
+
+    <name>confluence-annotate-plugin</name>
+    <description>This is the com.atlassian.labs:confluence-annotate-plugin plugin for Atlassian Confluence.</description>
+    <packaging>atlassian-plugin</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.6</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.atlassian.confluence</groupId>
+            <artifactId>confluence</artifactId>
+            <version>${confluence.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.atlassian.confluence.plugin</groupId>
+            <artifactId>func-test</artifactId>
+            <version>2.3-beta1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.jwebunit</groupId>
+            <artifactId>jwebunit-htmlunit-plugin</artifactId>
+            <version>2.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.nekohtml</groupId>
+            <artifactId>nekohtml</artifactId>
+            <version>1.9.12</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.atlassian.maven.plugins</groupId>
+                <artifactId>maven-confluence-plugin</artifactId>
+                <version>3.3-m7</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <productVersion>${confluence.version}</productVersion>
+                    <productDataVersion>${confluence.data.version}</productDataVersion>
+                    <pluginArtifacts>
+                        <pluginArtifact>
+                            <groupId>com.atlassian.labs</groupId>
+                            <artifactId>speakeasy-plugin</artifactId>
+                            <version>1.0-SNAPSHOT</version>
+                        </pluginArtifact>
+                    </pluginArtifacts>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <properties>
+        <confluence.version>3.4</confluence.version>
+        <confluence.data.version>3.1</confluence.data.version>
+    </properties>
+
+</project>

src/main/resources/atlassian-plugin.xml

+<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}" />
+    </plugin-info>
+
+    <scoped-web-resource key="annotate">
+        <resource type="download" name="annotate.js" location="js/annotate.js" />
+        <context>page</context>
+        <context>blogpost</context>
+    </scoped-web-resource>
+</atlassian-plugin>

src/main/resources/js/annotate.js

+
+(function() {
+
+    var MAGIC_DELIMITOR = "pw3sx"
+    function submitComment(selection) {
+        var pageId = jQuery('#pageId').val();
+        var contextPath = jQuery('#contextPath').val();
+        var token = jQuery('meta[name=atlassian-token]').attr('content');
+        jQuery.ajax({
+            type: 'post',
+            url: contextPath + '/pages/doaddcomment.action?pageId=' + pageId,
+            data: {
+                'content' : selection,
+                'atl_token' : token
+            },
+            success: function(response)
+            {
+                alert('comment added');
+            }
+        });
+    }
+
+    /* attempt to find a text selection */
+    function getSelected() {
+        if(window.getSelection) { return window.getSelection(); }
+        else if(document.getSelection) { return document.getSelection(); }
+        else {
+            var selection = document.selection && document.selection.createRange();
+            if(selection.text) { return selection.text; }
+            return false;
+        }
+    }
+
+    function handleSelection(selection) {
+        var dialog = new AJS.Dialog({width:470, height:400});
+        dialog.addHeader("Inline Comment");
+        dialog.addPanel("Inline Comment",
+                '<blockquote>' + selection + '</blockquote>' +
+                '<textarea id="inlineComment" rows="10" cols="50"></textarea>',
+                "panel-body");
+        var parsed = selection.split(' ');
+        var signature = MAGIC_DELIMITOR + parsed[0] + MAGIC_DELIMITOR + (parsed.length - 2) + MAGIC_DELIMITOR +  parsed[parsed.length-1];
+        dialog.addButton("Save", function (dialog) {
+            submitComment("{quote}" + selection + "{quote}\n" + jQuery('#inlineComment').val() + " {anchor:" + signature + "}");
+            dialog.hide();
+        });
+        dialog.addButton("Cancel", function (dialog) {
+            dialog.hide();
+        });
+
+        dialog.show();
+
+
+    }
+
+    function insertAfter( referenceNode, newNode )
+    {
+        referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling );
+    }
+
+
+
+    function scanComments() {
+        var links = {};
+        var counter = 0;
+        jQuery('a', '#comments-section').each(function() {
+            var name = jQuery(this).attr('name');
+            var matches = /.*pw3sx(.*)pw3sx(-?\d+)pw3sx(.*)/.exec(name);
+            if (matches) {
+                jQuery(this).attr('data-inlineid', counter);
+                var commentDiv = jQuery(this).closest('.comment');
+                var commentId = commentDiv.attr('id');
+                commentId = commentId.substring(commentId.indexOf('-') + 1);
+                var userId = jQuery('.userLogoLink', commentDiv).attr("data-username");
+
+
+                var comment = {
+                    comment : jQuery(this).parent().text(),
+                    user : userId,
+                    id : commentId
+                };
+                var existing = links[matches[0]];
+                if (existing) {
+                    existing.comments.push(comment);
+                } else {
+
+                    links[matches[0]] = {
+                        firstWord  : matches[1],
+                        numWordsInMiddle : parseInt(matches[2]),
+                        lastWord : matches[3],
+                        index : counter++,
+                        comments : [comment]
+                    };
+                }
+                jQuery(this).attr('href', '#inline-id-' + links[matches[0]].index);
+                jQuery(this).append('<img src="' + contextPath + '/images/icons/up_16.gif" />');
+            }
+        });
+
+        forEachTextNode('div.wiki-content', function(textNode) {
+            var text = textNode.nodeValue;
+            var matched = [];
+            jQuery.each(links, function(matchText, match) {
+                var firstWordPos = text.indexOf(this.firstWord);
+                if (firstWordPos > -1) {
+                    var lastWordPos = text.indexOf(this.lastWord, firstWordPos);
+                    if (lastWordPos > -1) {
+                        var endPos = lastWordPos + this.lastWord.length;
+                        var words = text.substring(firstWordPos, endPos).split(' ');
+                        if (words.length - 2 == this.numWordsInMiddle) {
+                            matched.push(matchText);
+                            textNode.nodeValue = text.substring(0, firstWordPos);
+                            jQuery(textNode).after(
+                                    '<a name="inline-id-' + this.index + '">' +
+                                    '<span id="inline-text-' + this.index + '">' +
+                                    text.substring(firstWordPos, endPos) +
+                                    '</span>' +
+                                    '<sub id="inline-sub-' + this.index + '">' + this.comments.length + '</sub></a> ' + text.substring(endPos));
+                            AJS.InlineDialog(jQuery('#inline-sub-' + this.index), 1, function(contents, trigger, showPopup) {
+                                contents.empty();
+                                jQuery.each(match.comments, function() {
+                                    contents.append('<p>' + this.user  + ': ' + this.comment + ' <a href="#comment-' + this.id + '">' +
+                                            ' <img src="' + contextPath + '/images/icons/down_16.gif" /></a></p>');
+                                });
+                                showPopup();
+                            });
+
+
+                        }
+                    }
+                }
+            });
+            jQuery.each(matched, function() {
+                delete links[this];
+            });
+        });
+    }
+
+    function forEachTextNode(context, callback) {
+        jQuery('*', context)
+                .andSelf()
+                .contents()
+                .filter(function(){
+                    return this.nodeType === 3;
+                })
+                .filter(function(){
+                    return this.nodeValue != null && this.nodeValue.length > 0;
+                })
+                .each(function() {
+                    callback(this)
+                });
+    }
+
+
+    jQuery(document).ready(function() {
+//        jQuery('#main').mouseup(function() {
+//            var selection = getSelected();
+//            if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
+//                handleSelection(selection);
+//            }
+//        });
+        scanComments();
+        AJS.whenIType('shift+c').execute(function() {
+            var selection = getSelected();
+            if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
+                handleSelection(selection);
+            }
+        });
+
+    });
+})();

src/test/java/com/atlassian/labs/annotate/ExampleMacroTest.java

+package com.atlassian.labs.annotate;
+
+import org.junit.Test;
+
+/**
+ * Testing {@link com.atlassian.labs.annotate.ExampleMacro}
+ */
+public class ExampleMacroTest
+{
+    @Test
+    public void basic()
+    {
+        // add test here...
+    }
+}

src/test/java/it/AbstractIntegrationTestCase.java

+package it;
+
+import com.atlassian.confluence.plugin.functest.AbstractConfluencePluginWebTestCase;
+import com.atlassian.confluence.plugin.functest.JWebUnitConfluenceWebTester;
+import com.atlassian.confluence.plugin.functest.TesterConfiguration;
+import junit.framework.Assert;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public class AbstractIntegrationTestCase extends AbstractConfluencePluginWebTestCase
+{
+    @Override
+    protected JWebUnitConfluenceWebTester createConfluenceWebTester()
+    {
+        Properties props = new Properties();
+        props.put("confluence.webapp.protocol", "http");
+        props.put("confluence.webapp.host", "localhost");
+
+        // this is deceiving: the func test library checks for the system properties
+        // *before* checking in this properties file for these values, so these
+        // properties are technically ignored
+        props.put("confluence.webapp.port", Integer.parseInt(System.getProperty("http.port")));
+        props.put("confluence.webapp.context.path", System.getProperty("context.path"));
+
+        props.put("confluence.auth.admin.username", "admin");
+        props.put("confluence.auth.admin.password", "admin");
+
+        TesterConfiguration conf;
+        try
+        {
+            conf = new TesterConfiguration(props);
+        }
+        catch (IOException ioe)
+        {
+            Assert.fail("Unable to create tester: " + ioe.getMessage());
+            return null;
+        }
+
+        JWebUnitConfluenceWebTester tester = new JWebUnitConfluenceWebTester(conf);
+
+        tester.getTestContext().setBaseUrl(tester.getBaseUrl());
+        tester.setScriptingEnabled(false);
+
+        return tester;
+    }
+}

src/test/java/it/IntegrationTestMyPlugin.java

+package it;
+
+public class IntegrationTestMyPlugin extends AbstractIntegrationTestCase
+{
+	public void testSomething()
+	{
+        gotoPage("");
+        assertTextPresent("Welcome");
+	}
+}