From cf7a05f80f68b5b1c8bcc0089679dd497cec2506 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sun, 14 Jun 2015 23:53:32 -0800 Subject: first commit --- web/react/utils/utils.jsx | 732 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 732 insertions(+) create mode 100644 web/react/utils/utils.jsx (limited to 'web/react/utils/utils.jsx') diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx new file mode 100644 index 000000000..72ed48faf --- /dev/null +++ b/web/react/utils/utils.jsx @@ -0,0 +1,732 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); +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'); +var LinkifyIt = require('linkify-it'); + +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) { + var cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-'); + cleaned = cleaned.replace(/^\-+/, ''); + cleaned = cleaned.replace(/\-+$/, ''); + return cleaned; +}; + + + +module.exports.isTestDomain = function() { + + if ((/^localhost/).test(window.location.hostname)) + return true; + + 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("."); + + if (parts.length == 1) + return "localhost:8065"; + + 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) { + if ("Notification" in window && Notification.permission !== 'denied') { + 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 { + window.location.href = "/channels/town-square"; + } + }; + 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(); +} + +module.exports.extractLinks = function(text) { + var repRegex = new RegExp("
", "g"); + var linkMatcher = new LinkifyIt(); + var matches = linkMatcher.match(text.replace(repRegex, "\n")); + + if (!matches) return { "links": null, "text": text }; + + var links = [] + for (var i = 0; i < matches.length; i++) { + links.push(matches[i].url) + } + + return { "links": links, "text": text }; +} + +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 ( +
+
+

+

+

{link}

+
+
+ ); +} + +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) { + $('.video-uploader.'+youtubeId).html(data.data.uploader); + $('.video-title.'+youtubeId).find('a').html(data.data.title); + $(".post-list-holder-by-time").scrollTop($(".post-list-holder-by-time")[0].scrollHeight); + $(".post-list-holder-by-time").perfectScrollbar('update'); + }; + + $.ajax({ + async: true, + url: 'https://gdata.youtube.com/feeds/api/videos/'+youtubeId+'?v=2&alt=jsonc', + type: 'GET', + success: success + }); + + return ( +
+

YouTube

+

+

+
+
+
+ +
+ +
+
+
+
+
+ ); + +} + +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 + }); +} + +var oldExplicitMentionRegex = /(?:)([\s\S]*?)(?:<\/mention>)/g; +var puncStartRegex = /^((?![@#])\W)+/g; +var puncEndRegex = /(\W)+$/g; + +module.exports.textToJsx = function(text, options) { + + if (options && options['singleline']) { + var repRegex = new RegExp("\n", "g"); + text = text.replace(repRegex, " "); + } else { + var repRegex = new RegExp("\n", "g"); + text = text.replace(repRegex, "
"); + } + + var searchTerm = "" + if (options && options['searchTerm']) { + searchTerm = options['searchTerm'].toLowerCase() + } + + var mentionClass = "mention-highlight"; + if (options && options['noMentionHighlight']) { + mentionClass = ""; + } + + var inner = []; + + // Function specific regexes + var hashRegex = /^href="#[^"]+"|(#[A-Za-z]+[A-Za-z0-9_]*[A-Za-z0-9])$/g; + + var implicitKeywords = {}; + var keywordArray = UserStore.getCurrentMentionKeys(); + for (var i = 0; i < keywordArray.length; i++) { + implicitKeywords[keywordArray[i]] = true; + } + + var lines = text.split("
"); + var urlMatcher = new LinkifyIt(); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + var words = line.split(" "); + var highlightSearchClass = ""; + for (var z = 0; z < words.length; z++) { + var word = words[z]; + var trimWord = word.replace(puncStartRegex, '').replace(puncEndRegex, '').trim(); + 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); + + if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm != "") { + + highlightSearchClass = " search-highlight"; + } + + if (explicitMention && UserStore.getProfileByUsername(explicitMention[1])) { + var name = explicitMention[1]; + // do both a non-case sensitive and case senstive check + var mClass = (name.toLowerCase() in implicitKeywords || name in implicitKeywords) ? mentionClass : ""; + + var suffix = word.match(puncEndRegex); + var prefix = word.match(puncStartRegex); + + if (searchTerm === name) { + highlightSearchClass = " search-highlight"; + } + + inner.push({prefix}@{name}{suffix} ); + } else if (urlMatcher.test(word)) { + var match = urlMatcher.match(word)[0]; + var link = match.url; + + var prefix = word.substring(0,word.indexOf(match.raw)) + var suffix = word.substring(word.indexOf(match.raw)+match.raw.length); + + inner.push({prefix}{match.raw}{suffix} ); + + } else if (trimWord.match(hashRegex)) { + var suffix = word.match(puncEndRegex); + var prefix = word.match(puncStartRegex); + var mClass = trimWord in implicitKeywords ? mentionClass : ""; + + if (searchTerm === trimWord.substring(1).toLowerCase() || searchTerm === trimWord.toLowerCase()) { + highlightSearchClass = " search-highlight"; + } + + inner.push({prefix}{trimWord}{suffix} ); + + } else if (trimWord in implicitKeywords) { + var suffix = word.match(puncEndRegex); + var prefix = word.match(puncStartRegex); + + if (trimWord.charAt(0) === '@') { + if (searchTerm === trimWord.substring(1).toLowerCase()) { + highlightSearchClass = " search-highlight"; + } + inner.push({prefix}{trimWord}{suffix} ); + } else { + inner.push({prefix}{module.exports.replaceHtmlEntities(trimWord)}{suffix} ); + } + + } else if (word === "") { + // if word is empty dont include a span + } else { + inner.push({module.exports.replaceHtmlEntities(word)} ); + } + highlightSearchClass = ""; + } + if (i != lines.length-1) + inner.push(
); + } + + return inner; +} + +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"; +}; + +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('.'); + if (fileSplit.length < 2) return {}; + + var ext = fileSplit[fileSplit.length-1]; + fileSplit.splice(fileSplit.length-1,1) + var filePath = fileSplit.join('.'); + var filename = filePath.split('/')[filePath.split('/').length-1]; + + return {'ext': ext, 'name': filename, 'path': filePath}; +} + +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 = $('
'); + 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 = $('
'); + classContainer.appendTo(cssMainContainer); + } + + // append additional style + classContainer.html(''); +} + +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."; + } + + else + { + var lowerName = name.toLowerCase().trim(); + + for (var i = 0; i < Constants.RESERVED_USERNAMES.length; i++) + { + if (lowerName === Constants.RESERVED_USERNAMES[i]) + { + 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 + }); + + var domain = window.location.href.split('/channels')[0]; + history.replaceState('data', '', domain + '/channels/' + channel.name); + + 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); + AsyncClient.getPosts(true, channel.id); + + $('.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; +} + +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; -- cgit v1.2.3-1-g7c22