Remixing Confluence with Speakeasy - AtlasCamp 2011

1,038 views

Published on

The new Confluence is awesome, but how about making it even better? Speakeasy democratises development by allowing you to quickly implement new features, even if you're not a Javascript whiz. In this talk, we'll provide you with paradigms for your Confluence Speakeasy extensions by showing you some useful ways of extracting information and remixing existing content on a page. You'll also get to see some of the useful, sometimes amusing, extensions that Atlassians have developed for our internal instances of Confluence.

Nabeelah Ali, Confluence Developer

Published in: Technology
  • Be the first to comment

Remixing Confluence with Speakeasy - AtlasCamp 2011

  1. 1. Remixing Confluence withSpeakeasyNabeelah AliAtlassian 2
  2. 2. Show of handsWritten a Confluence plugin? 3
  3. 3. Show of handsComfortable with Javascript? 4
  4. 4. Show of handsEnjoy memes? 5
  5. 5. About meNabeelah AliConfluence developer on 4.0 frontend features 6
  6. 6. Confluence 4• new features• diverse users 7
  7. 7. “ Be the change you seek. ” Atlassian value 8
  8. 8. 9
  9. 9. In case you were wondering• ragefaces is really an extension BEFORE AFTER 10
  10. 10. I can haz plugin?an atlassian-plugin.xml<atlassian-plugin name="Ragefaces resource" key="example.plugin.ragefaces" plugins-version="2"> <plugin-info> <description>A plugin to turn your [/awyeah]s into images</description> <vendor name="Meme Corporation" url="http://www.memecorp.us"/> <version>1.0</version> </plugin-info> <web-resource name="Resources" key="resources"> <resource name="foo.js" type="download" location="resources/foo.js"/> <context>atl.general</context> </web-resource></atlassian-plugin> 11
  11. 11. Creating a Confluence plugin 12
  12. 12. Creating a Confluence plugin 13
  13. 13. Creating a Confluence plugin run -> debug -> run 14
  14. 14. Creating a Confluence plugin run -> debug -> run 15
  15. 15. Creating a Confluence plugin run -> debug -> run 16
  16. 16. Creating a Confluence plugin run -> debug -> run 17
  17. 17. What you will hear today• Speakeasy 101• Let’s Build an Extension• Cautionary Advice• Resources 18
  18. 18. Speakeasy
  19. 19. Speakeasy: the what• cross-product plugin• run client-side Javascript, CSS & HTML 20
  20. 20. demonstration of Speakeasy for the end user
  21. 21. creating an extension skeleton 22
  22. 22. [demonstration of using the wizard to create an extension]
  23. 23. for plugin developers super fast prototyping 24
  24. 24. for confluence admins try out crazy stuff on production data 25
  25. 25. for confluence admins user-driven development 26
  26. 26. for confluence admins democratise development 27
  27. 27. Speakeasy: got Confluence?Atlassian Plugin SDK --atlas-run-standalone --product confluence --version 4.0 28
  28. 28. demonstration of installing the speakeasy plugin
  29. 29. liking 30
  30. 30. 31
  31. 31. pimping 32
  32. 32. 33
  33. 33. styling 34
  34. 34. 35
  35. 35. Let’s build an extension!
  36. 36. demonstration of plugin to build
  37. 37. Let’s build this thing1. Include the image2. Restrict the context3. Find/replace4. Twitter request5. Put it in a dialog 38
  38. 38. Include the imagevar img = require(speakeasy/resources).getImageUrl(module, bird.png); 39
  39. 39. restrict the context 40
  40. 40. Let’s do this all onready$(document).ready(function() { // we’ll put our code here} 41
  41. 41. Restrict the context if (!!AJS.Meta.get("page-id") && !AJS.Meta.get("editor-mode")) { // do our stuff } 42
  42. 42. grab the content 43
  43. 43. atlassian atlassianConfluence pagesviewing a page/blog editing a page/blog dashboardbreadcrumbs breadcrumbs breadcrumbs title title Welcome to Confluence Updates content content Spaces SAVE atlassian atlassian 44
  44. 44. Find & replace  var content = AJS.$("#main-content");  var twitterfiedContent = content.html().replace(/(^|s)#(w+)/g, " $1#<a href="http://search.twitter.com/search?q=%23$2">$2</a> <img src="+ img + " class=twittericon hashtag=$2/>");  content.html(twitterfiedContent); 45
  45. 45. All our hashtags are linked• Body Level One• Body Level One • Body Level Two • Body Level Two• Body Level One • Body Level Two 46
  46. 46. Atlassian User Interface (AUI)• a reusable set of UI components 47
  47. 47. Put it in a dialogAJS.$(".twittericon").each(function (i) { AJS.InlineDialog($(this), 1, function(content, trigger, showPopup) { // Let’s get some information to put in this inline dialog.   },  {onHover:true});} 48
  48. 48. Twitter request      $.getJSON("http://search.twitter.com/search.json?callback=?", { q: "#" + $(this).attr(hashtag), rpp: "5", lang: "en" }, function(data) {    $.each(data.results, function() {    // Put each result’s twitter handle, tweet text and user //profile photo in nice divs and style.               }); });    49
  49. 49. Twitter request      $.getJSON("http://search.twitter.com/search.json?callback=?", { q: "#" + $(this).attr(hashtag), rpp: "5", lang: "en" }, function(data) {    $.each(data.results, function() {    // Put each result’s twitter handle, tweet text and user //profile photo in nice divs and style.               }); });    50
  50. 50. So now we have    AJS.InlineDialog($(this), 1, function(content, trigger, showPopup) {      var tweets = AJS.$("<div></div>").attr("id", "tweets");      $.getJSON("http://search.twitter.com/search.json?callback=?", {q: "#" + id, rpp: "5",lang: "en"}, function(data) {        $.each(data.results, function() { // Assemble results into a tweets div.        });        $(content).html(tweets);       showPopup();       });    },  {onHover:true}); 51
  51. 51. So now we havevar img = require(speakeasy/resources).getImageUrl(module, bird.png);$(document).ready(function () { if ( !! AJS.Meta.get("page-id") && !AJS.Meta.get("editor-mode")) { var content = AJS.$("#main-content"); var twitterfiedContent = content.html().replace(/(^|s)#(w+)/g, "$1# <a href="http://search.twitter.com/search?q=%23$2">$2</a><img src=" + img + " class=twittericon data-val=$2/>"); content.html(twitterfiedContent); AJS.$(".twittericon").each(function (i) { AJS.InlineDialog($(this), 1, function (content, trigger, showPopup) { var tweets = AJS.$("<div></div>").addClass(“tweets”); AJS.$.getJSON("http://search.twitter.com/search.json?callback=?", { q: "#" + $(this).attr(hashtag), rpp: "5", lang: "en" }, function (data) { AJS.$.each(data.results, function () { tweets.append(formatTweet(this)); }); AJS.$(content).html(tweets); showPopup(); }); }, { onHover: true }); }); }}); 52
  52. 52. THE TWEETINATOR 53
  53. 53. Cautionary advice
  54. 54. Breaking things• Unsubscribe & restore URLs yourinstance/plugins/servlet/speakeasy/unsubscribe yourinstance/plugins/servlet/speakeasy/restore 55
  55. 55. Should you use it?• Do you trust your users?• Does your instance allow public signup? 56
  56. 56. Speakeasy Settings 57
  57. 57. Cross-site scripting• inserting unescaped HTML into the page • from user input • from data you fetched 58
  58. 58. XSS Examplevar result = "<script>alert();</script>";var el = document.getElementById(myDiv);     59
  59. 59. XSS Examplevar result = "<script>alert();</script>";var el = document.getElementById(myDiv);el.innerHTML = result; 60
  60. 60. XSS Examplevar result = "<script>alert();</script>";var el = document.getElementById(myDiv);el.innerHTML = result; // BAD - Don’t do this! 61
  61. 61. XSS Examplevar result = "<script>alert();</script>";var el = document.getElementById(myDiv);el.innerHTML = result; // BAD - Don’t do this!el.innerHTML = AJS.escapeHtml(result); // Do this instead. 62
  62. 62. XSS Examplevar result = "<script>alert();</script>";var el = document.getElementById(myDiv);el.innerHTML = result; // BAD - Don’t do this!el.innerHTML = AJS.escapeHtml(result); // Do this instead.AJS.$(el).text(result); // Or this. 63
  63. 63. Interested in learning more?Securing your Plugin - Penny Wyatt @ AtlasCamp 2010 Protip If you weren’t here last year or just enjoy nostalgia, check out the Atlascamp 2010 website for videos of every session. 64
  64. 64. Where can you go from here?
  65. 65. Moar• git support• applinks proxy• xml/rpc client• check out the docs! 66
  66. 66. Product Compatibility• Speakeasy documentation• Extension repository• Remember: not just Confluence! 67
  67. 67. ResourcesSpeakeasy Documentationhttps://developer.atlassian.com/display/SPEAK/SpeakeasySpeakeasy Source on githubhttps://github.com/mrdon/speakeasy-pluginSpeakeasy JARshttps://maven.atlassian.com/content/repositories/atlassian-public/com/atlassian/labs/speakeasy-plugin/ 68
  68. 68. TAKE-AWAYS“ Got an hour to spare? That’s enough time to ” prototype a new Confluence feature with Speakeasy. #atlascamp 69
  69. 69. Thank you!

×