Commit cbbebc26 authored by 神楽坂玲奈's avatar 神楽坂玲奈

inline image

parent 9b868cbd
...@@ -37,9 +37,12 @@ $(document).ready -> ...@@ -37,9 +37,12 @@ $(document).ready ->
debug: false, debug: false,
autojoin: ['mycard@conference.my-card.in'], autojoin: ['mycard@conference.my-card.in'],
view: view:
resources: '/vendor/stylesheets/candy/', resources: '/vendor/candy/res/',
language: 'cn' language: 'cn'
) )
CandyShop.InlineImages.init();
Candy.View.Template.Chat.infoMessage = '' Candy.View.Template.Chat.infoMessage = ''
Candy.Core.connect('zh99998测试80@my-card.in', 'zh112998') if window.location.href.indexOf("candy") != -1 Candy.Core.connect('zh99998测试80@my-card.in', 'zh112998') if window.location.href.indexOf("candy") != -1
#window.onunload = window.onbeforeunload #window.onunload = window.onbeforeunload
......
...@@ -87,10 +87,11 @@ ...@@ -87,10 +87,11 @@
autojoin: ['mycard@conference.my-card.in'] autojoin: ['mycard@conference.my-card.in']
}, },
view: { view: {
resources: '/vendor/stylesheets/candy/', resources: '/vendor/candy/res/',
language: 'cn' language: 'cn'
} }
}); });
CandyShop.InlineImages.init();
Candy.View.Template.Chat.infoMessage = ''; Candy.View.Template.Chat.infoMessage = '';
if (window.location.href.indexOf("candy") !== -1) { if (window.location.href.indexOf("candy") !== -1) {
Candy.Core.connect('zh99998测试80@my-card.in', 'zh112998'); Candy.Core.connect('zh99998测试80@my-card.in', 'zh112998');
......
...@@ -56,9 +56,3 @@ body{background:#fbfbfb;} ...@@ -56,9 +56,3 @@ body{background:#fbfbfb;}
} }
} }
.online_title{height:20px;background:#f9f9f9;width:190px;font-size:14px;line-height:16px;padding:10px 10px;color:#147CC3;} .online_title{height:20px;background:#f9f9f9;width:190px;font-size:14px;line-height:16px;padding:10px 10px;color:#147CC3;}
...@@ -207,10 +207,14 @@ ...@@ -207,10 +207,14 @@
<script src="/vendor/javascripts/mycard.js"></script> <script src="/vendor/javascripts/mycard.js"></script>
<link rel="stylesheet" type="text/css" href="/vendor/stylesheets/candy/default.css"/> <link rel="stylesheet" type="text/css" href="/vendor/candy/res/default.css"/>
<script type="text/javascript" src="/vendor/javascripts/candy.libs.min.js"></script> <script type="text/javascript" src="/vendor/candy/libs/libs.min.js"></script>
<script type="text/javascript" src="/vendor/javascripts/candy.min.js"></script> <script type="text/javascript" src="/vendor/candy/candy.min.js"></script>
<script type="text/javascript" src="/vendor/javascripts/candy.fix.js"></script>
<script type="text/javascript" src="/assets/javascripts/candy.fix.js"></script>
<script type="text/javascript" src="/vendor/candy/plugins/inline-images/candy.js"></script>
<link rel="stylesheet" type="text/css" href="/vendor/candy/plugins/inline-images/candy.css" />
<script src="/assets/javascripts/rooms.js"></script> <script src="/assets/javascripts/rooms.js"></script>
......
<div class="wrapper">
<header>Header</header>
<article>
<div class="main">Main</div>
<aside class="aside">Aside</aside>
<aside class="sub">Sub</aside>
</article>
<footer>Footer</footer>
</div>
<style>header{ height:100px; margin-top: 10px; border: 1px solid #000;}
article{ height:100%; margin-top: 10px;}
footer{ height:50px; margin-top: 10px; border: 1px solid #000;}
article{ display:-webkit-box; display:-moz-box; display:box; width: 100%;}
.aside{ width: 150px; border: 1px solid #f00; -webkit-box-ordinal-group:0; -moz-box-ordinal-group:0; box-ordinal-group:0;}
.main{ -webkit-box-flex:1; -moz-box-flex:1; box-flex:1; -webkit-box-ordinal-group:1; -moz-box-ordinal-group:1; box-ordinal-group:1; margin: 0px 10px; border: 1px solid #f00;}
.sub{ width: 200px; border: 1px solid #f00; -webkit-box-ordinal-group:2; -moz-box-ordinal-group:2; box-ordinal-group:2;}
.wrapper{height:500px}
</style>
\ No newline at end of file
# Colors
Send and receive colored messages.
![Color Picker](/amiadogroup/candy-plugins/raw/master/colors/screenshot.png)
## Usage
To enable *Colors* you have to include its JavaScript code and stylesheet:
```HTML
<script type="text/javascript" src="candyshop/colors/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/colors/candy.css" />
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
// enable Colors plugin (default: 8 colors)
CandyShop.Colors.init();
Candy.Core.connect();
```
To enable less or more colors just call `CandyShop.Colors.init(<number-of-colors>)`.
\ No newline at end of file
#colors-control {
background: no-repeat url('colors-control.png');
position: relative;
}
#colors-control-indicator {
display: inline-block;
height: 6px;
width: 6px;
border: 1px solid white;
position: absolute;
top: 100%;
left: 100%;
margin: -8px 0 0 -8px;
}
#context-menu .colors {
padding-left: 5px;
width: 89px;
white-space: normal;
}
#context-menu .colors:hover {
background-color: inherit;
}
#context-menu .colors span {
display: inline-block;
width: 14px;
height: 14px;
border: 1px solid white;
margin: 3px;
}
.message-pane span.colored {
background-color: transparent !important;
}
.color-0 {
color: #333;
background-color: #333;
}
.color-1 {
color: #c4322b;
background-color: #c4322b;
}
.color-2 {
color: #37991e;
background-color: #37991e;
}
.color-3 {
color: #1654c9;
background-color: #1654c9;
}
.color-4 {
color: #66379b;
background-color: #66379b;
}
.color-5 {
color: #ba7318;
background-color: #ba7318;
}
.color-6 {
color: #32938a;
background-color: #32938a;
}
.color-7 {
color: #9e2274;
background-color: #9e2274;
}
.color-8 {
color: #4C82E4;
background-color: #4C82E4;
}
.color-9 {
color: #7F140E;
background-color: #7F140E;
}
.color-10 {
color: #1C630A;
background-color: #1C630A;
}
.color-11 {
color: #CF55A4;
background-color: #CF55A4;
}
\ No newline at end of file
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Colors = (function(self, Candy, $) {
var _numColors,
_currentColor = 0;
self.init = function(numColors) {
_numColors = numColors ? numColors : 8;
self.applyTranslations();
Candy.View.Event.Message.beforeSend = function(message) {
if(_currentColor > 0 && $.trim(message) !== '') {
return '|c:'+ _currentColor +'|' + message;
}
return message;
};
Candy.View.Event.Message.beforeShow = function(args) {
var message = ($.type(args) !== 'string') ? /* Candy >= 1.0.4 */ args.message : /* Candy < 1.0.4 */ args;
return message.replace(/^\|c:([0-9]{1,2})\|(.*)/gm, '<span class="colored color-$1">$2</span>');
};
if(Candy.Util.cookieExists('candyshop-colors-current')) {
var color = parseInt(Candy.Util.getCookie('candyshop-colors-current'), 10);
if(color > 0 && color < _numColors) {
_currentColor = color;
}
}
var html = '<li id="colors-control" data-tooltip="' + $.i18n._('candyshopColorsMessagecolor') + '"><span class="color-' + _currentColor + '" id="colors-control-indicator"></span></li>';
$('#emoticons-icon').after(html);
$('#colors-control').click(function(event) {
CandyShop.Colors.showPicker(this);
});
};
self.showPicker = function(elem) {
elem = $(elem);
var pos = elem.offset(),
menu = $('#context-menu'),
content = $('ul', menu),
colors = '',
i;
$('#tooltip').hide();
for(i = _numColors-1; i >= 0; i--) {
colors = '<span class="color-' + i + '" data-color="' + i + '"></span>' + colors;
}
content.html('<li class="colors">' + colors + '</li>');
content.find('span').click(function() {
_currentColor = $(this).attr('data-color');
$('#colors-control-indicator').attr('class', 'color-' + _currentColor);
Candy.Util.setCookie('candyshop-colors-current', _currentColor, 365);
Candy.View.Pane.Room.setFocusToForm(Candy.View.getCurrent().roomJid);
menu.hide();
});
var posLeft = Candy.Util.getPosLeftAccordingToWindowBounds(menu, pos.left),
posTop = Candy.Util.getPosTopAccordingToWindowBounds(menu, pos.top);
menu.css({'left': posLeft.px, 'top': posTop.px, backgroundPosition: posLeft.backgroundPositionAlignment + ' ' + posTop.backgroundPositionAlignment});
menu.fadeIn('fast');
return true;
};
self.applyTranslations = function() {
Candy.View.Translation.en.candyshopColorsMessagecolor = 'Message color';
Candy.View.Translation.ru.candyshopColorsMessagecolor = 'Цвет сообщения';
Candy.View.Translation.de.candyshopColorsMessagecolor = 'Farbe für Nachrichten';
Candy.View.Translation.fr.candyshopColorsMessagecolor = 'Couleur des messages';
Candy.View.Translation.nl.candyshopColorsMessagecolor = 'Berichtkleur';
Candy.View.Translation.es.candyshopColorsMessagecolor = 'Color de los mensajes';
};
return self;
}(CandyShop.Colors || {}, Candy, jQuery));
\ No newline at end of file
# Inline Images
If a user posts a URL to an image, that image gets rendered directly inside of Candy.
![Inline Images](/amiadogroup/candy-plugins/raw/master/inline-images/screenshot.png)
## Usage
Include the JavaScript and CSS files:
```HTML
<script type="text/javascript" src="candyshop/inline-images/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/inline-images/candy.css" />
```
To enable the Inline Images plugin, just add one of the ´init´ methods to your bootstrap:
```JavaScript
// init with default settings:
CandyShop.InlineImages.init();
// customized initialization:
CandyShop.InlineImages.initWithFileExtensions(['png','jpg']); // only recognize PNG and JPG files as image
CandyShop.InlineImages.initWithMaxImageSize(150); // resize images to a maximum edge size of 150px
CandyShop.InlineImages.initWithFileExtensionsAndMaxImageSize(['png','jpg'], 150); // combination of the above examples
```
\ No newline at end of file
.inlineimages-link {
text-decoration:none;
position:relative;
display:inline-block;
}
.inlineimages-link:hover:before {
content: url('overlay.png');
position: absolute;
top: 5px;
left: 5px;
opacity: .8;
}
\ No newline at end of file
/*
* inline-images
* @version 1.0
* @author Manuel Alabor (manuel@alabor.me)
*
* If a user posts a URL to an image, that image gets rendered directly
* inside of Candy.
*/
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.InlineImages = (function(self, Candy, $) {
var _fileExtensions = ['png','jpg','jpeg','gif']
,_originalLinkify = Candy.Util.Parser.linkify
,_maxImageSize = 100;
/** Function: init
* Initializes the inline-images plugin with the default settings.
*/
self.init = function() {
Candy.View.Event.Message.beforeShow = handleBeforeShow;
Candy.View.Event.Message.onShow = handleOnShow;
Candy.Util.Parser.linkify = linkify;
};
/** Function: initWithFileExtensions
* Initializes the inline-images plugin with the possibility to pass an
* array with all the file extensions you want to display as image.
*
* Parameters:
* (String array) fileExtensions - Array with extensions (jpg, png, ...)
*/
self.initWithFileExtensions = function(fileExtensions) {
_fileExtensions = fileExtensions;
init();
};
/** Function: initWithMaxImageSize
* Initializes the inline-images plugin with the possibility to pass the
* maximum image size for displayed images.
*
* Parameters:
* (int) maxImageSize - Maximum edge size for images
*/
self.initWithMaxImageSize = function(maxImageSize) {
_maxImageSize = maxImageSize;
init();
};
/** Function: initWithFileExtensionsAndMaxImageSize
* Initializes the inline-images plugin with the possibility to pass an
* array with all the file extensions you want to display as image and
* the maximum image size for displayed images.
*
* Parameters:
* (String array) fileExtensions - Array with extensions (jpg, png, ...)
* (int) maxImageSize - Maximum edge size for images
*/
self.initWithFileExtensionsAndMaxImageSize = function(fileExtensions, maxImageSize) {
_fileExtensions = fileExtensions;
_maxImageSize = maxImageSize;
init();
};
/** Function: handleBeforeShow
* Handles the beforeShow event of a message.
*
* Paramteres:
* (Object) args - {roomJid, element, nick, message}
*
* Returns:
* (String)
*/
var handleBeforeShow = function(args) {
var message = args.message;
var processed = message.replace(/\|[^\|]+\|/, "");
processed = processed.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi, '$1http://$2');
processed = processed.replace(/\b(https?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, replaceCallback);
return processed;
};
/** Function: handleOnShow
* Each time a message gets displayed, this method checks for possible
* image loaders (created by buildImageLoaderSource).
* If there is one, the image "behind" the loader gets loaded in the
* background. As soon as the image is loaded, the image loader gets
* replaced by proper scaled image.
*
* Parameters:
* (Array) args
*/
var handleOnShow = function(args) {
$('.inlineimages-loader').each(function(index, element) {
$(element).removeClass('inlineimages-loader');
var url = $(element).attr('longdesc');
var imageLoader = new Image();
$(imageLoader).load(function() {
var origWidth = this.width;
var origHeight = this.height;
var ratio = Math.min(_maxImageSize / origWidth, _maxImageSize / origHeight);
var width = Math.round(ratio * origWidth);
var height = Math.round(ratio * origHeight);
$(element).replaceWith(buildImageSource(url, width, height))
});
imageLoader.src = url;
});
}
/** Function: linkify
* Is used to overwrite the original Candy.Util.Parser.linkify.
* This implementation prevents the parsing of URL's by the Candy core.
* inline-images handles this on itself by handleBeforeShow.
*
* Parameters:
* (String) text - text to process
*
* Returns:
* (String)
*/
var linkify = function(text) {
return text;
}
/** Function: replaceCallback
* This callback handles matches from the URL regex.
* If the callback detects an image URL, it returns an image with a loading
* indicator. If it is just a common URL, a link-tag gets returned.
*
* Paramters:
* (String) match - matched URL
*
* Returns:
* (String)
*/
var replaceCallback = function(match) {
var result = match;
var dotPosition = match.lastIndexOf(".");
if(dotPosition > -1) {
if(_fileExtensions.indexOf(match.substr(dotPosition+1)) != -1) {
result = buildImageLoaderSource(match);
} else {
result = buildLinkSource(match);
}
}
return result;
}
/** Function: buildImageLoaderSource
* Returns a loader indicator. The handleOnShow method fullfills afterwards
* the effective image loading.
*
* Parameters:
* (String) url - image url
*
* Returns:
* (String)
*/
var buildImageLoaderSource = function(url) {
return '<img class="inlineimages-loader" longdesc="' + url + '" src="candy-plugins/inline-images/spinner.gif" />'
}
/** Function: buildImageSource
* Returns HTML source to show a URL as an image.
*
* Parameters:
* (String) url - image url
*
* Returns:
* (String)
*/
var buildImageSource = function(url, width, height) {
return '<a href="' + url + '" target="_blank" class="inlineimages-link"><img src="' + url + '" width="' + width + '" height="' + height + '"/></a>';
}
/** Function: buildLinkSource
* Returns HTML source to show a URL as a link.
*
* Parameters:
* (String) url - url
*
* Returns:
* (String)
*/
var buildLinkSource = function(url) {
return '<a href="' + url + '" target="_blank">' + url + '</a>';
}
return self;
}(CandyShop.InlineImages || {}, Candy, jQuery));
#Candy jQuery UI lightness Theme plugin
This plugin replaces the default theme with the jQuery UI lightness Theme. (http://jqueryui.com/)
##Usage
To enable jQuery UI lightness Theme you have to include its stylesheet:
```html
<link rel="stylesheet" type="text/css" href="candy/plugins/jquery-ui/ui-lightness/css/ui-lightness.css" />
```
\ No newline at end of file
html, body {
font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
}
div#candy {
background-color: #EEE;
}
div#candy div#chat-pane ul#chat-tabs {
background-image: url('../images/ui-bg_gloss-wave_35_f6a828_500x100.png');
background-repeat: repeat-x;
background-color: #F6A828;
}
div#candy div#chat-pane ul#chat-tabs li {
border-right: 1px solid #CCC;
}
div#candy div#chat-pane ul#chat-tabs li a {
color: #1C94C4;
}
div#candy div#chat-pane ul#chat-tabs li.active a {
color: #E78F08;
}
div#candy div#chat-pane ul#chat-tabs li.roomtype-chat small.unread {
background-color: #F6A828;
}
div#candy div#chat-pane ul#chat-tabs li.roomtype-groupchat small.unread {
background-color: #F6A828;
}
div#candy div#chat-pane ul#chat-toolbar {
background-color: #EEE;
border-top: 1px solid #DDD;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane form.message-form input.submit {
padding: 2px 5px 5px 5px;
background-color: #F6F6F6;
border: 1px solid #CCC;
border-radius: 4px;
color: #1C94C4;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane form.message-form input.submit:hover {
background-color: #FDF9E1;
border: 1px solid #FBCB09;
color: #E78F08;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.message-form-wrapper {
border-top: 1px solid #DDD;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.message-pane-wrapper dl.message-pane dd span.label a.name {
color: #888;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.message-pane-wrapper dl.message-pane dd.adminmessage {
color: #000;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.message-pane-wrapper dl.message-pane dd.subject {
color: #E78F08;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.roster-pane div.user {
background-color: #F8F8F8;
border: 1px solid #CCC;
border-radius: 4px;
color: #1C94C4;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.roster-pane div.user:hover {
cursor: pointer;
background-color: #FDF9E1;
border: 1px solid #FBCB09;
color: #E78F08;
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.roster-pane ul li.context {
background-image: url('../images/action/menu.png');
}
div#candy div#chat-pane div#chat-rooms.rooms div.room-pane div.roster-pane ul li.context:hover {
background-image: url('../images/action/menu-hover.png');
background-color: #F6A828;
}
#context-menu {
position: absolute;
z-index: 10;
display: none;
padding: 15px 10px;
margin: 8px -28px -8px -12px;
background: url('../images/context-arrows.gif') no-repeat left bottom;
}
#context-menu ul {
background-color: #F8F8F8;
border: 1px solid #CCC;
border-radius: 4px;
color: #1C94C4;
}
#context-menu li:hover {
background-color: #FDF9E1 !important;
color: #E78F08;
}
#chat-modal {
background: url('../images/modal-bg.png');
color: #000;
}
#chat-modal a#admin-message-cancel.close {
color: #000;
}
#chat-modal a#admin-message-cancel.close:hover {
background-color: #F6A828;
color: #FFF;
}
#chat-modal-overlay {
background-image: url('../images/overlay.png');
filter:alpha(opacity=50);
opacity: 0.5;
-moz-opacity:0.5;
}
#tooltip {
background: url('../images/tooltip-arrows.gif') no-repeat left bottom;
}
#tooltip div {
background-color: #F6A828;
color: #FFF;
}
\ No newline at end of file
# RoomPanel
Adds Icon show a lists rooms, also allows to show rooms upon connection and when all rooms are closed.
![RoomPanel](/amiadogroup/candy-plugins/raw/master/roomPanel/screenshot.png)
## Usage
To enable *RoomPanel* you have to include its JavaScript code and stylesheet:
```HTML
<script type="text/javascript" src="candyshop/roomPanel/roomPanel.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/roomPanel/default.css" />
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
// enable RoomPanel plugin
CandyShop.RoomPanel.init({
// domain that hosts the muc rooms, only required if autoDetectRooms is enabled
mucDomain: 'conference.yourdomain.com',
// allow you to force a list of rooms, only required if autoDetectRoom is disabled
roomList: [
{
name: 'my room',
jid: 'my-room@conference.yourdomain.com'
},
{
name: 'other room',
jid: 'other-room@conference.yourdomain.com'
}
],
// show room list if all rooms are closed, default value is true. [optional]
showIfAllTabClosed: true,
// detect rooms before showing list, default value is true. [optional]
autoDetectRooms: true,
// how long in seconds before refreshing room list, default value is 600. [optional]
roomCacheTime: 600
});
Candy.Core.connect();
.roomList a {
color: #000;
}
#roomPanel-control {
width: 16px;
background: url(images/room.png);
}
\ No newline at end of file
var CandyShop = (function(self) {return self;}(CandyShop || {}));
/**
* Class: Shows a list of rooms upon connection and adds a little icon to bring list of rooms
*/
CandyShop.RoomPanel = (function(self, Candy, Strophe, $) {
var _options = {
// domain that hosts the muc rooms, only required if autoDetectRooms is enabled
mucDomain: '',
// allow you to force a list of rooms, only required if autoDetectRoom is disabled
roomList: [],
// show room list if all rooms are closed, default value is true. [optional]
showIfAllTabClosed: true,
// detect rooms before showing list, default value is true. [optional]
autoDetectRooms: true,
// how long in seconds before refreshing room list, default value is 600. [optional]
roomCacheTime: 600
};
var _lastRoomUpdate = 0;
self.init = function(options) {
$.extend(_options, options);
self.applyTranslations();
/* Overwrite candy allTabsClosed function not
* to disconnect when all tags are closed */
if (_options.showIfAllTabClosed) {
Candy.View.Pane.Chat.allTabsClosed = function () {
CandyShop.RoomPanel.showRoomPanel();
return;
};
} //if
var html = '<li id="roomPanel-control" data-tooltip="' + $.i18n._('candyshopRoomPanelListRoom') + '"></li>';
$('#chat-toolbar').prepend(html);
$('#roomPanel-control').click(function() {
CandyShop.RoomPanel.showRoomPanel();
});
Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.CHAT, {update: function(obj, data) {
if (data.type == 'connection') {
if (Strophe.Status.CONNECTED == data.status) {
/* only show room window if not already in a room, timeout is to let some time for auto join to execute */
setTimeout(CandyShop.RoomPanel.showRoomPanelIfAllClosed, 500);
} //if
} //if
return true;
}});
};
self.showRoomPanelIfAllClosed = function() {
var roomCount = 0;
var rooms = Candy.Core.getRooms();
for (k in rooms) {
if (rooms.hasOwnProperty(k)) {
roomCount++;
} //if
} //for
if (roomCount == 0) {
CandyShop.RoomPanel.showRoomPanel();
} //if
}
self.updateRoomList = function (iq) {
var newRoomList = [];
$('item', iq).each(function (index, value) {
var name = $(value).attr('name');
var jid = $(value).attr('jid');
if (typeof name == 'undefined') {
name = jid.split('@')[0];
} //if
newRoomList.push({
name: name,
jid: jid
});
});
_options.roomList = newRoomList;
_lastRoomUpdate = Math.round(new Date().getTime() / 1000);
self.showRoomPanel();
};
self.showRoomPanel = function() {
/* call until connecting modal is gone */
if ($('#chat-modal').is(':visible')) {
setTimeout(CandyShop.RoomPanel.showRoomPanel, 100);
} else {
var timeDiff = Math.round(new Date().getTime() / 1000) - _options.roomCacheTime;
if (_options.autoDetectRooms && timeDiff > _lastRoomUpdate ) {
/* sends a request to get list of rooms user for the room */
var iq = $iq({type: 'get', from: Candy.Core.getUser().getJid(), to: _options.mucDomain , id: 'findRooms1'})
.c('query', {xmlns: Strophe.NS.DISCO_ITEMS});
Candy.Core.getConnection().sendIQ(iq, self.updateRoomList);
} else {
var html = Mustache.to_html(CandyShop.RoomPanel.Template.rooms, {
title: $.i18n._('candyshopRoomPanelChooseRoom'),
roomList: _options.roomList
});
Candy.View.Pane.Chat.Modal.show(html,true);
$('.roomList a').bind('click', function(e) {
var roomJid = this.href.split('#')[1];
Candy.Core.Action.Jabber.Room.Join(roomJid);
Candy.View.Pane.Chat.Modal.hide();
e.preventDefault();
});
} //if
} //if
return true;
};
self.applyTranslations = function() {
Candy.View.Translation.en.candyshopRoomPanelListRoom = 'List Rooms';
Candy.View.Translation.ru.candyshopRoomPanelListRoom = 'Список комнат';
Candy.View.Translation.de.candyshopRoomPanelListRoom = 'Verfügbare Räume anzeigen';
Candy.View.Translation.fr.candyshopRoomPanelListRoom = 'Liste des salles';
Candy.View.Translation.nl.candyshopRoomPanelListRoom = 'List Rooms';
Candy.View.Translation.es.candyshopRoomPanelListRoom = 'List Rooms';
Candy.View.Translation.en.candyshopRoomPanelChooseRoom = 'Choose Room To Join';
Candy.View.Translation.ru.candyshopRoomPanelChooseRoom = 'Выберите комнату ';
Candy.View.Translation.de.candyshopRoomPanelChooseRoom = 'Verfügbare Räume';
Candy.View.Translation.fr.candyshopRoomPanelChooseRoom = 'Choisir une salle';
Candy.View.Translation.nl.candyshopRoomPanelChooseRoom = 'Choose Room To Join';
Candy.View.Translation.es.candyshopRoomPanelChooseRoom = 'Choose Room To Join';
};
return self;
}(CandyShop.RoomPanel || {}, Candy, Strophe, jQuery));
CandyShop.RoomPanel.Template = (function (self) {
var roomParts = [
'<div class="roomList">',
'<h2>{{title}}</h2>',
'<ul>',
'{{#roomList}}',
'<li><a href="#{{jid}}">{{name}}</a></li>',
'{{/roomList}}',
'</ul>',
'</div>'
];
self.rooms = roomParts.join('');
return self;
})(CandyShop.RoomPanel.Template || {});
\ No newline at end of file
#Candy Timeago plugin
This plugin replaces the exact time/date with 'fuzzy timestamps' (e.g. 'less than a minute ago', '2 minutes ago', 'about an hour ago'). The timestamps update dynamically. All the heavy lifting is done by Ryan McGeary's excellent jQuery Timeago plugin (http://timeago.yarp.com/).
##Usage
To enable Timeago include it's JavaScript code and CSS file (after the main Candy script and CSS):
```html
<script type="text/javascript" src="candyshop/timeago/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/timeago/candy.css" />
```
Then call its init() method after Candy has been initialized:
```html
Candy.init('/http-bind/');
CandyShop.Timeago.init();
Candy.Core.connect();
```
\ No newline at end of file
.message-pane dt {
width: 120px;
padding-right: 10px;
}
.message-pane dt abbr {
border-bottom: none;
}
\ No newline at end of file
/*
* candy-timeago-plugin
* @version 0.1 (2011-07-15)
* @author David Devlin (dave.devlin@gmail.com)
*
* Integrates the jQuery Timeago plugin (http://timeago.yarp.com/) with Candy.
*/
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Timeago = (function(self, Candy, $) {
self.init = function() {
Candy.View.Template.Chat['adminMessage'] = '<dt><abbr title="{{time}}">{{time}}</abbr></dt><dd class="adminmessage"><span class="label">{{sender}}</span>{{subject}} {{message}}</dd>';
Candy.View.Template.Chat['infoMessage'] = '<dt><abbr title="{{time}}">{{time}}</abbr></dt><dd class="infomessage">{{subject}} {{message}}</dd>';
Candy.View.Template.Room['subject'] = '<dt><abbr title="{{time}}">{{time}}</abbr></dt><dd class="subject"><span class="label">{{roomName}}</span>{{_roomSubject}} {{subject}}</dd>';
Candy.View.Template.Message['item'] = '<dt><abbr title="{{time}}">{{time}}</abbr></dt><dd><span class="label"><a href="#" class="name">{{displayName}}</a></span>{{{message}}}</dd>';
Candy.Util.localizedTime = function(dateTime) {
if (dateTime === undefined) {
return undefined;
}
var date = Candy.Util.iso8601toDate(dateTime);
return date.format($.i18n._('isoDateTime'));
};
Candy.View.Event.Message.onShow = function(message) {
$('abbr').timeago();
};
Candy.View.Event.Chat.onAdminMessage = function(message) {
$('abbr').timeago();
};
Candy.View.Event.Room.onSubjectChange = function(message) {
$('abbr').timeago();
};
Candy.View.Event.Room.onPresenceChange = function(message) {
$('abbr').timeago();
};
};
return self;
}(CandyShop.Timeago || {}, Candy, jQuery));
/*
* timeago: a jQuery plugin, version: 0.9.3 (2011-01-21)
* @requires jQuery v1.2.3 or later
*
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
*/
(function($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowFuture: false,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
numbers: []
}
},
inWords: function(distanceMillis) {
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
distanceMillis = Math.abs(distanceMillis);
}
var seconds = distanceMillis / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 48 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.floor(days)) ||
days < 60 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.floor(days / 30)) ||
years < 2 && substitute($l.year, 1) ||
substitute($l.years, Math.floor(years));
return $.trim([prefix, words, suffix].join(" "));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
return new Date(s);
},
datetime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
}
});
$.fn.timeago = function() {
var self = this;
self.each(refresh);
var $s = $t.settings;
if ($s.refreshMillis > 0) {
setInterval(function() { self.each(refresh); }, $s.refreshMillis);
}
return self;
};
function refresh() {
var data = prepareData(this);
if (!isNaN(data.datetime)) {
$(this).text(inWords(data.datetime));
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if (text.length > 0) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}(jQuery));
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment