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
44. atlassian atlassian
Confluence pages
viewing a page/blog editing a page/blog dashboard
breadcrumbs breadcrumbs breadcrumbs
title title Welcome to Confluence Updates
content
content
Spaces
SAVE
atlassian atlassian
44
48. Put it in a dialog
AJS.$(".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
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.
});
});
49
50. 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
51. 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
52. So now we have
var 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
59. XSS Example
var result = "<script>alert();</script>";
var el = document.getElementById('myDiv');
59
60. XSS Example
var result = "<script>alert();</script>";
var el = document.getElementById('myDiv');
el.innerHTML = result;
60
61. XSS Example
var result = "<script>alert();</script>";
var el = document.getElementById('myDiv');
el.innerHTML = result; // BAD - Don’t do this!
61
62. XSS Example
var 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
63. XSS Example
var 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
64. 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