2015-06-14 23:53:32 -08:00
|
|
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
|
|
|
|
// See License.txt for license information.
|
|
|
|
|
|
|
|
|
|
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
2015-07-01 12:41:36 -07:00
|
|
|
var ChannelStore = require('../stores/channel_store.jsx')
|
2015-06-14 23:53:32 -08:00
|
|
|
var UserStore = require('../stores/user_store.jsx');
|
|
|
|
|
var Constants = require('../utils/constants.jsx');
|
|
|
|
|
var ActionTypes = Constants.ActionTypes;
|
|
|
|
|
var AsyncClient = require('./async_client.jsx');
|
|
|
|
|
var client = require('./client.jsx');
|
2015-07-07 09:24:42 -07:00
|
|
|
var Autolinker = require('autolinker');
|
2015-07-08 11:34:34 -07:00
|
|
|
var formatText = require('../../static/js/marked/lib/marked.js');
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
module.exports.isEmail = function(email) {
|
|
|
|
|
var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
|
|
|
|
|
return regex.test(email);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
module.exports.cleanUpUrlable = function(input) {
|
2015-07-08 11:50:10 -04:00
|
|
|
var cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-');
|
|
|
|
|
cleaned = cleaned.replace(/^\-+/, '');
|
|
|
|
|
cleaned = cleaned.replace(/\-+$/, '');
|
|
|
|
|
return cleaned;
|
2015-06-14 23:53:32 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
module.exports.isTestDomain = function() {
|
|
|
|
|
|
|
|
|
|
if ((/^localhost/).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-06-18 10:55:51 -08:00
|
|
|
if ((/^dockerhost/).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
if ((/^test/).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((/^127.0./).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((/^192.168./).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((/^10./).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((/^176./).test(window.location.hostname))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var getSubDomain = function() {
|
|
|
|
|
|
|
|
|
|
if (module.exports.isTestDomain())
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
if ((/^www/).test(window.location.hostname))
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
if ((/^beta/).test(window.location.hostname))
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
if ((/^ci/).test(window.location.hostname))
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
var parts = window.location.hostname.split(".");
|
|
|
|
|
|
|
|
|
|
if (parts.length != 3)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
return parts[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global.window.getSubDomain = getSubDomain;
|
|
|
|
|
module.exports.getSubDomain = getSubDomain;
|
|
|
|
|
|
|
|
|
|
module.exports.getDomainWithOutSub = function() {
|
|
|
|
|
|
|
|
|
|
var parts = window.location.host.split(".");
|
|
|
|
|
|
2015-06-18 10:55:51 -08:00
|
|
|
if (parts.length == 1) {
|
|
|
|
|
if (parts[0].indexOf("dockerhost") > -1) {
|
|
|
|
|
return "dockerhost:8065";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return "localhost:8065";
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
return parts[1] + "." + parts[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getCookie = function(name) {
|
|
|
|
|
var value = "; " + document.cookie;
|
|
|
|
|
var parts = value.split("; " + name + "=");
|
|
|
|
|
if (parts.length == 2) return parts.pop().split(";").shift();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.notifyMe = function(title, body, channel) {
|
2015-07-08 11:34:34 -07:00
|
|
|
if ("Notification" in window && Notification.permission !== 'denied') {
|
2015-06-14 23:53:32 -08:00
|
|
|
Notification.requestPermission(function (permission) {
|
|
|
|
|
if (Notification.permission !== permission) {
|
|
|
|
|
Notification.permission = permission;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (permission === "granted") {
|
|
|
|
|
var notification = new Notification(title,
|
|
|
|
|
{ body: body, tag: body, icon: '/static/images/icon50x50.gif' }
|
|
|
|
|
);
|
|
|
|
|
notification.onclick = function() {
|
|
|
|
|
window.focus();
|
|
|
|
|
if (channel) {
|
|
|
|
|
module.exports.switchChannel(channel);
|
|
|
|
|
} else {
|
2015-07-08 11:50:10 -04:00
|
|
|
window.location.href = "/";
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
setTimeout(function(){
|
|
|
|
|
notification.close();
|
|
|
|
|
}, 5000);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.ding = function() {
|
|
|
|
|
var audio = new Audio('/static/images/ding.mp3');
|
|
|
|
|
audio.play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getUrlParameter = function(sParam) {
|
|
|
|
|
var sPageURL = window.location.search.substring(1);
|
|
|
|
|
var sURLVariables = sPageURL.split('&');
|
|
|
|
|
for (var i = 0; i < sURLVariables.length; i++)
|
|
|
|
|
{
|
|
|
|
|
var sParameterName = sURLVariables[i].split('=');
|
|
|
|
|
if (sParameterName[0] == sParam)
|
|
|
|
|
{
|
|
|
|
|
return sParameterName[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getDateForUnixTicks = function(ticks) {
|
|
|
|
|
return new Date(ticks)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.displayDate = function(ticks) {
|
|
|
|
|
var d = new Date(ticks);
|
|
|
|
|
var m_names = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
|
|
|
|
|
|
|
|
|
|
return m_names[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.displayTime = function(ticks) {
|
|
|
|
|
var d = new Date(ticks);
|
|
|
|
|
var hours = d.getHours();
|
|
|
|
|
var minutes = d.getMinutes();
|
|
|
|
|
var ampm = hours >= 12 ? "PM" : "AM";
|
|
|
|
|
hours = hours % 12;
|
|
|
|
|
hours = hours ? hours : "12"
|
|
|
|
|
minutes = minutes > 9 ? minutes : '0'+minutes
|
|
|
|
|
return hours + ":" + minutes + " " + ampm
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.displayDateTime = function(ticks) {
|
|
|
|
|
var seconds = Math.floor((Date.now() - ticks) / 1000)
|
|
|
|
|
|
|
|
|
|
interval = Math.floor(seconds / 3600);
|
|
|
|
|
|
|
|
|
|
if (interval > 24) {
|
|
|
|
|
return this.displayTime(ticks)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (interval > 1) {
|
|
|
|
|
return interval + " hours ago";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (interval == 1) {
|
|
|
|
|
return interval + " hour ago";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interval = Math.floor(seconds / 60);
|
|
|
|
|
if (interval > 1) {
|
|
|
|
|
return interval + " minutes ago";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "1 minute ago";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// returns Unix timestamp in milliseconds
|
|
|
|
|
module.exports.getTimestamp = function() {
|
|
|
|
|
return Date.now();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 09:24:42 -07:00
|
|
|
var testUrlMatch = function(text) {
|
2015-07-16 14:22:15 -07:00
|
|
|
var urlMatcher = new Autolinker.matchParser.MatchParser({
|
|
|
|
|
urls: true,
|
|
|
|
|
emails: false,
|
|
|
|
|
twitter: false,
|
|
|
|
|
phone: false,
|
|
|
|
|
hashtag: false,
|
|
|
|
|
});
|
2015-07-07 09:24:42 -07:00
|
|
|
var result = [];
|
|
|
|
|
var replaceFn = function(match) {
|
|
|
|
|
var linkData = {};
|
|
|
|
|
var matchText = match.getMatchedText();
|
|
|
|
|
|
|
|
|
|
linkData.text = matchText;
|
|
|
|
|
linkData.link = matchText.trim().indexOf("http") !== 0 ? "http://" + matchText : matchText;
|
|
|
|
|
|
|
|
|
|
result.push(linkData);
|
|
|
|
|
}
|
|
|
|
|
urlMatcher.replace(text,replaceFn,this);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
module.exports.extractLinks = function(text) {
|
|
|
|
|
var repRegex = new RegExp("<br>", "g");
|
2015-07-07 09:24:42 -07:00
|
|
|
var matches = testUrlMatch(text.replace(repRegex, "\n"));
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-07-08 10:32:33 -07:00
|
|
|
if (!matches.length) return { "links": null, "text": text };
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-07-08 10:32:33 -07:00
|
|
|
var links = [];
|
2015-06-14 23:53:32 -08:00
|
|
|
for (var i = 0; i < matches.length; i++) {
|
2015-07-08 10:32:33 -07:00
|
|
|
links.push(matches[i].link);
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { "links": links, "text": text };
|
2015-07-11 08:32:02 -07:00
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
module.exports.escapeRegExp = function(string) {
|
|
|
|
|
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getEmbed = function(link) {
|
|
|
|
|
|
|
|
|
|
var ytRegex = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|watch\?(?:[a-zA-Z-_]+=[a-zA-Z0-9-_]+&)+v=)([^#\&\?]*).*/;
|
|
|
|
|
|
|
|
|
|
var match = link.trim().match(ytRegex);
|
|
|
|
|
if (match && match[1].length==11){
|
|
|
|
|
return getYoutubeEmbed(link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generl embed feature turned off for now
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var id = parseInt((Math.random() * 1000000) + 1);
|
|
|
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
|
type: 'GET',
|
|
|
|
|
url: "https://query.yahooapis.com/v1/public/yql",
|
|
|
|
|
data: {
|
|
|
|
|
q: "select * from html where url=\""+link+"\" and xpath='html/head'",
|
|
|
|
|
format: "json"
|
|
|
|
|
},
|
|
|
|
|
async: true
|
|
|
|
|
}).done(function(data) {
|
|
|
|
|
if(!data.query.results) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var headerData = data.query.results.head;
|
|
|
|
|
|
|
|
|
|
var description = ""
|
|
|
|
|
for(var i = 0; i < headerData.meta.length; i++) {
|
|
|
|
|
if(headerData.meta[i].name && (headerData.meta[i].name === "description" || headerData.meta[i].name === "Description")){
|
|
|
|
|
description = headerData.meta[i].content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$('.embed-title.'+id).html(headerData.title);
|
|
|
|
|
$('.embed-description.'+id).html(description);
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="post-comment">
|
|
|
|
|
<div className={"web-embed-data"}>
|
|
|
|
|
<p className={"embed-title " + id} />
|
|
|
|
|
<p className={"embed-description " + id} />
|
|
|
|
|
<p className={"embed-link " + id}>{link}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var getYoutubeEmbed = function(link) {
|
|
|
|
|
var regex = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|watch\?(?:[a-zA-Z-_]+=[a-zA-Z0-9-_]+&)+v=)([^#\&\?]*).*/;
|
|
|
|
|
|
|
|
|
|
var youtubeId = link.trim().match(regex)[1];
|
|
|
|
|
|
|
|
|
|
var onclick = function(e) {
|
|
|
|
|
var div = $(e.target).closest('.video-thumbnail__container')[0];
|
|
|
|
|
var iframe = document.createElement("iframe");
|
|
|
|
|
iframe.setAttribute("src",
|
|
|
|
|
"https://www.youtube.com/embed/" + div.id
|
|
|
|
|
+ "?autoplay=1&autohide=1&border=0&wmode=opaque&enablejsapi=1");
|
|
|
|
|
iframe.setAttribute("width", "480px");
|
|
|
|
|
iframe.setAttribute("height", "360px");
|
|
|
|
|
iframe.setAttribute("type", "text/html");
|
|
|
|
|
iframe.setAttribute("frameborder", "0");
|
|
|
|
|
|
|
|
|
|
div.parentNode.replaceChild(iframe, div);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var success = function(data) {
|
2015-07-14 11:55:49 -07:00
|
|
|
if(!data.items.length || !data.items[0].snippet) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-15 09:13:34 -07:00
|
|
|
var metadata = data.items[0].snippet;
|
2015-07-14 11:55:49 -07:00
|
|
|
$('.video-uploader.'+youtubeId).html(metadata.channelTitle);
|
|
|
|
|
$('.video-title.'+youtubeId).find('a').html(metadata.title);
|
2015-06-14 23:53:32 -08:00
|
|
|
$(".post-list-holder-by-time").scrollTop($(".post-list-holder-by-time")[0].scrollHeight);
|
|
|
|
|
$(".post-list-holder-by-time").perfectScrollbar('update');
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-14 11:55:49 -07:00
|
|
|
if(config.GoogleDeveloperKey) {
|
|
|
|
|
$.ajax({
|
|
|
|
|
async: true,
|
|
|
|
|
url: "https://www.googleapis.com/youtube/v3/videos",
|
|
|
|
|
type: 'GET',
|
|
|
|
|
data: {part:"snippet", id:youtubeId, key:config.GoogleDeveloperKey},
|
|
|
|
|
success: success
|
|
|
|
|
});
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="post-comment">
|
|
|
|
|
<h4 className="video-type">YouTube</h4>
|
|
|
|
|
<h4 className={"video-uploader "+youtubeId}></h4>
|
|
|
|
|
<h4 className={"video-title "+youtubeId}><a href={link}></a></h4>
|
|
|
|
|
<div className="video-div embed-responsive-item" id={youtubeId} onClick={onclick}>
|
|
|
|
|
<div className="embed-responsive embed-responsive-4by3 video-div__placeholder">
|
|
|
|
|
<div id={youtubeId} className="video-thumbnail__container">
|
|
|
|
|
<img className="video-thumbnail" src={"https://i.ytimg.com/vi/" + youtubeId + "/hqdefault.jpg"}/>
|
|
|
|
|
<div className="block">
|
|
|
|
|
<span className="play-button"><span></span></span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.areStatesEqual = function(state1, state2) {
|
|
|
|
|
return JSON.stringify(state1) === JSON.stringify(state2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.replaceHtmlEntities = function(text) {
|
|
|
|
|
var tagsToReplace = {
|
|
|
|
|
'&': '&',
|
|
|
|
|
'<': '<',
|
|
|
|
|
'>': '>'
|
|
|
|
|
};
|
|
|
|
|
for (var tag in tagsToReplace) {
|
|
|
|
|
var regex = new RegExp(tag, "g");
|
|
|
|
|
text = text.replace(regex, tagsToReplace[tag]);
|
|
|
|
|
}
|
|
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.insertHtmlEntities = function(text) {
|
|
|
|
|
var tagsToReplace = {
|
|
|
|
|
'&': '&',
|
|
|
|
|
'<': '<',
|
|
|
|
|
'>': '>'
|
|
|
|
|
};
|
|
|
|
|
for (var tag in tagsToReplace) {
|
|
|
|
|
var regex = new RegExp(tag, "g");
|
|
|
|
|
text = text.replace(regex, tagsToReplace[tag]);
|
|
|
|
|
}
|
|
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.searchForTerm = function(term) {
|
|
|
|
|
AppDispatcher.handleServerAction({
|
|
|
|
|
type: ActionTypes.RECIEVED_SEARCH_TERM,
|
|
|
|
|
term: term,
|
|
|
|
|
do_search: true
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 11:34:34 -07:00
|
|
|
/* Options:
|
|
|
|
|
- disable: Parses out *'s and other format specifiers in the text, but doesn't convert to html
|
|
|
|
|
*/
|
|
|
|
|
module.exports.customMarkedRenderer = function(options) {
|
|
|
|
|
var customTextRenderer = new formatText.Renderer();
|
|
|
|
|
if (options && options.disable) {
|
|
|
|
|
customTextRenderer.paragraph = function(text) {
|
|
|
|
|
return text + ' ';
|
|
|
|
|
};
|
|
|
|
|
customTextRenderer.strong = function(text) {
|
|
|
|
|
return text;
|
|
|
|
|
};
|
|
|
|
|
customTextRenderer.em = function(text) {
|
|
|
|
|
return text;
|
|
|
|
|
};
|
|
|
|
|
customTextRenderer.codespan = function(code) {
|
|
|
|
|
return code;
|
|
|
|
|
};
|
2015-08-10 16:44:54 -07:00
|
|
|
customTextRenderer.link = function(href) {
|
2015-07-08 11:34:34 -07:00
|
|
|
return href;
|
|
|
|
|
};
|
2015-08-10 16:44:54 -07:00
|
|
|
customTextRenderer.image = function(href) {
|
2015-07-08 11:34:34 -07:00
|
|
|
return href;
|
|
|
|
|
};
|
|
|
|
|
} else {
|
2015-08-10 16:44:54 -07:00
|
|
|
customTextRenderer.link = function(href) {
|
2015-07-08 11:34:34 -07:00
|
|
|
return href;
|
|
|
|
|
};
|
2015-08-10 16:44:54 -07:00
|
|
|
customTextRenderer.image = function(href) {
|
2015-07-08 11:34:34 -07:00
|
|
|
return href;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return customTextRenderer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var puncStartRegex = /^((?![@#])[^A-Za-z0-9_<>])+/g;
|
|
|
|
|
var puncEndRegex = /([^A-Za-z0-9_<>])+$/g;
|
|
|
|
|
var startTagRegex = /(<\s*\w.*?>)+/g;
|
|
|
|
|
var endTagRegex = /(<\s*\/\s*\w\s*.*?>|<\s*br\s*>)+/g;
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
module.exports.textToJsx = function(textToChange, options) {
|
2015-07-08 11:34:34 -07:00
|
|
|
var useTextFormatting = config.AllowTextFormatting && (!options || !options.noTextFormatting);
|
2015-08-10 16:44:54 -07:00
|
|
|
var text = textToChange;
|
2015-07-08 11:34:34 -07:00
|
|
|
|
|
|
|
|
if (useTextFormatting) {
|
|
|
|
|
text = formatText(text, {sanitize: true, mangle: false, gfm: true, breaks: true, tables: false, smartypants: true, renderer: module.exports.customMarkedRenderer()});
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
if (options && options.singleline) {
|
|
|
|
|
var repRegex = new RegExp('\n', 'g');
|
|
|
|
|
text = text.replace(repRegex, ' ');
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
var searchTerm = '';
|
|
|
|
|
if (options && options.searchTerm) {
|
|
|
|
|
searchTerm = options.searchTerm.toLowerCase();
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
var mentionClass = 'mention-highlight';
|
|
|
|
|
if (options && options.noMentionHighlight) {
|
|
|
|
|
mentionClass = '';
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var inner = [];
|
2015-07-08 11:34:34 -07:00
|
|
|
var codeFlag = false;
|
|
|
|
|
var codeString = '';
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-06-30 11:56:55 -07:00
|
|
|
// Function specific regex
|
|
|
|
|
var hashRegex = /^href="#[^"]+"|(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$/g;
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-06-30 15:00:57 -07:00
|
|
|
var implicitKeywords = UserStore.getCurrentMentionKeys();
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
var lines = text.split('\n');
|
2015-06-14 23:53:32 -08:00
|
|
|
for (var i = 0; i < lines.length; i++) {
|
|
|
|
|
var line = lines[i];
|
2015-08-10 16:44:54 -07:00
|
|
|
var words = line.split(' ');
|
|
|
|
|
var highlightSearchClass = '';
|
2015-06-14 23:53:32 -08:00
|
|
|
for (var z = 0; z < words.length; z++) {
|
|
|
|
|
var word = words[z];
|
2015-07-08 11:34:34 -07:00
|
|
|
var trimWord;
|
|
|
|
|
if (useTextFormatting) {
|
|
|
|
|
trimWord = word.replace(endTagRegex, '').replace(startTagRegex, '').replace(puncStartRegex, '').replace(puncEndRegex, '').trim();
|
|
|
|
|
} else {
|
|
|
|
|
trimWord = word.replace(puncStartRegex, '').replace(puncEndRegex, '').trim();
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
var mentionRegex = /^(?:@)([a-z0-9_]+)$/gi; // looks loop invariant but a weird JS bug needs it to be redefined here
|
|
|
|
|
var explicitMention = mentionRegex.exec(trimWord);
|
2015-08-10 16:44:54 -07:00
|
|
|
var mClass;
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
var prefix = '';
|
|
|
|
|
var suffix = '';
|
|
|
|
|
var prefixSpan = null;
|
|
|
|
|
var suffixSpan = <span key={word + i + z + 'suf_span'}> </span>;
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting) {
|
2015-08-10 16:44:54 -07:00
|
|
|
if (word.match(startTagRegex)) {
|
|
|
|
|
prefix += word.match(startTagRegex);
|
|
|
|
|
}
|
|
|
|
|
if (word.replace(startTagRegex, '').match(puncStartRegex)) {
|
|
|
|
|
prefix += word.replace(startTagRegex, '').match(puncStartRegex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (word.match(endTagRegex)) {
|
|
|
|
|
suffix += word.match(endTagRegex);
|
|
|
|
|
}
|
|
|
|
|
if (word.replace(endTagRegex, '').match(puncEndRegex)) {
|
|
|
|
|
suffix += word.replace(endTagRegex, '').match(puncEndRegex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prefix) {
|
|
|
|
|
prefixSpan = <span key={word + i + z + 'pre_span'}><span dangerouslySetInnerHTML={{__html: prefix}} /></span>;
|
|
|
|
|
}
|
|
|
|
|
if (suffix) {
|
|
|
|
|
suffixSpan = <span key={word + i + z + 'suf_span'}><span dangerouslySetInnerHTML={{__html: suffix}} /> </span>;
|
|
|
|
|
}
|
2015-07-08 11:34:34 -07:00
|
|
|
} else {
|
|
|
|
|
prefix = word.match(puncStartRegex);
|
|
|
|
|
suffix = word.match(puncEndRegex);
|
2015-08-10 16:44:54 -07:00
|
|
|
if (prefix) {
|
|
|
|
|
prefixSpan = <span key={word + i + z + 'pre_span'}>{prefix}</span>;
|
|
|
|
|
}
|
|
|
|
|
if (suffix) {
|
|
|
|
|
suffixSpan = <span key={word + i + z + 'suf_span'}>{suffix} </span>;
|
|
|
|
|
}
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm !== '') {
|
|
|
|
|
highlightSearchClass = ' search-highlight';
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting && (codeFlag || word.indexOf('<code>') !== -1)) {
|
|
|
|
|
codeString += word + ' ';
|
|
|
|
|
codeFlag = true;
|
|
|
|
|
|
|
|
|
|
if (word.indexOf('</code>') !== -1) {
|
2015-08-10 16:44:54 -07:00
|
|
|
inner.push(<span key={word + i + z + '_span'} className={highlightSearchClass} dangerouslySetInnerHTML={{__html: codeString}} />);
|
2015-07-08 11:34:34 -07:00
|
|
|
codeString = '';
|
|
|
|
|
codeFlag = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (explicitMention &&
|
2015-08-10 16:44:54 -07:00
|
|
|
(UserStore.getProfileByUsername(explicitMention[1]) ||
|
|
|
|
|
Constants.SPECIAL_MENTIONS.indexOf(explicitMention[1]) !== -1)) {
|
2015-06-14 23:53:32 -08:00
|
|
|
var name = explicitMention[1];
|
2015-08-10 16:44:54 -07:00
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
// do both a non-case sensitive and case senstive check
|
2015-08-10 16:44:54 -07:00
|
|
|
mClass = '';
|
|
|
|
|
if (implicitKeywords.indexOf('@' + name.toLowerCase()) !== -1 || implicitKeywords.indexOf('@' + name) !== -1) {
|
|
|
|
|
mClass = mentionClass;
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
if (searchTerm === name) {
|
2015-08-10 16:44:54 -07:00
|
|
|
highlightSearchClass = ' search-highlight';
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting) {
|
2015-08-10 16:44:54 -07:00
|
|
|
if (prefixSpan) {
|
|
|
|
|
inner.push(prefixSpan);
|
|
|
|
|
}
|
|
|
|
|
inner.push(<span key={word + i + z + 'word_span'}><a className={mClass + highlightSearchClass + ' mention-link'} key={name + i + z + '_link'} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(name)}>{'@' + name}</a></span>);
|
|
|
|
|
if (suffixSpan) {
|
|
|
|
|
inner.push(suffixSpan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={name + i + z + '_span'}>{prefix}<a className={mClass + highlightSearchClass + ' mention-link'} key={name + i + z + '_link'} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(name)}>@{name}</a>{suffix} </span>);
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-07-07 09:24:42 -07:00
|
|
|
} else if (testUrlMatch(word).length) {
|
|
|
|
|
var match = testUrlMatch(word)[0];
|
2015-07-08 10:32:33 -07:00
|
|
|
var link = match.link;
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-08-10 16:44:54 -07:00
|
|
|
prefix = word.substring(0, word.indexOf(match.text));
|
|
|
|
|
suffix = word.substring(word.indexOf(match.text) + match.text.length);
|
|
|
|
|
if (prefix) {
|
|
|
|
|
prefixSpan = <span key={word + i + z + 'pre_span'}><span dangerouslySetInnerHTML={{__html: prefix}} /></span>;
|
|
|
|
|
}
|
|
|
|
|
if (suffix) {
|
|
|
|
|
suffixSpan = <span key={word + i + z + 'suf_span'}><span dangerouslySetInnerHTML={{__html: suffix}} /> </span>;
|
|
|
|
|
} else {
|
|
|
|
|
suffixSpan = <span key={word + i + z + 'suf_span'}> </span>;
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting) {
|
2015-08-10 16:44:54 -07:00
|
|
|
if (prefixSpan) {
|
|
|
|
|
inner.push(prefixSpan);
|
|
|
|
|
}
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}><a key={name + i + z + '_link'} className={'theme' + highlightSearchClass} target='_blank' href={link}>{match.text}</a></span>);
|
|
|
|
|
if (suffixSpan) {
|
|
|
|
|
inner.push(suffixSpan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}>{prefix}<a key={word + i + z + '_link'} className={'theme' + highlightSearchClass} target='_blank' href={link}>{match.text}</a>{suffix} </span>);
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
} else if (trimWord.match(hashRegex)) {
|
2015-08-10 16:44:54 -07:00
|
|
|
mClass = '';
|
|
|
|
|
if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) {
|
|
|
|
|
mClass = mentionClass;
|
|
|
|
|
}
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
if (searchTerm === trimWord.substring(1).toLowerCase() || searchTerm === trimWord.toLowerCase()) {
|
2015-08-10 16:44:54 -07:00
|
|
|
highlightSearchClass = ' search-highlight';
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting) {
|
2015-08-10 16:44:54 -07:00
|
|
|
if (prefixSpan) {
|
|
|
|
|
inner.push(prefixSpan);
|
|
|
|
|
}
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}><a key={word + i + z + '_hash'} className={'theme ' + mClass + highlightSearchClass} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a></span>);
|
|
|
|
|
if (suffixSpan) {
|
|
|
|
|
inner.push(suffixSpan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}>{prefix}<a key={word + i + z + '_hash'} className={'theme ' + mClass + highlightSearchClass} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a>{suffix} </span>);
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-06-30 12:30:11 -07:00
|
|
|
} else if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) {
|
2015-06-14 23:53:32 -08:00
|
|
|
if (trimWord.charAt(0) === '@') {
|
|
|
|
|
if (searchTerm === trimWord.substring(1).toLowerCase()) {
|
2015-08-10 16:44:54 -07:00
|
|
|
highlightSearchClass = ' search-highlight';
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
2015-07-08 11:34:34 -07:00
|
|
|
if (useTextFormatting) {
|
2015-08-10 16:44:54 -07:00
|
|
|
if (prefixSpan) {
|
|
|
|
|
inner.push(prefixSpan);
|
|
|
|
|
}
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}><a className={mentionClass + highlightSearchClass} key={name + i + z + '_link'} href='#'>{trimWord}</a></span>);
|
|
|
|
|
if (suffixSpan) {
|
|
|
|
|
inner.push(suffixSpan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}>{prefix}<a className={mentionClass + highlightSearchClass} key={name + i + z + '_link'} href='#'>{trimWord}</a>{suffix} </span>);
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-08-10 16:44:54 -07:00
|
|
|
} else if (useTextFormatting) {
|
|
|
|
|
if (prefixSpan) {
|
|
|
|
|
inner.push(prefixSpan);
|
|
|
|
|
}
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}><span className={mentionClass + highlightSearchClass}>{trimWord}</span></span>);
|
|
|
|
|
if (suffixSpan) {
|
|
|
|
|
inner.push(suffixSpan);
|
2015-07-08 11:34:34 -07:00
|
|
|
}
|
2015-08-10 16:44:54 -07:00
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}>{prefix}<span className={mentionClass + highlightSearchClass}>{module.exports.replaceHtmlEntities(trimWord)}</span>{suffix} </span>);
|
|
|
|
|
}
|
|
|
|
|
} else if (word !== '') {
|
|
|
|
|
if (useTextFormatting) {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'} className={highlightSearchClass} dangerouslySetInnerHTML={{__html: word + ' '}} />);
|
|
|
|
|
} else {
|
|
|
|
|
inner.push(<span key={word + i + z + '_span'}><span className={highlightSearchClass}>{module.exports.replaceHtmlEntities(word)}</span> </span>);
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
}
|
2015-08-10 16:44:54 -07:00
|
|
|
highlightSearchClass = '';
|
|
|
|
|
}
|
|
|
|
|
if (!useTextFormatting && i !== lines.length - 1) {
|
|
|
|
|
inner.push(<br key={'br_' + i}/>);
|
2015-08-10 16:51:59 -07:00
|
|
|
} else if (useTextFormatting && !codeFlag && i < lines.length - 2) {
|
|
|
|
|
inner.push(<br key={'br_' + i}/>);
|
2015-06-14 23:53:32 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return inner;
|
2015-07-08 11:34:34 -07:00
|
|
|
};
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
module.exports.getFileType = function(ext) {
|
|
|
|
|
ext = ext.toLowerCase();
|
|
|
|
|
if (Constants.IMAGE_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "image";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.AUDIO_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "audio";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.VIDEO_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "video";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.SPREADSHEET_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "spreadsheet";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.CODE_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "code";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.WORD_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "word";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.EXCEL_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "excel";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.PDF_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "pdf";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Constants.PATCH_TYPES.indexOf(ext) > -1) {
|
|
|
|
|
return "patch";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "other";
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-24 17:04:02 -04:00
|
|
|
module.exports.getPreviewImagePathForFileType = function(fileType) {
|
|
|
|
|
fileType = fileType.toLowerCase();
|
|
|
|
|
|
|
|
|
|
var icon;
|
|
|
|
|
if (fileType in Constants.ICON_FROM_TYPE) {
|
|
|
|
|
icon = Constants.ICON_FROM_TYPE[fileType];
|
|
|
|
|
} else {
|
|
|
|
|
icon = Constants.ICON_FROM_TYPE["other"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "/static/images/icons/" + icon + ".png";
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
module.exports.getIconClassName = function(fileType) {
|
|
|
|
|
fileType = fileType.toLowerCase();
|
|
|
|
|
|
|
|
|
|
if (fileType in Constants.ICON_FROM_TYPE)
|
|
|
|
|
return Constants.ICON_FROM_TYPE[fileType];
|
|
|
|
|
|
|
|
|
|
return "glyphicon-file";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.splitFileLocation = function(fileLocation) {
|
|
|
|
|
var fileSplit = fileLocation.split('.');
|
|
|
|
|
|
2015-07-27 12:36:14 -04:00
|
|
|
var ext = "";
|
|
|
|
|
if (fileSplit.length > 1) {
|
|
|
|
|
ext = fileSplit[fileSplit.length - 1];
|
|
|
|
|
fileSplit.splice(fileSplit.length - 1, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
var filePath = fileSplit.join('.');
|
|
|
|
|
var filename = filePath.split('/')[filePath.split('/').length-1];
|
|
|
|
|
|
|
|
|
|
return {'ext': ext, 'name': filename, 'path': filePath};
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-22 17:18:33 -04:00
|
|
|
// Asynchronously gets the size of a file by requesting its headers. If successful, it calls the
|
|
|
|
|
// provided callback with the file size in bytes as the argument.
|
|
|
|
|
module.exports.getFileSize = function(url, callback) {
|
|
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
|
|
|
|
|
|
request.open('HEAD', url, true);
|
|
|
|
|
request.onreadystatechange = function() {
|
|
|
|
|
if (request.readyState == 4 && request.status == 200) {
|
|
|
|
|
if (callback) {
|
|
|
|
|
callback(parseInt(request.getResponseHeader("content-length")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
request.send();
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
module.exports.toTitleCase = function(str) {
|
|
|
|
|
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.changeCss = function(className, classValue) {
|
|
|
|
|
// we need invisible container to store additional css definitions
|
|
|
|
|
var cssMainContainer = $('#css-modifier-container');
|
|
|
|
|
if (cssMainContainer.length == 0) {
|
|
|
|
|
var cssMainContainer = $('<div id="css-modifier-container"></div>');
|
|
|
|
|
cssMainContainer.hide();
|
|
|
|
|
cssMainContainer.appendTo($('body'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// and we need one div for each class
|
|
|
|
|
classContainer = cssMainContainer.find('div[data-class="' + className + '"]');
|
|
|
|
|
if (classContainer.length == 0) {
|
|
|
|
|
classContainer = $('<div data-class="' + className + '"></div>');
|
|
|
|
|
classContainer.appendTo(cssMainContainer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// append additional style
|
|
|
|
|
classContainer.html('<style>' + className + ' {' + classValue + '}</style>');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.rgb2hex = function(rgb) {
|
|
|
|
|
if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;
|
|
|
|
|
|
|
|
|
|
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
|
|
|
|
function hex(x) {
|
|
|
|
|
return ("0" + parseInt(x).toString(16)).slice(-2);
|
|
|
|
|
}
|
|
|
|
|
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.placeCaretAtEnd = function(el) {
|
|
|
|
|
el.focus();
|
|
|
|
|
if (typeof window.getSelection != "undefined"
|
|
|
|
|
&& typeof document.createRange != "undefined") {
|
|
|
|
|
var range = document.createRange();
|
|
|
|
|
range.selectNodeContents(el);
|
|
|
|
|
range.collapse(false);
|
|
|
|
|
var sel = window.getSelection();
|
|
|
|
|
sel.removeAllRanges();
|
|
|
|
|
sel.addRange(range);
|
|
|
|
|
} else if (typeof document.body.createTextRange != "undefined") {
|
|
|
|
|
var textRange = document.body.createTextRange();
|
|
|
|
|
textRange.moveToElementText(el);
|
|
|
|
|
textRange.collapse(false);
|
|
|
|
|
textRange.select();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getCaretPosition = function(el) {
|
|
|
|
|
if (el.selectionStart) {
|
|
|
|
|
return el.selectionStart;
|
|
|
|
|
} else if (document.selection) {
|
|
|
|
|
el.focus();
|
|
|
|
|
|
|
|
|
|
var r = document.selection.createRange();
|
|
|
|
|
if (r == null) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var re = el.createTextRange(),
|
|
|
|
|
rc = re.duplicate();
|
|
|
|
|
re.moveToBookmark(r.getBookmark());
|
|
|
|
|
rc.setEndPoint('EndToStart', re);
|
|
|
|
|
|
|
|
|
|
return rc.text.length;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.setSelectionRange = function(input, selectionStart, selectionEnd) {
|
|
|
|
|
if (input.setSelectionRange) {
|
|
|
|
|
input.focus();
|
|
|
|
|
input.setSelectionRange(selectionStart, selectionEnd);
|
|
|
|
|
}
|
|
|
|
|
else if (input.createTextRange) {
|
|
|
|
|
var range = input.createTextRange();
|
|
|
|
|
range.collapse(true);
|
|
|
|
|
range.moveEnd('character', selectionEnd);
|
|
|
|
|
range.moveStart('character', selectionStart);
|
|
|
|
|
range.select();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.setCaretPosition = function (input, pos) {
|
|
|
|
|
module.exports.setSelectionRange(input, pos, pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.getSelectedText = function(input) {
|
|
|
|
|
var selectedText;
|
|
|
|
|
if (document.selection != undefined) {
|
|
|
|
|
input.focus();
|
|
|
|
|
var sel = document.selection.createRange();
|
|
|
|
|
selectedText = sel.text;
|
|
|
|
|
} else if (input.selectionStart != undefined) {
|
|
|
|
|
var startPos = input.selectionStart;
|
|
|
|
|
var endPos = input.selectionEnd;
|
|
|
|
|
selectedText = input.value.substring(startPos, endPos)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return selectedText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.isValidUsername = function (name) {
|
|
|
|
|
|
|
|
|
|
var error = ""
|
|
|
|
|
if (!name) {
|
|
|
|
|
error = "This field is required";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (name.length < 3 || name.length > 15)
|
|
|
|
|
{
|
|
|
|
|
error = "Must be between 3 and 15 characters";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (!/^[a-z0-9\.\-\_]+$/.test(name))
|
|
|
|
|
{
|
|
|
|
|
error = "Must contain only lowercase letters, numbers, and the symbols '.', '-', and '_'.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (!/[a-z]/.test(name.charAt(0)))
|
|
|
|
|
{
|
|
|
|
|
error = "First character must be a letter.";
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-11 08:32:02 -07:00
|
|
|
else
|
2015-06-14 23:53:32 -08:00
|
|
|
{
|
|
|
|
|
var lowerName = name.toLowerCase().trim();
|
|
|
|
|
|
2015-07-11 08:32:02 -07:00
|
|
|
for (var i = 0; i < Constants.RESERVED_USERNAMES.length; i++)
|
2015-06-14 23:53:32 -08:00
|
|
|
{
|
2015-07-11 08:32:02 -07:00
|
|
|
if (lowerName === Constants.RESERVED_USERNAMES[i])
|
2015-06-14 23:53:32 -08:00
|
|
|
{
|
|
|
|
|
error = "Cannot use a reserved word as a username.";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.switchChannel = function(channel, teammate_name) {
|
|
|
|
|
AppDispatcher.handleViewAction({
|
|
|
|
|
type: ActionTypes.CLICK_CHANNEL,
|
|
|
|
|
name: channel.name,
|
|
|
|
|
id: channel.id
|
|
|
|
|
});
|
|
|
|
|
|
2015-07-08 11:50:10 -04:00
|
|
|
var teamURL = window.location.href.split('/channels')[0];
|
|
|
|
|
history.replaceState('data', '', teamURL + '/channels/' + channel.name);
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
if (channel.type === 'D' && teammate_name) {
|
|
|
|
|
document.title = teammate_name + " " + document.title.substring(document.title.lastIndexOf("-"));
|
|
|
|
|
} else {
|
|
|
|
|
document.title = channel.display_name + " " + document.title.substring(document.title.lastIndexOf("-"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncClient.getChannels(true, true, true);
|
|
|
|
|
AsyncClient.getChannelExtraInfo(true);
|
2015-07-29 11:30:54 -04:00
|
|
|
AsyncClient.getPosts(true, channel.id, Constants.POST_CHUNK_SIZE);
|
2015-06-14 23:53:32 -08:00
|
|
|
|
|
|
|
|
$('.inner__wrap').removeClass('move--right');
|
|
|
|
|
$('.sidebar--left').removeClass('move--right');
|
|
|
|
|
|
|
|
|
|
client.trackPage();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.isMobile = function() {
|
|
|
|
|
return screen.width <= 768;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports.isComment = function(post) {
|
|
|
|
|
if ('root_id' in post) {
|
|
|
|
|
return post.root_id != "";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 12:41:36 -07:00
|
|
|
module.exports.getDirectTeammate = function(channel_id) {
|
2015-07-02 09:32:31 -04:00
|
|
|
var userIds = ChannelStore.get(channel_id).name.split('__');
|
|
|
|
|
var curUserId = UserStore.getCurrentId();
|
|
|
|
|
var teammate = {};
|
2015-07-01 12:41:36 -07:00
|
|
|
|
2015-07-02 09:32:31 -04:00
|
|
|
if(userIds.length != 2 || userIds.indexOf(curUserId) === -1) {
|
|
|
|
|
return teammate;
|
|
|
|
|
}
|
2015-07-01 12:41:36 -07:00
|
|
|
|
2015-07-02 09:34:57 -04:00
|
|
|
for (var idx in userIds) {
|
2015-07-02 09:32:31 -04:00
|
|
|
if(userIds[idx] !== curUserId) {
|
|
|
|
|
teammate = UserStore.getProfile(userIds[idx]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-07-01 12:41:36 -07:00
|
|
|
|
2015-07-02 09:32:31 -04:00
|
|
|
return teammate;
|
2015-07-01 12:41:36 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-14 23:53:32 -08:00
|
|
|
Image.prototype.load = function(url, progressCallback) {
|
|
|
|
|
var thisImg = this;
|
|
|
|
|
var xmlHTTP = new XMLHttpRequest();
|
|
|
|
|
xmlHTTP.open('GET', url, true);
|
|
|
|
|
xmlHTTP.responseType = 'arraybuffer';
|
|
|
|
|
xmlHTTP.onload = function(e) {
|
|
|
|
|
var h = xmlHTTP.getAllResponseHeaders(),
|
|
|
|
|
m = h.match( /^Content-Type\:\s*(.*?)$/mi ),
|
|
|
|
|
mimeType = m[ 1 ] || 'image/png';
|
|
|
|
|
|
|
|
|
|
var blob = new Blob([this.response], { type: mimeType });
|
|
|
|
|
thisImg.src = window.URL.createObjectURL(blob);
|
|
|
|
|
};
|
|
|
|
|
xmlHTTP.onprogress = function(e) {
|
|
|
|
|
parseInt(thisImg.completedPercentage = (e.loaded / e.total) * 100);
|
|
|
|
|
if (progressCallback) progressCallback();
|
|
|
|
|
};
|
|
|
|
|
xmlHTTP.onloadstart = function() {
|
|
|
|
|
thisImg.completedPercentage = 0;
|
|
|
|
|
};
|
|
|
|
|
xmlHTTP.send();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Image.prototype.completedPercentage = 0;
|
2015-06-16 15:35:34 -04:00
|
|
|
|
2015-07-11 08:32:02 -07:00
|
|
|
module.exports.changeColor =function(col, amt) {
|
|
|
|
|
|
|
|
|
|
var usePound = false;
|
|
|
|
|
|
|
|
|
|
if (col[0] == "#") {
|
|
|
|
|
col = col.slice(1);
|
|
|
|
|
usePound = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var num = parseInt(col,16);
|
|
|
|
|
|
|
|
|
|
var r = (num >> 16) + amt;
|
|
|
|
|
|
|
|
|
|
if (r > 255) r = 255;
|
|
|
|
|
else if (r < 0) r = 0;
|
|
|
|
|
|
|
|
|
|
var b = ((num >> 8) & 0x00FF) + amt;
|
|
|
|
|
|
|
|
|
|
if (b > 255) b = 255;
|
|
|
|
|
else if (b < 0) b = 0;
|
|
|
|
|
|
|
|
|
|
var g = (num & 0x0000FF) + amt;
|
|
|
|
|
|
|
|
|
|
if (g > 255) g = 255;
|
|
|
|
|
else if (g < 0) g = 0;
|
|
|
|
|
|
|
|
|
|
return (usePound?"#":"") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
|
2015-07-13 17:47:57 -04:00
|
|
|
};
|
2015-07-11 08:32:02 -07:00
|
|
|
|
2015-07-14 17:07:19 -04:00
|
|
|
module.exports.getFullName = function(user) {
|
|
|
|
|
if (user.first_name && user.last_name) {
|
|
|
|
|
return user.first_name + " " + user.last_name;
|
|
|
|
|
} else if (user.first_name) {
|
|
|
|
|
return user.first_name;
|
|
|
|
|
} else if (user.last_name) {
|
|
|
|
|
return user.last_name;
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-13 17:47:57 -04:00
|
|
|
module.exports.getDisplayName = function(user) {
|
|
|
|
|
if (user.nickname && user.nickname.trim().length > 0) {
|
|
|
|
|
return user.nickname;
|
|
|
|
|
} else {
|
2015-07-14 17:07:19 -04:00
|
|
|
var fullName = module.exports.getFullName(user);
|
|
|
|
|
|
|
|
|
|
if (fullName) {
|
|
|
|
|
return fullName;
|
|
|
|
|
} else {
|
|
|
|
|
return user.username;
|
|
|
|
|
}
|
2015-07-13 17:47:57 -04:00
|
|
|
}
|
2015-07-11 08:32:02 -07:00
|
|
|
};
|
2015-07-24 14:13:19 -07:00
|
|
|
|
|
|
|
|
//IE10 does not set window.location.origin automatically so this must be called instead when using it
|
|
|
|
|
module.exports.getWindowLocationOrigin = function() {
|
2015-07-27 13:21:50 -07:00
|
|
|
var windowLocationOrigin = window.location.origin;
|
|
|
|
|
if (!windowLocationOrigin) {
|
|
|
|
|
windowLocationOrigin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
|
2015-07-24 14:13:19 -07:00
|
|
|
}
|
2015-07-27 13:21:50 -07:00
|
|
|
return windowLocationOrigin;
|
2015-07-22 17:18:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Converts a file size in bytes into a human-readable string of the form "123MB".
|
|
|
|
|
module.exports.fileSizeToString = function(bytes) {
|
|
|
|
|
// it's unlikely that we'll have files bigger than this
|
|
|
|
|
if (bytes > 1024 * 1024 * 1024 * 1024) {
|
|
|
|
|
return Math.floor(bytes / (1024 * 1024 * 1024 * 1024)) + "TB";
|
|
|
|
|
} else if (bytes > 1024 * 1024 * 1024) {
|
|
|
|
|
return Math.floor(bytes / (1024 * 1024 * 1024)) + "GB";
|
|
|
|
|
} else if (bytes > 1024 * 1024) {
|
|
|
|
|
return Math.floor(bytes / (1024 * 1024)) + "MB";
|
|
|
|
|
} else if (bytes > 1024) {
|
|
|
|
|
return Math.floor(bytes / 1024) + "KB";
|
|
|
|
|
} else {
|
|
|
|
|
return bytes + "B";
|
|
|
|
|
}
|
2015-07-24 14:13:19 -07:00
|
|
|
};
|
2015-07-28 11:30:22 -04:00
|
|
|
|
|
|
|
|
// Converts a filename (like those attached to Post objects) to a url that can be used to retrieve attachments from the server.
|
|
|
|
|
module.exports.getFileUrl = function(filename) {
|
|
|
|
|
var url = filename;
|
|
|
|
|
|
|
|
|
|
// This is a temporary patch to fix issue with old files using absolute paths
|
|
|
|
|
if (url.indexOf("/api/v1/files/get") != -1) {
|
|
|
|
|
url = filename.split("/api/v1/files/get")[1];
|
|
|
|
|
}
|
|
|
|
|
url = module.exports.getWindowLocationOrigin() + "/api/v1/files/get" + url;
|
|
|
|
|
|
|
|
|
|
return url;
|
|
|
|
|
};
|
2015-07-28 16:41:57 -04:00
|
|
|
|
|
|
|
|
// Gets the name of a file (including extension) from a given url or file path.
|
|
|
|
|
module.exports.getFileName = function(path) {
|
|
|
|
|
var split = path.split('/');
|
|
|
|
|
return split[split.length - 1];
|
2015-07-24 14:13:19 -07:00
|
|
|
};
|
2015-08-10 12:05:45 -04:00
|
|
|
|
|
|
|
|
// Generates a RFC-4122 version 4 compliant globally unique identifier.
|
|
|
|
|
module.exports.generateId = function() {
|
|
|
|
|
// implementation taken from http://stackoverflow.com/a/2117523
|
|
|
|
|
var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
|
|
|
|
|
|
|
|
|
id = id.replace(/[xy]/g, function(c) {
|
|
|
|
|
var r = Math.floor(Math.random() * 16);
|
|
|
|
|
|
|
|
|
|
var v;
|
|
|
|
|
if (c === 'x') {
|
|
|
|
|
v = r;
|
|
|
|
|
} else {
|
|
|
|
|
v = r & 0x3 | 0x8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v.toString(16);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
};
|