diff options
author | Chris <ccbrown112@gmail.com> | 2017-07-25 11:47:03 -0700 |
---|---|---|
committer | Harrison Healey <harrisonmhealey@gmail.com> | 2017-07-25 14:47:03 -0400 |
commit | d49419776de0811732db59eae90c5c6da223f076 (patch) | |
tree | 1b684895f37c6f91e239d1f3930c28a652fbcac4 /webapp/components | |
parent | e5e450fc097c14110e942731018041cd1931aa25 (diff) | |
download | chat-d49419776de0811732db59eae90c5c6da223f076.tar.gz chat-d49419776de0811732db59eae90c5c6da223f076.tar.bz2 chat-d49419776de0811732db59eae90c5c6da223f076.zip |
Refresh the emoji library (#7001)
* refresh the emoji library
* fix img_trans.gif
* compress sprite sheet
* remove note on compression - webpack seems to handle compression decently
* better emoji sheet preloading
* requested changes
Diffstat (limited to 'webapp/components')
5 files changed, 136 insertions, 17 deletions
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx index 94852c465..858f4c68c 100644 --- a/webapp/components/create_comment.jsx +++ b/webapp/components/create_comment.jsx @@ -17,6 +17,7 @@ import MsgTyping from './msg_typing.jsx'; import FileUpload from './file_upload.jsx'; import FilePreview from './file_preview.jsx'; import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; +import * as EmojiPicker from 'components/emoji_picker/emoji_picker.jsx'; import * as Utils from 'utils/utils.jsx'; import * as UserAgent from 'utils/user_agent.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; @@ -588,6 +589,7 @@ export default class CreateComment extends React.Component { <span className={'fa fa-smile-o icon--emoji-picker emoji-rhs'} onClick={this.toggleEmojiPicker} + onMouseOver={EmojiPicker.beginPreloading} /> </span> ); diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 4b092ff08..1ad1dda4f 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -9,6 +9,7 @@ import FilePreview from './file_preview.jsx'; import PostDeletedModal from './post_deleted_modal.jsx'; import TutorialTip from './tutorial/tutorial_tip.jsx'; import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; +import * as EmojiPicker from 'components/emoji_picker/emoji_picker.jsx'; import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; @@ -746,6 +747,7 @@ export default class CreatePost extends React.Component { <span className={'fa fa-smile-o icon--emoji-picker emoji-main'} onClick={this.toggleEmojiPicker} + onMouseOver={EmojiPicker.beginPreloading} /> </span> ); diff --git a/webapp/components/emoji_picker/components/emoji_picker_item.jsx b/webapp/components/emoji_picker/components/emoji_picker_item.jsx index 3321bf761..2854a637a 100644 --- a/webapp/components/emoji_picker/components/emoji_picker_item.jsx +++ b/webapp/components/emoji_picker/components/emoji_picker_item.jsx @@ -14,7 +14,8 @@ export default class EmojiPickerItem extends React.Component { onItemOut: PropTypes.func.isRequired, onItemClick: PropTypes.func.isRequired, onItemUnmount: PropTypes.func.isRequired, - category: PropTypes.string.isRequired + category: PropTypes.string.isRequired, + isLoaded: PropTypes.bool.isRequired } constructor(props) { @@ -61,8 +62,8 @@ export default class EmojiPickerItem extends React.Component { item = (<div > <img - src='/static/emoji/img_trans.gif' - className={' emojisprite emoji-' + this.props.emoji.filename + ' '} + src='/static/images/img_trans.gif' + className={' emojisprite' + (this.props.isLoaded ? '' : '-loading') + ' emoji-' + this.props.emoji.filename + ' '} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onClick={this.handleClick} diff --git a/webapp/components/emoji_picker/components/emoji_picker_preview.jsx b/webapp/components/emoji_picker/components/emoji_picker_preview.jsx index 914844551..b9f3f4262 100644 --- a/webapp/components/emoji_picker/components/emoji_picker_preview.jsx +++ b/webapp/components/emoji_picker/components/emoji_picker_preview.jsx @@ -27,7 +27,7 @@ export default class EmojiPickerPreview extends React.Component { name = emoji.aliases[0]; aliases = emoji.aliases; previewImage = (<span className='sprite-preview'><img - src='/static/emoji/img_trans.gif' + src='/static/images/img_trans.gif' className={' emojisprite-preview emoji-' + emoji.filename + ' '} /></span>); } else { diff --git a/webapp/components/emoji_picker/emoji_picker.jsx b/webapp/components/emoji_picker/emoji_picker.jsx index 0d9b34176..8b5375000 100644 --- a/webapp/components/emoji_picker/emoji_picker.jsx +++ b/webapp/components/emoji_picker/emoji_picker.jsx @@ -14,14 +14,23 @@ import EmojiPickerCategory from './components/emoji_picker_category.jsx'; import EmojiPickerItem from './components/emoji_picker_item.jsx'; import EmojiPickerPreview from './components/emoji_picker_preview.jsx'; +import PeopleSpriteSheet from 'images/emoji-sheets/people.png'; +import NatureSpriteSheet from 'images/emoji-sheets/nature.png'; +import FoodsSpriteSheet from 'images/emoji-sheets/foods.png'; +import ActivitySpriteSheet from 'images/emoji-sheets/activity.png'; +import PlacesSpriteSheet from 'images/emoji-sheets/places.png'; +import ObjectsSpriteSheet from 'images/emoji-sheets/objects.png'; +import SymbolsSpriteSheet from 'images/emoji-sheets/symbols.png'; +import FlagsSpriteSheet from 'images/emoji-sheets/flags.png'; + // This should include all the categories available in Emoji.CategoryNames const CATEGORIES = [ 'recent', 'people', 'nature', - 'food', + 'foods', 'activity', - 'travel', + 'places', 'objects', 'symbols', 'flags', @@ -49,6 +58,7 @@ export default class EmojiPicker extends React.Component { // All props are primitives or treated as immutable this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); + this.handlePreload = this.handlePreload.bind(this); this.handleCategoryClick = this.handleCategoryClick.bind(this); this.handleFilterChange = this.handleFilterChange.bind(this); this.handleItemOver = this.handleItemOver.bind(this); @@ -61,7 +71,8 @@ export default class EmojiPicker extends React.Component { this.state = { category: 'recent', filter: '', - selected: null + selected: null, + preloaded: [] }; } @@ -71,6 +82,23 @@ export default class EmojiPicker extends React.Component { requestAnimationFrame(() => { this.searchInput.focus(); }); + beginPreloading(); + subscribeToPreloads(this.handlePreload); + this.handlePreload(); + } + + componentWillUnmount() { + unsubscribeFromPreloads(this.handlePreload); + } + + handlePreload() { + const preloaded = []; + for (const category of CATEGORIES) { + if (didPreloadCategory(category)) { + preloaded.push(category); + } + } + this.setState({preloaded}); } handleCategoryClick(category) { @@ -139,7 +167,8 @@ export default class EmojiPicker extends React.Component { } } } - renderCategory(category, filter) { + + renderCategory(category, isLoaded, filter) { const items = []; let indices = []; let recentEmojis = []; @@ -181,6 +210,7 @@ export default class EmojiPicker extends React.Component { key={'system_' + (category === 'recent' ? 'recent_' : '') + (emoji.name || emoji.aliases[0])} emoji={emoji} category={category} + isLoaded={isLoaded} onItemOver={this.handleItemOver} onItemOut={this.handleItemOut} onItemClick={this.handleItemClick} @@ -261,7 +291,7 @@ export default class EmojiPicker extends React.Component { previewImage = ( <span> <img - src='/static/emoji/img_trans.gif' + src='/static/images/img_trans.gif' className={' emojisprite-preview emoji-' + selected.filename + ' '} align='absmiddle' /> @@ -293,9 +323,9 @@ export default class EmojiPicker extends React.Component { for (const category of CATEGORIES) { if (category === 'custom') { - items.push(this.renderCategory('custom', this.state.filter, this.props.customEmojis)); + items.push(this.renderCategory('custom', true, this.state.filter, this.props.customEmojis)); } else { - items.push(this.renderCategory(category, this.state.filter)); + items.push(this.renderCategory(category, category === 'recent' || this.state.preloaded.indexOf(category) >= 0, this.state.filter)); } } @@ -357,15 +387,15 @@ export default class EmojiPicker extends React.Component { selected={this.state.category === 'nature'} /> <EmojiPickerCategory - category='food' + category='foods' icon={ <i className='fa fa-cutlery' - title={Utils.localizeMessage('emoji_picker.food', 'Food')} + title={Utils.localizeMessage('emoji_picker.foods', 'Foods')} /> } onCategoryClick={this.handleCategoryClick} - selected={this.state.category === 'food'} + selected={this.state.category === 'foods'} /> <EmojiPickerCategory category='activity' @@ -379,15 +409,15 @@ export default class EmojiPicker extends React.Component { selected={this.state.category === 'activity'} /> <EmojiPickerCategory - category='travel' + category='places' icon={ <i className='fa fa-plane' - title={Utils.localizeMessage('emoji_picker.travel', 'Travel')} + title={Utils.localizeMessage('emoji_picker.places', 'Places')} /> } onCategoryClick={this.handleCategoryClick} - selected={this.state.category === 'travel'} + selected={this.state.category === 'places'} /> <EmojiPickerCategory category='objects' @@ -459,3 +489,87 @@ export default class EmojiPicker extends React.Component { ); } } + +var preloads = { + people: { + src: PeopleSpriteSheet, + didPreload: false + }, + nature: { + src: NatureSpriteSheet, + didPreload: false + }, + foods: { + src: FoodsSpriteSheet, + didPreload: false + }, + activity: { + src: ActivitySpriteSheet, + didPreload: false + }, + places: { + src: PlacesSpriteSheet, + didPreload: false + }, + objects: { + src: ObjectsSpriteSheet, + didPreload: false + }, + symbols: { + src: SymbolsSpriteSheet, + didPreload: false + }, + flags: { + src: FlagsSpriteSheet, + didPreload: false + } +}; + +var didBeginPreloading = false; + +var preloadCallback = null; + +export function beginPreloading() { + if (didBeginPreloading) { + return; + } + didBeginPreloading = true; + preloadNextCategory(); +} + +function preloadNextCategory() { + let sheet = null; + for (const category of CATEGORIES) { + const preload = preloads[category]; + if (preload && !preload.didPreload) { + sheet = preload; + break; + } + } + if (sheet) { + const img = new Image(); + img.onload = () => { + sheet.didPreload = true; + if (preloadCallback) { + preloadCallback(); + } + preloadNextCategory(); + }; + img.src = sheet.src; + } +} + +export function didPreloadCategory(category) { + const preload = preloads[category]; + return preload && preload.didPreload; +} + +function subscribeToPreloads(callback) { + preloadCallback = callback; +} + +function unsubscribeFromPreloads(callback) { + if (callback === preloadCallback) { + preloadCallback = null; + } +} |