2012-04-17 19:12:24 -04:00
/ *
Jappix - An open social platform
These are the microblog JS scripts for Jappix
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
License : AGPL
Author : Vanaryon
Last revision : 03 / 12 / 11
* /
// Completes arrays of an entry's attached files
function attachedMicroblog ( selector , tFName , tFURL , tFThumb , tFSource , tFType , tFLength , tFEComments , tFNComments ) {
if ( $ ( selector ) . attr ( 'title' ) )
tFName . push ( $ ( selector ) . attr ( 'title' ) ) ;
else
tFName . push ( '' ) ;
if ( $ ( selector ) . attr ( 'href' ) )
tFURL . push ( $ ( selector ) . attr ( 'href' ) ) ;
else
tFURL . push ( '' ) ;
if ( $ ( selector ) . find ( 'link[rel=self][title=thumb]:first' ) . attr ( 'href' ) )
tFThumb . push ( $ ( selector ) . find ( 'link[rel=self][title=thumb]:first' ) . attr ( 'href' ) ) ;
else
tFThumb . push ( '' ) ;
if ( $ ( selector ) . attr ( 'source' ) )
tFSource . push ( $ ( selector ) . attr ( 'source' ) ) ;
else
tFSource . push ( '' ) ;
if ( $ ( selector ) . attr ( 'type' ) )
tFType . push ( $ ( selector ) . attr ( 'type' ) ) ;
else
tFType . push ( '' ) ;
if ( $ ( selector ) . attr ( 'length' ) )
tFLength . push ( $ ( selector ) . attr ( 'length' ) ) ;
else
tFLength . push ( '' ) ;
// Comments?
var comments _href _c = $ ( selector ) . find ( 'link[rel=replies][title=comments_file]:first' ) . attr ( 'href' ) ;
if ( comments _href _c && comments _href _c . match ( /^xmpp:(.+)\?;node=(.+)/ ) ) {
tFEComments . push ( RegExp . $1 ) ;
tFNComments . push ( decodeURIComponent ( RegExp . $2 ) ) ;
}
else {
tFEComments . push ( '' ) ;
tFNComments . push ( '' ) ;
}
}
// Displays a given microblog item
function displayMicroblog ( packet , from , hash , mode , way ) {
// Get some values
var iParse = $ ( packet . getNode ( ) ) . find ( 'items item' ) ;
iParse . each ( function ( ) {
// Initialize
var tTitle , tFiltered , tTime , tDate , tStamp , tBody , tName , tID , tHash , tIndividual , tFEClick ;
// Arrays
var tFName = [ ] ;
var tFURL = [ ] ;
var tFThumb = [ ] ;
var tFSource = [ ] ;
var tFType = [ ] ;
var tFLength = [ ] ;
var tFEComments = [ ] ;
var tFNComments = [ ] ;
var aFURL = [ ] ;
var aFCat = [ ] ;
// Get the values
tDate = $ ( this ) . find ( 'published' ) . text ( ) ;
tBody = $ ( this ) . find ( 'body' ) . text ( ) ;
tID = $ ( this ) . attr ( 'id' ) ;
tName = getBuddyName ( from ) ;
tHash = 'update-' + hex _md5 ( tName + tDate + tID ) ;
// Read attached files with a thumb (place them at first)
$ ( this ) . find ( 'link[rel=enclosure]:has(link[rel=self][title=thumb])' ) . each ( function ( ) {
attachedMicroblog ( this , tFName , tFURL , tFThumb , tFSource , tFType , tFLength , tFEComments , tFNComments ) ;
} ) ;
// Read attached files without any thumb
$ ( this ) . find ( 'link[rel=enclosure]:not(:has(link[rel=self][title=thumb]))' ) . each ( function ( ) {
attachedMicroblog ( this , tFName , tFURL , tFThumb , tFSource , tFType , tFLength , tFEComments , tFNComments ) ;
} ) ;
// Get the repeat value
var uRepeat = [ $ ( this ) . find ( 'source author name' ) . text ( ) , explodeThis ( ':' , $ ( this ) . find ( 'source author uri' ) . text ( ) , 1 ) ] ;
var uRepeated = false ;
if ( ! uRepeat [ 0 ] )
uRepeat = [ getBuddyName ( from ) , uRepeat [ 1 ] ] ;
if ( ! uRepeat [ 1 ] )
uRepeat = [ uRepeat [ 0 ] , from ] ;
// Repeated?
if ( uRepeat [ 1 ] != from )
uRepeated = true ;
// Get the comments node
var entityComments , nodeComments ;
// Get the comments
var comments _href = $ ( this ) . find ( 'link[title=comments]:first' ) . attr ( 'href' ) ;
if ( comments _href && comments _href . match ( /^xmpp:(.+)\?;node=(.+)/ ) ) {
entityComments = RegExp . $1 ;
nodeComments = decodeURIComponent ( RegExp . $2 ) ;
}
// No comments node?
if ( ! entityComments || ! nodeComments ) {
entityComments = '' ;
nodeComments = '' ;
}
// Get the stamp & time
if ( tDate ) {
tStamp = extractStamp ( Date . jab2date ( tDate ) ) ;
tTime = relativeDate ( tDate ) ;
}
else {
tStamp = getTimeStamp ( ) ;
tTime = '' ;
}
// Get the item geoloc
var tGeoloc = '' ;
var sGeoloc = $ ( this ) . find ( 'geoloc[xmlns=' + NS _GEOLOC + ']:first' ) ;
var gLat = sGeoloc . find ( 'lat' ) . text ( ) ;
var gLon = sGeoloc . find ( 'lon' ) . text ( ) ;
if ( gLat && gLon ) {
tGeoloc += '<a class="geoloc talk-images" href="http://maps.google.com/?q=' + encodeQuotes ( gLat ) + ',' + encodeQuotes ( gLon ) + '" target="_blank">' ;
// Human-readable name?
var gHuman = humanPosition (
sGeoloc . find ( 'locality' ) . text ( ) ,
sGeoloc . find ( 'region' ) . text ( ) ,
sGeoloc . find ( 'country' ) . text ( )
) ;
if ( gHuman )
tGeoloc += gHuman . htmlEnc ( ) ;
else
tGeoloc += gLat . htmlEnc ( ) + '; ' + gLon . htmlEnc ( ) ;
tGeoloc += '</a>' ;
}
// Retrieve the message body
tTitle = $ ( this ) . find ( 'content[type=text]' ) . text ( ) ;
if ( ! tTitle ) {
// Legacy?
tTitle = $ ( this ) . find ( 'title:not(source > title)' ) . text ( ) ;
// Last chance?
if ( ! tTitle )
tTitle = tBody ;
}
// Trim the content
tTitle = trim ( tTitle ) ;
// Any content?
if ( tTitle ) {
// Apply links to message body
tFiltered = filterThisMessage ( tTitle , tName . htmlEnc ( ) , true ) ;
// Display the received message
var html = '<div class="one-update update_' + hash + ' ' + tHash + '" data-stamp="' + encodeQuotes ( tStamp ) + '" data-id="' + encodeQuotes ( tID ) + '" data-xid="' + encodeQuotes ( from ) + '">' +
'<div class="' + hash + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'</div>' +
'<div class="body">' +
'<p>' ;
// Is it a repeat?
if ( uRepeated )
html += '<a href="#" class="repeat talk-images" title="' + encodeQuotes ( printf ( _e ( "This is a repeat from %s" ) , uRepeat [ 0 ] + ' (' + uRepeat [ 1 ] + ')' ) ) + '" onclick="return checkChatCreate(\'' + encodeOnclick ( uRepeat [ 1 ] ) + '\', \'chat\');" data-xid="' + encodeQuotes ( uRepeat [ 1 ] ) + '"></a>' ;
html += '<b title="' + from + '" class="name">' + tName . htmlEnc ( ) + '</b> <span>' + tFiltered + '</span></p>' +
'<p class="infos">' + tTime + tGeoloc + '</p>' ;
// Any file to display?
if ( tFURL . length )
html += '<p class="file">' ;
// Generate an array of the files URL
for ( var a = 0 ; a < tFURL . length ; a ++ ) {
// Not enough data?
if ( ! tFURL [ a ] )
continue ;
// Push the current URL! (YouTube or file)
if ( tFURL [ a ] . match ( /(\w{3,5})(:)(\S+)((\.youtube\.com\/watch(\?v|\?\S+v|\#\!v|\#\!\S+v)\=)|(youtu\.be\/))([^& ]+)((&\S)|(&\S)|\s|$)/gim ) ) {
aFURL . push ( trim ( RegExp . $8 ) ) ;
aFCat . push ( 'youtube' ) ;
}
else if ( canIntegrateBox ( explodeThis ( '/' , tFType [ a ] , 1 ) ) ) {
aFURL . push ( tFURL [ a ] ) ;
aFCat . push ( fileCategory ( explodeThis ( '/' , tFType [ a ] , 1 ) ) ) ;
}
}
// Add each file code
for ( var f = 0 ; f < tFURL . length ; f ++ ) {
// Not enough data?
if ( ! tFURL [ f ] )
continue ;
// Get the file type
var tFExt = explodeThis ( '/' , tFType [ f ] , 1 ) ;
var tFCat = fileCategory ( tFExt ) ;
var tFLink = tFURL [ f ] ;
// Youtube video?
if ( tFLink . match ( /(\w{3,5})(:)(\S+)((\.youtube\.com\/watch(\?v|\?\S+v|\#\!v|\#\!\S+v)\=)|(youtu\.be\/))([^& ]+)((&\S)|(&\S)|\s|$)/gim ) ) {
tFLink = trim ( RegExp . $8 ) ;
tFCat = 'youtube' ;
}
// Supported image/video/sound
if ( canIntegrateBox ( tFExt ) || ( tFCat == 'youtube' ) )
tFEClick = 'onclick="return applyIntegrateBox(\'' + encodeOnclick ( tFLink ) + '\', \'' + encodeOnclick ( tFCat ) + '\', \'' + encodeOnclick ( aFURL ) + '\', \'' + encodeOnclick ( aFCat ) + '\', \'' + encodeOnclick ( tFEComments ) + '\', \'' + encodeOnclick ( tFNComments ) + '\', \'large\');" ' ;
else
tFEClick = '' ;
// Any thumbnail?
if ( tFThumb [ f ] )
html += '<a class="thumb" ' + tFEClick + 'href="' + encodeQuotes ( tFURL [ f ] ) + '" target="_blank" title="' + encodeQuotes ( tFName [ f ] ) + '" data-node="' + encodeQuotes ( tFNComments ) + '"><img src="' + encodeQuotes ( tFThumb [ f ] ) + '" alt="" /></a>' ;
else
html += '<a class="' + encodeQuotes ( tFCat ) + ' link talk-images" ' + tFEClick + 'href="' + encodeQuotes ( tFURL [ f ] ) + '" target="_blank" data-node="' + encodeQuotes ( tFNComments ) + '">' + tFName [ f ] . htmlEnc ( ) + '</a>' ;
}
if ( tFURL . length )
html += '</p>' ;
// It's my own notice, we can remove it!
if ( from == getXID ( ) )
html += '<a href="#" onclick="return removeMicroblog(\'' + encodeOnclick ( tID ) + '\', \'' + encodeOnclick ( tHash ) + '\');" title="' + _e ( "Remove this notice" ) + '" class="mbtool remove talk-images"></a>' ;
// Notice from another user
else {
// User profile
html += '<a href="#" title="' + _e ( "View profile" ) + '" class="mbtool profile talk-images" onclick="return openUserInfos(\'' + encodeOnclick ( from ) + '\');"></a>' ;
// If PEP is enabled
if ( enabledPEP ( ) )
html += '<a href="#" title="' + _e ( "Repeat this notice" ) + '" class="mbtool repost talk-images"></a>' ;
}
html += '</div><div class="comments-container" data-node="' + encodeQuotes ( nodeComments ) + '"></div></div>' ;
// Mixed mode
if ( ( mode == 'mixed' ) && ! exists ( '.mixed .' + tHash ) ) {
// Remove the old element
if ( way == 'push' )
$ ( '#channel .content.mixed .one-update.update_' + hash ) . remove ( ) ;
// Get the nearest element
var nearest = sortElementByStamp ( tStamp , '#channel .mixed .one-update' ) ;
// Append the content at the right position (date relative)
if ( nearest == 0 )
$ ( '#channel .content.mixed' ) . append ( html ) ;
else
$ ( '#channel .one-update[data-stamp=' + nearest + ']:first' ) . before ( html ) ;
// Show the new item
if ( way == 'push' )
$ ( '#channel .content.mixed .one-update.' + tHash ) . fadeIn ( 'fast' ) ;
else
$ ( '#channel .content.mixed .one-update.' + tHash ) . show ( ) ;
// Remove the old notices to make the DOM lighter
var oneUpdate = '#channel .content.mixed .one-update' ;
if ( $ ( oneUpdate ) . size ( ) > 80 )
$ ( oneUpdate + ':last' ) . remove ( ) ;
// Click event on avatar/name
$ ( '.mixed .' + tHash + ' .avatar-container, .mixed .' + tHash + ' .body b' ) . click ( function ( ) {
getMicroblog ( from , hash ) ;
} ) ;
}
// Individual mode
tIndividual = '#channel .content.individual.microblog-' + hash ;
// Can append individual content?
var can _individual = true ;
if ( $ ( '#channel .top.individual input[name=comments]' ) . val ( ) && exists ( tIndividual + ' .one-update' ) )
can _individual = false ;
if ( can _individual && exists ( tIndividual ) && ! exists ( '.individual .' + tHash ) ) {
if ( mode == 'mixed' )
$ ( tIndividual ) . prepend ( html ) ;
else
$ ( tIndividual + ' a.more' ) . before ( html ) ;
// Show the new item
if ( way == 'push' )
$ ( '#channel .content.individual .one-update.' + tHash ) . fadeIn ( 'fast' ) ;
else
$ ( '#channel .content.individual .one-update.' + tHash ) . show ( ) ;
// Make 'more' link visible
$ ( tIndividual + ' a.more' ) . css ( 'visibility' , 'visible' ) ;
// Click event on name (if not me!)
if ( from != getXID ( ) )
$ ( '.individual .' + tHash + ' .avatar-container, .individual .' + tHash + ' .body b' ) . click ( function ( ) {
checkChatCreate ( from , 'chat' ) ;
} ) ;
}
// Apply the click event
$ ( '.' + tHash + ' a.repost:not([data-event=true])' ) . click ( function ( ) {
return publishMicroblog ( tTitle , tFName , tFURL , tFType , tFLength , tFThumb , uRepeat , entityComments , nodeComments , tFEComments , tFNComments ) ;
} )
. attr ( 'data-event' , 'true' ) ;
// Apply the hover event
if ( nodeComments )
$ ( '.' + mode + ' .' + tHash ) . hover ( function ( ) {
showCommentsMicroblog ( $ ( this ) , entityComments , nodeComments , tHash ) ;
} , function ( ) {
if ( $ ( this ) . find ( 'div.comments a.one-comment.loading' ) . size ( ) )
$ ( this ) . find ( 'div.comments' ) . remove ( ) ;
} ) ;
}
} ) ;
// Display the avatar of this buddy
getAvatar ( from , 'cache' , 'true' , 'forget' ) ;
}
// Removes a given microblog item
function removeMicroblog ( id , hash ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#publisher-delete */
// Initialize
var selector = $ ( '.' + hash ) ;
var get _last = false ;
// Get the latest item for the mixed mode
if ( exists ( '#channel .content.mixed .' + hash ) )
get _last = true ;
// Remove the item from our DOM
selector . fadeOut ( 'fast' , function ( ) {
$ ( this ) . remove ( ) ;
} ) ;
// Send the IQ to remove the item (and get eventual error callback)
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
var retract = pubsub . appendChild ( iq . buildNode ( 'retract' , { 'node' : NS _URN _MBLOG , 'xmlns' : NS _PUBSUB } ) ) ;
retract . appendChild ( iq . buildNode ( 'item' , { 'id' : id , 'xmlns' : NS _PUBSUB } ) ) ;
if ( get _last )
con . send ( iq , handleRemoveMicroblog ) ;
else
con . send ( iq , handleErrorReply ) ;
return false ;
}
// Handles the microblog item removal
function handleRemoveMicroblog ( iq ) {
// Handle the error reply
handleErrorReply ( iq ) ;
// Get the latest item
requestMicroblog ( getXID ( ) , '1' , false , handleUpdateRemoveMicroblog ) ;
}
// Handles the microblog update
function handleUpdateRemoveMicroblog ( iq ) {
// Error?
if ( iq . getType ( ) == 'error' )
return ;
// Initialize
var xid = bareXID ( getStanzaFrom ( iq ) ) ;
var hash = hex _md5 ( xid ) ;
// Display the item!
displayMicroblog ( iq , xid , hash , 'mixed' , 'push' ) ;
}
// Gets a given microblog comments node
function getCommentsMicroblog ( server , node , id ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#subscriber-retrieve-requestall */
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'get' ) ;
iq . setID ( 'get_' + genID ( ) + '-' + id ) ;
iq . setTo ( server ) ;
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
pubsub . appendChild ( iq . buildNode ( 'items' , { 'node' : node , 'xmlns' : NS _PUBSUB } ) ) ;
con . send ( iq , handleCommentsMicroblog ) ;
return false ;
}
// Handles a microblog comments node items
function handleCommentsMicroblog ( iq ) {
// Path
var id = explodeThis ( '-' , iq . getID ( ) , 1 ) ;
var path = 'div.comments[data-id=' + id + '] div.comments-content' ;
// Does not exist?
if ( ! exists ( path ) )
return false ;
// Any error?
if ( handleErrorReply ( iq ) ) {
$ ( path ) . html ( '<div class="one-comment loading">' + _e ( "Could not get the comments!" ) + '</div>' ) ;
return false ;
}
// Initialize
var data = iq . getNode ( ) ;
var server = bareXID ( getStanzaFrom ( iq ) ) ;
var node = $ ( data ) . find ( 'items:first' ) . attr ( 'node' ) ;
var users _xid = [ ] ;
var code = '' ;
// No node?
if ( ! node )
node = $ ( data ) . find ( 'publish:first' ) . attr ( 'node' ) ;
// Get the parent microblog item
var parent _select = $ ( '#channel .one-update:has(*[data-node=' + node + '])' ) ;
var parent _data = [ parent _select . attr ( 'data-xid' ) , NS _URN _MBLOG , parent _select . attr ( 'data-id' ) ] ;
// Get the owner XID
var owner _xid = parent _select . attr ( 'data-xid' ) ;
var repeat _xid = parent _select . find ( 'a.repeat' ) . attr ( 'data-xid' ) ;
// Must we create the complete DOM?
var complete = true ;
if ( $ ( path ) . find ( '.one-comment.compose' ) . size ( ) )
complete = false ;
// Add the comment tool
if ( complete )
code += '<div class="one-comment compose">' +
'<span class="icon talk-images"></span><input type="text" placeholder="' + _e ( "Type your comment here..." ) + '" />' +
'</div>' ;
// Append the comments
$ ( data ) . find ( 'item' ) . each ( function ( ) {
// Get comment
var current _id = $ ( this ) . attr ( 'id' ) ;
var current _xid = explodeThis ( ':' , $ ( this ) . find ( 'source author uri' ) . text ( ) , 1 ) ;
var current _name = $ ( this ) . find ( 'source author name' ) . text ( ) ;
var current _date = $ ( this ) . find ( 'published' ) . text ( ) ;
var current _body = $ ( this ) . find ( 'content[type=text]' ) . text ( ) ;
var current _bname = getBuddyName ( current _xid ) ;
// Legacy?
if ( ! current _body )
current _body = $ ( this ) . find ( 'title:not(source > title)' ) . text ( ) ;
// Yet displayed? (continue the loop)
if ( $ ( path ) . find ( '.one-comment[data-id=' + current _id + ']' ) . size ( ) )
return ;
// No XID?
if ( ! current _xid ) {
current _xid = '' ;
if ( ! current _name )
current _name = _e ( "unknown" ) ;
}
else if ( ! current _name || ( current _bname != getXIDNick ( current _xid ) ) )
current _name = current _bname ;
// Any date?
if ( current _date )
current _date = relativeDate ( current _date ) ;
else
current _date = getCompleteTime ( ) ;
// Click event
var onclick = 'false' ;
if ( current _xid != getXID ( ) )
onclick = 'checkChatCreate(\'' + encodeOnclick ( current _xid ) + '\', \'chat\')' ;
// If this is my comment, add a marker
var type = 'him' ;
var marker = '' ;
var remove = '' ;
if ( current _xid == getXID ( ) ) {
type = 'me' ;
marker = '<div class="marker"></div>' ;
remove = '<a href="#" class="remove" onclick="return removeCommentMicroblog(\'' + encodeOnclick ( server ) + '\', \'' + encodeOnclick ( node ) + '\', \'' + encodeOnclick ( current _id ) + '\');">' + _e ( "Remove" ) + '</a>' ;
}
// New comment?
var new _class = '' ;
if ( ! complete )
new _class = ' new' ;
// Add the comment
if ( current _body ) {
// Add the XID
if ( ! existArrayValue ( users _xid , current _xid ) )
users _xid . push ( current _xid ) ;
// Add the HTML code
code += '<div class="one-comment ' + hex _md5 ( current _xid ) + ' ' + type + new _class + '" data-id="' + encodeQuotes ( current _id ) + '">' +
marker +
'<div class="avatar-container" onclick="return ' + onclick + ';">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="comment-container">' +
'<a href="#" onclick="return ' + onclick + ';" title="' + encodeQuotes ( current _xid ) + '" class="name">' + current _name . htmlEnc ( ) + '</a>' +
'<span class="date">' + current _date . htmlEnc ( ) + '</span>' +
remove +
'<p class="body">' + filterThisMessage ( current _body , current _name , true ) + '</p>' +
'</div>' +
'<div class="clear"></div>' +
'</div>' ;
}
} ) ;
// Add the HTML
if ( complete ) {
$ ( path ) . html ( code ) ;
// Focus on the compose input
$ ( document ) . oneTime ( 10 , function ( ) {
$ ( path ) . find ( '.one-comment.compose input' ) . focus ( ) ;
} ) ;
}
else {
$ ( path ) . find ( '.one-comment.compose' ) . after ( code ) ;
// Beautiful effect
$ ( path ) . find ( '.one-comment.new' ) . slideDown ( 'fast' , function ( ) {
adaptCommentMicroblog ( id ) ;
} ) . removeClass ( 'new' ) ;
}
// Set the good widths
adaptCommentMicroblog ( id ) ;
// Get the avatars
for ( a in users _xid )
getAvatar ( users _xid [ a ] , 'cache' , 'true' , 'forget' ) ;
// Add the owner XID
if ( owner _xid && owner _xid . match ( '@' ) && ! existArrayValue ( users _xid , owner _xid ) )
users _xid . push ( owner _xid ) ;
// Add the repeated from XID
if ( repeat _xid && repeat _xid . match ( '@' ) && ! existArrayValue ( users _xid , repeat _xid ) )
users _xid . push ( repeat _xid ) ;
// Remove my own XID
removeArrayValue ( users _xid , getXID ( ) ) ;
// DOM events
if ( complete ) {
// Update timer
$ ( path ) . everyTime ( '60s' , function ( ) {
getCommentsMicroblog ( server , node , id ) ;
logThis ( 'Updating comments node: ' + node + ' on ' + server + '...' ) ;
} ) ;
// Input key event
$ ( path ) . find ( '.one-comment.compose input' ) . placeholder ( )
. keyup ( function ( e ) {
if ( ( e . keyCode == 13 ) && $ ( this ) . val ( ) ) {
// Send the comment!
sendCommentMicroblog ( $ ( this ) . val ( ) , server , node , id , users _xid , parent _data ) ;
// Reset the input value
$ ( this ) . val ( '' ) ;
return false ;
}
} ) ;
}
}
// Shows the microblog comments box
function showCommentsMicroblog ( path , entityComments , nodeComments , tHash ) {
// Do not display it twice!
if ( path . find ( 'div.comments' ) . size ( ) )
return ;
// Generate an unique ID
var idComments = genID ( ) ;
// Create comments container
path . find ( 'div.comments-container' ) . append (
'<div class="comments" data-id="' + encodeQuotes ( idComments ) + '">' +
'<div class="arrow talk-images"></div>' +
'<div class="comments-content">' +
'<a href="#" class="one-comment loading"><span class="icon talk-images"></span>' + _e ( "Show comments" ) + '</a>' +
'</div>' +
'</div>'
) ;
// Click event
path . find ( 'div.comments a.one-comment' ) . click ( function ( ) {
// Set loading info
$ ( this ) . parent ( ) . html ( '<div class="one-comment loading"><span class="icon talk-images"></span>' + _e ( "Loading comments..." ) + '</div>' ) ;
// Request comments
getCommentsMicroblog ( entityComments , nodeComments , idComments ) ;
// Remove the comments from the DOM if click away
if ( tHash ) {
$ ( '#channel' ) . die ( 'click' ) ;
$ ( '#channel' ) . live ( 'click' , function ( evt ) {
if ( ! $ ( evt . target ) . parents ( '.' + tHash ) . size ( ) ) {
$ ( '#channel' ) . die ( 'click' ) ;
$ ( '#channel .one-update div.comments-content' ) . stopTime ( ) ;
$ ( '#channel .one-update div.comments' ) . remove ( ) ;
}
} ) ;
}
return false ;
} ) ;
}
// Sends a comment on a given microblog comments node
function sendCommentMicroblog ( value , server , node , id , notifiy _arr , parent _data ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#publisher-publish */
// Not enough data?
if ( ! value || ! server || ! node )
return false ;
// Get some values
var date = getXMPPTime ( 'utc' ) ;
var hash = hex _md5 ( value + date ) ;
// New IQ
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
iq . setTo ( server ) ;
iq . setID ( 'set_' + genID ( ) + '-' + id ) ;
// PubSub main elements
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
var publish = pubsub . appendChild ( iq . buildNode ( 'publish' , { 'node' : node , 'xmlns' : NS _PUBSUB } ) ) ;
var item = publish . appendChild ( iq . buildNode ( 'item' , { 'id' : hash , 'xmlns' : NS _PUBSUB } ) ) ;
var entry = item . appendChild ( iq . buildNode ( 'entry' , { 'xmlns' : NS _ATOM } ) ) ;
// Author infos
var Source = entry . appendChild ( iq . buildNode ( 'source' , { 'xmlns' : NS _ATOM } ) ) ;
var author = Source . appendChild ( iq . buildNode ( 'author' , { 'xmlns' : NS _ATOM } ) ) ;
author . appendChild ( iq . buildNode ( 'name' , { 'xmlns' : NS _ATOM } , getName ( ) ) ) ;
author . appendChild ( iq . buildNode ( 'uri' , { 'xmlns' : NS _ATOM } , 'xmpp:' + getXID ( ) ) ) ;
// Create the comment
entry . appendChild ( iq . buildNode ( 'content' , { 'type' : 'text' , 'xmlns' : NS _ATOM } , value ) ) ;
entry . appendChild ( iq . buildNode ( 'published' , { 'xmlns' : NS _ATOM } , date ) ) ;
con . send ( iq ) ;
// Handle this comment!
iq . setFrom ( server ) ;
handleCommentsMicroblog ( iq ) ;
// Notify users
if ( notifiy _arr && notifiy _arr . length ) {
// XMPP link to the item
var href = 'xmpp:' + server + '?;node=' + encodeURIComponent ( node ) + ';item=' + encodeURIComponent ( hash ) ;
// Loop!
for ( n in notifiy _arr )
sendNotification ( notifiy _arr [ n ] , 'comment' , href , value , parent _data ) ;
}
return false ;
}
// Removes a given microblog comment item
function removeCommentMicroblog ( server , node , id ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#publisher-delete */
// Remove the item from our DOM
$ ( '.one-comment[data-id=' + id + ']' ) . slideUp ( 'fast' , function ( ) {
// Get the parent ID
var parent _id = $ ( this ) . parents ( 'div.comments' ) . attr ( 'data-id' ) ;
// Remove it!
$ ( this ) . remove ( ) ;
// Adapt the width
adaptCommentMicroblog ( parent _id ) ;
} ) ;
// Send the IQ to remove the item (and get eventual error callback)
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
iq . setTo ( server ) ;
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
var retract = pubsub . appendChild ( iq . buildNode ( 'retract' , { 'node' : node , 'xmlns' : NS _PUBSUB } ) ) ;
retract . appendChild ( iq . buildNode ( 'item' , { 'id' : id , 'xmlns' : NS _PUBSUB } ) ) ;
con . send ( iq ) ;
return false ;
}
// Adapts the comment elements width
function adaptCommentMicroblog ( id ) {
var selector = $ ( 'div.comments[data-id=' + id + '] div.comments-content' ) ;
var selector _width = selector . width ( ) ;
// Change widths
selector . find ( '.one-comment.compose input' ) . css ( 'width' , selector _width - 60 ) ;
selector . find ( '.one-comment .comment-container' ) . css ( 'width' , selector _width - 55 ) ;
}
// Handles the microblog of an user
function handleMicroblog ( iq ) {
// Get the from attribute of this IQ
var from = bareXID ( getStanzaFrom ( iq ) ) ;
// Define the selector path
var selector = '#channel .top.individual input[name=' ;
// Is this request still alive?
if ( from == $ ( selector + 'jid]' ) . val ( ) ) {
var hash = hex _md5 ( from ) ;
// Update the items counter
var old _count = parseInt ( $ ( selector + 'counter]' ) . val ( ) ) ;
$ ( selector + 'counter]' ) . val ( old _count + 20 ) ;
// Display the microblog
displayMicroblog ( iq , from , hash , 'individual' , 'request' ) ;
// Hide the waiting icon
if ( enabledPEP ( ) )
waitMicroblog ( 'sync' ) ;
else
waitMicroblog ( 'unsync' ) ;
// Hide the 'more items' link?
if ( $ ( iq . getNode ( ) ) . find ( 'item' ) . size ( ) < old _count )
$ ( '#channel .individual a.more' ) . remove ( ) ;
// Get the comments?
var comments _node = $ ( '#channel .top.individual input[name=comments]' ) . val ( ) ;
if ( comments _node && comments _node . match ( /^xmpp:(.+)\?;node=(.+);item=(.+)/ ) ) {
// Get the values
var comments _entity = RegExp . $1 ;
comments _node = decodeURIComponent ( RegExp . $2 ) ;
// Selectors
var file _link = $ ( '#channel .individual .one-update p.file a[data-node=' + comments _node + ']' ) ;
var entry _link = $ ( '#channel .individual .one-update:has(*[data-node=' + comments _node + '])' ) ;
// Is it a file?
if ( file _link . size ( ) )
file _link . click ( ) ;
// Is it a microblog entry?
else if ( entry _link . size ( ) ) {
showCommentsMicroblog ( entry _link , comments _entity , comments _node ) ;
entry _link . find ( 'a.one-comment' ) . click ( ) ;
}
}
}
logThis ( 'Microblog got: ' + from , 3 ) ;
}
// Resets the microblog elements
function resetMicroblog ( ) {
// Reset everything
$ ( '#channel .individual .one-update div.comments-content' ) . stopTime ( ) ;
$ ( '#channel .individual' ) . remove ( ) ;
$ ( '#channel .mixed' ) . show ( ) ;
// Hide the waiting icon
if ( enabledPEP ( ) )
waitMicroblog ( 'sync' ) ;
else
waitMicroblog ( 'unsync' ) ;
return false ;
}
// Gets the user's microblog to check it exists
function getInitMicroblog ( ) {
getMicroblog ( getXID ( ) , hex _md5 ( getXID ( ) ) , true ) ;
}
// Handles the user's microblog to create it in case of error
function handleInitMicroblog ( iq ) {
// Any error?
if ( ( iq . getType ( ) == 'error' ) && $ ( iq . getNode ( ) ) . find ( 'item-not-found' ) . size ( ) ) {
// The node may not exist, create it!
setupMicroblog ( '' , NS _URN _MBLOG , '1' , '1000000' , '' , '' , true ) ;
logThis ( 'Error while getting microblog, trying to reconfigure the Pubsub node!' , 2 ) ;
}
}
// Requests an user's microblog
function requestMicroblog ( xid , items , get _item , handler ) {
// Ask the server the user's microblog
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'get' ) ;
iq . setTo ( xid ) ;
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
var ps _items = pubsub . appendChild ( iq . buildNode ( 'items' , { 'node' : NS _URN _MBLOG , 'xmlns' : NS _PUBSUB } ) ) ;
// Request a particular item?
if ( get _item )
ps _items . appendChild ( iq . buildNode ( 'item' , { 'id' : get _item , 'xmlns' : NS _PUBSUB } ) ) ;
else
ps _items . setAttribute ( 'max_items' , items ) ;
if ( handler )
con . send ( iq , handler ) ;
else
con . send ( iq , handleMicroblog ) ;
return false ;
}
// Gets the microblog of an user
function getMicroblog ( xid , hash , check ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#subscriber-retrieve */
logThis ( 'Get the microblog: ' + xid , 3 ) ;
// Fire the wait event
waitMicroblog ( 'fetch' ) ;
// XMPP URI?
var get _item = '' ;
if ( xid . match ( /^xmpp:(.+)\?;node=(.+);item=(.+)/ ) ) {
xid = RegExp . $1 ;
get _item = decodeURIComponent ( RegExp . $3 ) ;
}
// No hash?
if ( ! hash )
hash = hex _md5 ( xid ) ;
// Can display the individual channel?
if ( ! check && ! exists ( '#channel .individual' ) ) {
// Hide the mixed channel
$ ( '#channel .mixed' ) . hide ( ) ;
// Get the channel title depending on the XID
var cTitle ;
var cShortcuts = '' ;
if ( xid == getXID ( ) )
cTitle = _e ( "Your channel" ) ;
else {
cTitle = _e ( "Channel of" ) + ' ' + getBuddyName ( xid ) . htmlEnc ( ) ;
cShortcuts = '<div class="shortcuts">' +
'<a href="#" class="message talk-images" title="' + _e ( "Send him/her a message" ) + '" onclick="return composeInboxMessage(\'' + encodeOnclick ( xid ) + '\');"></a>' +
'<a href="#" class="chat talk-images" title="' + _e ( "Start a chat with him/her" ) + '" onclick="return checkChatCreate(\'' + encodeOnclick ( xid ) + '\', \'chat\');"></a>' +
'<a href="#" class="command talk-images" title="' + _e ( "Command" ) + '" onclick="return retrieveAdHoc(\'' + encodeOnclick ( xid ) + '\');"></a>' +
'<a href="#" class="profile talk-images" title="' + _e ( "Show user profile" ) + '" onclick="return openUserInfos(\'' + encodeOnclick ( xid ) + '\');"></a>' +
'</div>' ;
}
// Create a new individual channel
$ ( '#channel .content.mixed' ) . after (
'<div class="content individual microblog-' + hash + '">' +
'<a href="#" class="more home-images" onclick="return getMicroblog(\'' + encodeOnclick ( xid ) + '\', \'' + encodeOnclick ( hash ) + '\');">' + _e ( "More notices..." ) + '</a>' +
'</div>'
)
. before (
'<div class="top individual ' + hash + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="update">' +
'<h2>' + cTitle + '</h2>' +
'<a href="#" onclick="return resetMicroblog();">« ' + _e ( "Previous" ) + '</a>' +
'</div>' +
cShortcuts +
'<input type="hidden" name="jid" value="' + encodeQuotes ( xid ) + '" />' +
'<input type="hidden" name="counter" value="20" />' +
'</div>'
) ;
// Display the user avatar
getAvatar ( xid , 'cache' , 'true' , 'forget' ) ;
}
// Get the number of items to retrieve
var items = '0' ;
if ( ! check )
items = $ ( '#channel .top.individual input[name=counter]' ) . val ( ) ;
// Request
if ( check )
requestMicroblog ( xid , items , get _item , handleInitMicroblog ) ;
else
requestMicroblog ( xid , items , get _item , handleMicroblog ) ;
return false ;
}
// Show a given microblog waiting status
function waitMicroblog ( type ) {
// First hide all the infos elements
$ ( '#channel .footer div' ) . hide ( ) ;
// Display the good one
$ ( '#channel .footer div.' + type ) . show ( ) ;
// Depending on the type, disable/enable certain tools
var selector = $ ( '#channel .top input[name=microblog_body]' ) ;
if ( type == 'unsync' )
selector . attr ( 'disabled' , true ) ;
else if ( type == 'sync' )
$ ( document ) . oneTime ( 10 , function ( ) {
selector . removeAttr ( 'disabled' ) . focus ( ) ;
} ) ;
}
// Setups a new microblog
function setupMicroblog ( entity , node , persist , maximum , access , publish , create ) {
/* REF: http://xmpp.org/extensions/xep-0060.html#owner-create-and-configure */
// Create the PubSub node
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
// Any external entity?
if ( entity )
iq . setTo ( entity ) ;
// Create it?
if ( create ) {
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
pubsub . appendChild ( iq . buildNode ( 'create' , { 'xmlns' : NS _PUBSUB , 'node' : node } ) ) ;
}
else
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB _OWNER } ) ;
// Configure it!
var configure = pubsub . appendChild ( iq . buildNode ( 'configure' , { 'node' : node , 'xmlns' : NS _PUBSUB } ) ) ;
var x = configure . appendChild ( iq . buildNode ( 'x' , { 'xmlns' : NS _XDATA , 'type' : 'submit' } ) ) ;
var field1 = x . appendChild ( iq . buildNode ( 'field' , { 'var' : 'FORM_TYPE' , 'type' : 'hidden' , 'xmlns' : NS _XDATA } ) ) ;
field1 . appendChild ( iq . buildNode ( 'value' , { 'xmlns' : NS _XDATA } , NS _PUBSUB _NC ) ) ;
// Persist items?
if ( persist ) {
var field2 = x . appendChild ( iq . buildNode ( 'field' , { 'var' : 'pubsub#persist_items' , 'xmlns' : NS _XDATA } ) ) ;
field2 . appendChild ( iq . buildNode ( 'value' , { 'xmlns' : NS _XDATA } , persist ) ) ;
}
// Maximum items?
if ( maximum ) {
var field3 = x . appendChild ( iq . buildNode ( 'field' , { 'var' : 'pubsub#max_items' , 'xmlns' : NS _XDATA } ) ) ;
field3 . appendChild ( iq . buildNode ( 'value' , { 'xmlns' : NS _XDATA } , maximum ) ) ;
}
// Access rights?
if ( access ) {
var field4 = x . appendChild ( iq . buildNode ( 'field' , { 'var' : 'pubsub#access_model' , 'xmlns' : NS _XDATA } ) ) ;
field4 . appendChild ( iq . buildNode ( 'value' , { 'xmlns' : NS _XDATA } , access ) ) ;
}
// Publish rights?
if ( publish ) {
var field5 = x . appendChild ( iq . buildNode ( 'field' , { 'var' : 'pubsub#publish_model' , 'xmlns' : NS _XDATA } ) ) ;
field5 . appendChild ( iq . buildNode ( 'value' , { 'xmlns' : NS _XDATA } , publish ) ) ;
}
con . send ( iq ) ;
}
// Gets the microblog configuration
function getConfigMicroblog ( ) {
// Lock the microblog options
$ ( '#persistent, #maxnotices' ) . attr ( 'disabled' , true ) ;
// Get the microblog configuration
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'get' ) ;
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB _OWNER } ) ;
pubsub . appendChild ( iq . buildNode ( 'configure' , { 'node' : NS _URN _MBLOG , 'xmlns' : NS _PUBSUB _OWNER } ) ) ;
con . send ( iq , handleGetConfigMicroblog ) ;
}
// Handles the microblog configuration
function handleGetConfigMicroblog ( iq ) {
// Reset the options stuffs
waitOptions ( 'microblog' ) ;
// Unlock the microblog options
$ ( '#persistent, #maxnotices' ) . removeAttr ( 'disabled' ) ;
// End if not a result
if ( ! iq || ( iq . getType ( ) != 'result' ) )
return ;
// Initialize the values
var selector = $ ( iq . getNode ( ) ) ;
var persistent = '0' ;
var maxnotices = '1000000' ;
// Get the values
var xPersistent = selector . find ( 'field[var=pubsub#persist_items] value:first' ) . text ( ) ;
var xMaxnotices = selector . find ( 'field[var=pubsub#max_items] value:first' ) . text ( ) ;
// Any value?
if ( xPersistent )
persistent = xPersistent ;
if ( xMaxnotices )
maxnotices = xMaxnotices ;
// Change the maxnotices value
switch ( maxnotices ) {
case '1' :
case '100' :
case '1000' :
case '10000' :
case '100000' :
case '1000000' :
break ;
default :
maxnotices = '1000000' ;
break ;
}
// Apply persistent value
if ( persistent == '0' )
$ ( '#persistent' ) . attr ( 'checked' , false ) ;
else
$ ( '#persistent' ) . attr ( 'checked' , true ) ;
// Apply maxnotices value
$ ( '#maxnotices' ) . val ( maxnotices ) ;
}
// Handles the user's microblog
function handleMyMicroblog ( packet ) {
// Reset the entire form
$ ( '#channel .top input[name=microblog_body]' ) . removeAttr ( 'disabled' ) . val ( '' ) ;
$ ( '#channel .top input[name=microblog_body]' ) . placeholder ( ) ;
unattachMicroblog ( ) ;
// Check for errors
handleErrorReply ( packet ) ;
}
// Performs the microblog sender checks
function sendMicroblog ( ) {
logThis ( 'Send a new microblog item' , 3 ) ;
// Avoid nasty errors
try {
// Get the values
var selector = $ ( '#channel .top input[name=microblog_body]' ) ;
var body = trim ( selector . val ( ) ) ;
// Sufficient parameters
if ( body ) {
// Disable & blur our input
selector . attr ( 'disabled' , true ) . blur ( ) ;
// Files array
var fName = [ ] ;
var fType = [ ] ;
var fLength = [ ] ;
var fURL = [ ] ;
var fThumb = [ ] ;
// Read the files
$ ( '#attach .one-file' ) . each ( function ( ) {
// Push the values!
fName . push ( $ ( this ) . find ( 'a.link' ) . text ( ) ) ;
fType . push ( $ ( this ) . attr ( 'data-type' ) ) ;
fLength . push ( $ ( this ) . attr ( 'data-length' ) ) ;
fURL . push ( $ ( this ) . find ( 'a.link' ) . attr ( 'href' ) ) ;
fThumb . push ( $ ( this ) . attr ( 'data-thumb' ) ) ;
} ) ;
// Containing YouTube videos?
var yt _matches = body . match ( /(\w{3,5})(:)(\S+)((\.youtube\.com\/watch(\?v|\?\S+v|\#\!v|\#\!\S+v)\=)|(youtu\.be\/))([^& ]+)((&\S)|(&\S)|\s|$)/gim ) ;
for ( y in yt _matches ) {
fName . push ( '' ) ;
fType . push ( 'text/html' ) ;
fLength . push ( '' ) ;
fURL . push ( trim ( yt _matches [ y ] ) ) ;
fThumb . push ( 'https://img.youtube.com/vi/' + trim ( yt _matches [ y ] . replace ( /(\w{3,5})(:)(\S+)((\.youtube\.com\/watch(\?v|\?\S+v|\#\!v|\#\!\S+v)\=)|(youtu\.be\/))([^& ]+)((&\S)|(&\S)|\s|$)/gim , '$8' ) ) + '/0.jpg' ) ;
}
// Send the message on the XMPP network
publishMicroblog ( body , fName , fURL , fType , fLength , fThumb ) ;
}
}
// Return false (security)
finally {
return false ;
}
}
// Publishes a given microblog item
function publishMicroblog ( body , attachedname , attachedurl , attachedtype , attachedlength , attachedthumb , repeat , comments _entity , comments _node , comments _entity _file , comments _node _file ) {
/* REF: http://xmpp.org/extensions/xep-0277.html */
// Generate some values
var time = getXMPPTime ( 'utc' ) ;
var id = hex _md5 ( body + time ) ;
var nick = getName ( ) ;
var xid = getXID ( ) ;
// Define repeat options
var author _nick = nick ;
var author _xid = xid ;
if ( repeat && repeat . length ) {
author _nick = repeat [ 0 ] ;
author _xid = repeat [ 1 ] ;
}
// Define comments options
var node _create = false ;
if ( ! comments _entity || ! comments _node ) {
node _create = true ;
comments _entity = HOST _PUBSUB ;
comments _node = NS _URN _MBLOG + ':comments/' + id ;
}
if ( ! comments _entity _file )
comments _entity _file = [ ] ;
if ( ! comments _node _file )
comments _node _file = [ ] ;
// Don't create another comments node if only 1 file is attached
if ( attachedurl && ( attachedurl . length == 1 ) && ( ! comments _entity _file [ 0 ] || ! comments _node _file [ 0 ] ) ) {
comments _entity _file = [ comments _entity ] ;
comments _node _file = [ comments _node ] ;
}
// New IQ
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
iq . setTo ( xid ) ;
// Create the main XML nodes/childs
var pubsub = iq . appendNode ( 'pubsub' , { 'xmlns' : NS _PUBSUB } ) ;
var publish = pubsub . appendChild ( iq . buildNode ( 'publish' , { 'node' : NS _URN _MBLOG , 'xmlns' : NS _PUBSUB } ) ) ;
var item = publish . appendChild ( iq . buildNode ( 'item' , { 'id' : id , 'xmlns' : NS _PUBSUB } ) ) ;
var entry = item . appendChild ( iq . buildNode ( 'entry' , { 'xmlns' : NS _ATOM } ) ) ;
// Create the XML source childs
var Source = entry . appendChild ( iq . buildNode ( 'source' , { 'xmlns' : NS _ATOM } ) ) ;
var author = Source . appendChild ( iq . buildNode ( 'author' , { 'xmlns' : NS _ATOM } ) ) ;
author . appendChild ( iq . buildNode ( 'name' , { 'xmlns' : NS _ATOM } , author _nick ) ) ;
author . appendChild ( iq . buildNode ( 'uri' , { 'xmlns' : NS _ATOM } , 'xmpp:' + author _xid ) ) ;
// Create the XML entry childs
entry . appendChild ( iq . buildNode ( 'content' , { 'type' : 'text' , 'xmlns' : NS _ATOM } , body ) ) ;
entry . appendChild ( iq . buildNode ( 'published' , { 'xmlns' : NS _ATOM } , time ) ) ;
entry . appendChild ( iq . buildNode ( 'updated' , { 'xmlns' : NS _ATOM } , time ) ) ;
entry . appendChild ( iq . buildNode ( 'link' , {
'rel' : 'alternate' ,
'href' : 'xmpp:' + xid + '?;node=' + encodeURIComponent ( NS _URN _MBLOG ) + ';item=' + encodeURIComponent ( id ) ,
'xmlns' : NS _ATOM
} ) ) ;
// Create the attached files nodes
for ( var i = 0 ; i < attachedurl . length ; i ++ ) {
// Not enough data?
if ( ! attachedurl [ i ] )
continue ;
// Append a new file element
var file = entry . appendChild ( iq . buildNode ( 'link' , { 'xmlns' : NS _ATOM , 'rel' : 'enclosure' , 'href' : attachedurl [ i ] } ) ) ;
// Add attributes
if ( attachedname [ i ] )
file . setAttribute ( 'title' , attachedname [ i ] ) ;
if ( attachedtype [ i ] )
file . setAttribute ( 'type' , attachedtype [ i ] ) ;
if ( attachedlength [ i ] )
file . setAttribute ( 'length' , attachedlength [ i ] ) ;
// Any thumbnail?
if ( attachedthumb [ i ] )
file . appendChild ( iq . buildNode ( 'link' , { 'xmlns' : NS _URN _MBLOG , 'rel' : 'self' , 'title' : 'thumb' , 'type' : attachedtype [ i ] , 'href' : attachedthumb [ i ] } ) ) ;
// Any comments node?
if ( ! comments _entity _file [ i ] || ! comments _node _file [ i ] ) {
// Generate values
comments _entity _file [ i ] = HOST _PUBSUB ;
comments _node _file [ i ] = NS _URN _MBLOG + ':comments/' + hex _md5 ( attachedurl [ i ] + attachedname [ i ] + attachedtype [ i ] + attachedlength [ i ] + time ) ;
// Create the node
setupMicroblog ( comments _entity _file [ i ] , comments _node _file [ i ] , '1' , '1000000' , 'open' , 'open' , true ) ;
}
file . appendChild ( iq . buildNode ( 'link' , { 'xmlns' : NS _URN _MBLOG , 'rel' : 'replies' , 'title' : 'comments_file' , 'href' : 'xmpp:' + comments _entity _file [ i ] + '?;node=' + encodeURIComponent ( comments _node _file [ i ] ) } ) ) ;
}
// Create the comments child
entry . appendChild ( iq . buildNode ( 'link' , { 'xmlns' : NS _ATOM , 'rel' : 'replies' , 'title' : 'comments' , 'href' : 'xmpp:' + comments _entity + '?;node=' + encodeURIComponent ( comments _node ) } ) ) ;
// Create the geoloc child
var geoloc _xml = getDB ( 'geolocation' , 'now' ) ;
if ( geoloc _xml ) {
// Create two position arrays
var geo _names = [ 'lat' , 'lon' , 'country' , 'countrycode' , 'region' , 'postalcode' , 'locality' , 'street' , 'building' , 'text' , 'uri' , 'timestamp' ] ;
var geo _values = parsePosition ( XMLFromString ( geoloc _xml ) ) ;
// New geoloc child
var geoloc = entry . appendChild ( iq . buildNode ( 'geoloc' , { 'xmlns' : NS _GEOLOC } ) ) ;
// Append the geoloc content
for ( var g = 0 ; g < geo _names . length ; g ++ ) {
if ( geo _names [ g ] && geo _values [ g ] )
geoloc . appendChild ( iq . buildNode ( geo _names [ g ] , { 'xmlns' : NS _GEOLOC } , geo _values [ g ] ) ) ;
}
}
// Send the IQ
con . send ( iq , handleMyMicroblog ) ;
// Create the XML comments PubSub nodes
if ( node _create )
setupMicroblog ( comments _entity , comments _node , '1' , '1000000' , 'open' , 'open' , true ) ;
return false ;
}
// Attaches a file to a microblog post
function attachMicroblog ( ) {
// File upload vars
var attach _options = {
dataType : 'xml' ,
beforeSubmit : waitMicroblogAttach ,
success : handleMicroblogAttach
} ;
// Upload form submit event
$ ( '#attach' ) . submit ( function ( ) {
if ( ! exists ( '#attach .wait' ) && $ ( '#attach input[type=file]' ) . val ( ) )
$ ( this ) . ajaxSubmit ( attach _options ) ;
return false ;
} ) ;
// Upload input change event
$ ( '#attach input[type=file]' ) . change ( function ( ) {
if ( ! exists ( '#attach .wait' ) && $ ( this ) . val ( ) )
$ ( '#attach' ) . ajaxSubmit ( attach _options ) ;
return false ;
} ) ;
}
// Unattaches a microblog file
function unattachMicroblog ( id ) {
// Individual removal?
if ( id )
$ ( '#attach .one-file[data-id=' + id + ']' ) . remove ( ) ;
else
$ ( '#attach .one-file' ) . remove ( ) ;
// Must enable the popup again?
if ( ! exists ( '#attach .one-file' ) ) {
// Restore the bubble class
$ ( '#attach' ) . addClass ( 'bubble' ) ;
// Enable the bubble click events
if ( id ) {
$ ( '#attach' ) . hide ( ) ;
showBubble ( '#attach' ) ;
}
else
closeBubbles ( ) ;
}
return false ;
}
// Wait event for file attaching
function waitMicroblogAttach ( ) {
// Append the wait icon
$ ( '#attach input[type=submit]' ) . after ( '<div class="wait wait-medium"></div>' ) ;
// Lock the bubble
$ ( '#attach' ) . removeClass ( 'bubble' ) ;
}
// Success event for file attaching
function handleMicroblogAttach ( responseXML ) {
// Data selector
var dData = $ ( responseXML ) . find ( 'jappix' ) ;
// Process the returned data
if ( ! dData . find ( 'error' ) . size ( ) ) {
// Do not allow this bubble to be hidden
$ ( '#attach' ) . removeClass ( 'bubble' ) ;
// Get the file values
var fName = dData . find ( 'title' ) . text ( ) ;
var fType = dData . find ( 'type' ) . text ( ) ;
var fLength = dData . find ( 'length' ) . text ( ) ;
var fURL = dData . find ( 'href' ) . text ( ) ;
var fThumb = dData . find ( 'thumb' ) . text ( ) ;
// Generate a file ID
var fID = hex _md5 ( fURL ) ;
// Add this file
$ ( '#attach .attach-subitem' ) . append (
'<div class="one-file" data-type="' + encodeQuotes ( fType ) + '" data-length="' + encodeQuotes ( fLength ) + '" data-thumb="' + encodeQuotes ( fThumb ) + '" data-id="' + fID + '">' +
'<a class="remove talk-images" href="#" title="' + encodeQuotes ( _e ( "Unattach the file" ) ) + '"></a>' +
'<a class="link" href="' + encodeQuotes ( fURL ) + '" target="_blank">' + fName . htmlEnc ( ) + '</a>' +
'</div>'
) ;
// Click event
$ ( '#attach .one-file[data-id=' + fID + '] a.remove' ) . click ( function ( ) {
return unattachMicroblog ( fID ) ;
} ) ;
logThis ( 'File attached.' , 3 ) ;
}
// Any error?
else {
openThisError ( 4 ) ;
// Unlock the bubble?
if ( ! exists ( '#attach .one-file' ) ) {
$ ( '#attach' ) . addClass ( 'bubble' ) . hide ( ) ;
// Show the bubble again!
showBubble ( '#attach' ) ;
}
logThis ( 'Error while attaching the file: ' + dData . find ( 'error' ) . text ( ) , 1 ) ;
}
// Reset the attach bubble
$ ( '#attach input[type=file]' ) . val ( '' ) ;
$ ( '#attach .wait' ) . remove ( ) ;
// Focus on the text input
$ ( document ) . oneTime ( 10 , function ( ) {
$ ( '#channel .top input[name=microblog_body]' ) . focus ( ) ;
} ) ;
}
// Shows the microblog of an user from his infos
function fromInfosMicroblog ( xid , hash ) {
// Renitialize the channel
resetMicroblog ( ) ;
// Switch to the channel
switchChan ( 'channel' ) ;
// Get the microblog
getMicroblog ( xid , hash ) ;
}
2018-01-20 11:01:59 -05:00
// Addon launcher
2012-04-17 19:12:24 -04:00
function launchMicroblog ( ) {
// Keyboard event
$ ( '#channel .top input[name=microblog_body]' ) . keyup ( function ( e ) {
// Enter pressed: send the microblog notice
if ( ( e . keyCode == 13 ) && ! exists ( '#attach .wait' ) )
return sendMicroblog ( ) ;
} )
// Placeholder
. placeholder ( ) ;
// Microblog file attacher
attachMicroblog ( ) ;
}