diff --git a/public/css/style.less b/public/css/style.less
index ed91e3ba98..ed0bfb2172 100644
--- a/public/css/style.less
+++ b/public/css/style.less
@@ -821,4 +821,40 @@ body .navbar .nodebb-inline-block {
background: #eceff5;
}
}
+}
+
+.posts-bar {
+ display: none;
+ -moz-opacity: 0.5;
+ opacity: 0.5;
+ -webkit-transition: opacity 250ms ease-in;
+ -moz-transition: opacity 250ms ease-in;
+ -ms-transition: opacity 250ms ease-in;
+ -o-transition: opacity 250ms ease-in;
+ transition: opacity 250ms ease-in;
+
+ &[data-active="1"] {
+ display: block;
+ }
+
+ &:hover {
+ -moz-opacity: 1;
+ opacity: 1;
+ }
+
+ li {
+ a > span {
+ .inline-block;
+ max-width: 200px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ img {
+ max-width: 24px;
+ max-height: 24px;
+ margin-right: 1em;
+ }
+ }
}
\ No newline at end of file
diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js
new file mode 100644
index 0000000000..812bde57bd
--- /dev/null
+++ b/public/src/modules/composer.js
@@ -0,0 +1,53 @@
+define(function() {
+ var composer = {
+ initialized: false,
+ posts: [],
+ container: undefined,
+ listEl: undefined
+ };
+
+ composer.init = function() {
+ // Create the fixed bottom bar
+ var contentEl = document.getElementById('content');
+
+ composer.container = document.createElement('div');
+
+ composer.container.innerHTML = '
';
+ composer.container.className = 'posts-bar navbar navbar-fixed-bottom';
+ composer.listEl = composer.container.querySelector('ul');
+ document.body.insertBefore(composer.container, contentEl);
+
+ socket.on('api:composer.push', function(threadData) {
+ console.log(threadData);
+ var uuid = utils.generateUUID(),
+ btnEl = document.createElement('li');
+ btnEl.innerHTML = '
' + threadData.title + '';
+ btnEl.setAttribute('data-uuid', uuid);
+ composer.listEl.appendChild(btnEl);
+ composer.posts.push(uuid);
+ composer.update();
+ });
+
+ composer.initialized = true;
+ }
+
+ composer.update = function() {
+ if (composer.initialized) {
+ if (composer.posts.length > 0) {
+ composer.container.setAttribute('data-active', '1');
+ } else {
+ composer.container.removeAttribute('data-active');
+ }
+ }
+ }
+
+ composer.push = function(tid) {
+ socket.emit('api:composer.push', tid);
+ }
+
+ composer.init();
+
+ return {
+ push: composer.push
+ };
+});
\ No newline at end of file
diff --git a/public/templates/header.tpl b/public/templates/header.tpl
index 6adebc6f60..edef89dee4 100644
--- a/public/templates/header.tpl
+++ b/public/templates/header.tpl
@@ -13,6 +13,13 @@
+
+
diff --git a/public/vendor/requirejs/require.js b/public/vendor/requirejs/require.js
new file mode 100644
index 0000000000..f04b8c3f7d
--- /dev/null
+++ b/public/vendor/requirejs/require.js
@@ -0,0 +1,36 @@
+/*
+ RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
+ Available via the MIT or new BSD license.
+ see: http://github.com/jrburke/requirejs for details
+*/
+var requirejs,require,define;
+(function(ba){function J(b){return"[object Function]"===N.call(b)}function K(b){return"[object Array]"===N.call(b)}function z(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(J(n)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{e=k.execCb(c,n,b,e)}catch(d){a=d}else e=k.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==
+this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(r[c]=e,h.onResourceLoad))h.onResourceLoad(k,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=
+!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=l(a.prefix);this.depMaps.push(d);u(d,"defined",v(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,C=k.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=l(a.prefix+"!"+d,this.map.parentMap),u(e,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),
+d=m(q,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",v(this,function(a){this.emit("error",a)}));d.enable()}}else n=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=v(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];H(q,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),n.fromText=v(this,function(e,c){var d=a.name,g=l(d),i=Q;c&&(e=c);i&&(Q=!1);s(g);t(j.config,b)&&(j.config[d]=j.config[b]);try{h.exec(e)}catch(D){return w(B("fromtexteval",
+"fromText eval for "+b+" failed: "+D,D,[b]))}i&&(Q=!0);this.depMaps.push(g);k.completeLoad(d);C([d],n)}),e.load(a.name,C,n,j)}));k.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){W[this.map.id]=this;this.enabling=this.enabled=!0;z(this.depMaps,v(this,function(a,b){var c,e;if("string"===typeof a){a=l(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(P,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;u(a,"defined",v(this,function(a){this.defineDep(b,
+a);this.check()}));this.errback&&u(a,"error",v(this,this.errback))}c=a.id;e=q[c];!t(P,c)&&(e&&!e.enabled)&&k.enable(a,this)}));H(this.pluginMaps,v(this,function(a){var b=m(q,a.id);b&&!b.enabled&&k.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};k={config:j,contextName:b,registry:q,defined:r,urlFetched:V,defQueue:I,Module:$,makeModuleMap:l,
+nextTick:h.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.pkgs,c=j.shim,e={paths:!0,config:!0,map:!0};H(a,function(a,b){e[b]?"map"===b?(j.map||(j.map={}),S(j[b],a,!0,!0)):S(j[b],a,!0):j[b]=a});a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=k.makeShimExports(a);c[b]=a}),j.shim=c);a.packages&&(z(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,
+location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),j.pkgs=b);H(q,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=l(b))});if(a.deps||a.callback)k.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,f){function d(e,c,g){var i,j;f.enableBuildCallback&&(c&&J(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(J(c))return w(B("requireargs",
+"Invalid require call"),g);if(a&&t(P,e))return P[e](q[a.id]);if(h.get)return h.get(k,e,a,d);i=l(e,a,!1,!0);i=i.id;return!t(r,i)?w(B("notloaded",'Module name "'+i+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[i]}M();k.nextTick(function(){M();j=s(l(null,a));j.skipMap=f.skipMap;j.init(e,c,g,{enabled:!0});E()});return d}f=f||{};S(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1g.attachEvent.toString().indexOf("[native code"))&&!Z?(Q=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,M=g,E?y.insertBefore(g,E):y.appendChild(g),
+M=null,g;if(ea)try{importScripts(d),b.completeLoad(c)}catch(l){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,l,[c]))}};A&&O(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(L=b.getAttribute("data-main"))return s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0});define=function(b,c,d){var h,g;"string"!==typeof b&&(d=c,c=b,b=null);
+K(c)||(d=c,c=null);!c&&J(d)&&(c=[],d.length&&(d.toString().replace(ma,"").replace(na,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(Q){if(!(h=M))R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return R=b}),h=R;h&&(b||(b=h.getAttribute("data-requiremodule")),g=G[h.getAttribute("data-requirecontext")])}(g?g.defQueue:U).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)};
+h(u)}})(this);
\ No newline at end of file
diff --git a/src/websockets.js b/src/websockets.js
index 38855755eb..09cea3505d 100644
--- a/src/websockets.js
+++ b/src/websockets.js
@@ -304,6 +304,12 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
if (!err) socket.emit('api:config.set', { status: 'ok' });
});
});
+
+ socket.on('api:composer.push', function(tid) {
+ topics.get_topic(tid, uid, function(topicData) {
+ socket.emit('api:composer.push', topicData);
+ });
+ });
});
}(SocketIO));