Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
GitLab
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
projects.thm.de
GitLab
Commits
77c47389
Commit
77c47389
authored
May 02, 2018
by
Tim Zallmann
Committed by
Clement Ho
May 02, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimize Emoji Sprite Handling
parent
c7c9f38d
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
5501 additions
and
2697 deletions
+5501
-2697
app/assets/javascripts/behaviors/gl_emoji.js
app/assets/javascripts/behaviors/gl_emoji.js
+12
-15
app/assets/javascripts/emoji/index.js
app/assets/javascripts/emoji/index.js
+4
-2
app/assets/javascripts/emoji/support/unicode_support_map.js
app/assets/javascripts/emoji/support/unicode_support_map.js
+20
-20
app/assets/stylesheets/emoji_sprites.scss
app/assets/stylesheets/emoji_sprites.scss
+5403
-0
app/assets/stylesheets/framework.scss
app/assets/stylesheets/framework.scss
+60
-61
app/assets/stylesheets/framework/emoji_sprites.scss
app/assets/stylesheets/framework/emoji_sprites.scss
+0
-1813
app/assets/stylesheets/pages/repo.scss.orig
app/assets/stylesheets/pages/repo.scss.orig
+0
-786
config/application.rb
config/application.rb
+1
-0
lib/gitlab/gon_helper.rb
lib/gitlab/gon_helper.rb
+1
-0
No files found.
app/assets/javascripts/behaviors/gl_emoji.js
View file @
77c47389
...
...
@@ -7,27 +7,24 @@ export default function installGlEmojiElement() {
const
GlEmojiElementProto
=
Object
.
create
(
HTMLElement
.
prototype
);
GlEmojiElementProto
.
createdCallback
=
function
createdCallback
()
{
const
emojiUnicode
=
this
.
textContent
.
trim
();
const
{
name
,
unicodeVersion
,
fallbackSrc
,
fallbackSpriteClass
,
}
=
this
.
dataset
;
const
{
name
,
unicodeVersion
,
fallbackSrc
,
fallbackSpriteClass
}
=
this
.
dataset
;
const
isEmojiUnicode
=
this
.
childNodes
&&
Array
.
prototype
.
every
.
call
(
this
.
childNodes
,
childNode
=>
childNode
.
nodeType
===
3
,
);
const
isEmojiUnicode
=
this
.
childNodes
&&
Array
.
prototype
.
every
.
call
(
this
.
childNodes
,
childNode
=>
childNode
.
nodeType
===
3
);
const
hasImageFallback
=
fallbackSrc
&&
fallbackSrc
.
length
>
0
;
const
hasCssSpriteFalback
=
fallbackSpriteClass
&&
fallbackSpriteClass
.
length
>
0
;
if
(
emojiUnicode
&&
isEmojiUnicode
&&
!
isEmojiUnicodeSupported
(
emojiUnicode
,
unicodeVersion
)
)
{
if
(
emojiUnicode
&&
isEmojiUnicode
&&
!
isEmojiUnicodeSupported
(
emojiUnicode
,
unicodeVersion
))
{
// CSS sprite fallback takes precedence over image fallback
if
(
hasCssSpriteFalback
)
{
if
(
!
gon
.
emoji_sprites_css_added
&&
gon
.
emoji_sprites_css_path
)
{
const
emojiSpriteLinkTag
=
document
.
createElement
(
'
link
'
);
emojiSpriteLinkTag
.
setAttribute
(
'
rel
'
,
'
stylesheet
'
);
emojiSpriteLinkTag
.
setAttribute
(
'
href
'
,
gon
.
emoji_sprites_css_path
);
document
.
head
.
appendChild
(
emojiSpriteLinkTag
);
gon
.
emoji_sprites_css_added
=
true
;
}
// IE 11 doesn't like adding multiple at once :(
this
.
classList
.
add
(
'
emoji-icon
'
);
this
.
classList
.
add
(
fallbackSpriteClass
);
...
...
app/assets/javascripts/emoji/index.js
View file @
77c47389
...
...
@@ -34,7 +34,7 @@ export function getEmojiCategoryMap() {
symbols
:
[],
flags
:
[],
};
Object
.
keys
(
emojiMap
).
forEach
(
(
name
)
=>
{
Object
.
keys
(
emojiMap
).
forEach
(
name
=>
{
const
emoji
=
emojiMap
[
name
];
if
(
emojiCategoryMap
[
emoji
.
category
])
{
emojiCategoryMap
[
emoji
.
category
].
push
(
name
);
...
...
@@ -79,7 +79,9 @@ export function glEmojiTag(inputName, options) {
classList
.
push
(
fallbackSpriteClass
);
}
const
classAttribute
=
classList
.
length
>
0
?
`class="
${
classList
.
join
(
'
'
)}
"`
:
''
;
const
fallbackSpriteAttribute
=
opts
.
sprite
?
`data-fallback-sprite-class="
${
fallbackSpriteClass
}
"`
:
''
;
const
fallbackSpriteAttribute
=
opts
.
sprite
?
`data-fallback-sprite-class="
${
fallbackSpriteClass
}
"`
:
''
;
let
contents
=
emojiInfo
.
moji
;
if
(
opts
.
forceFallback
&&
!
opts
.
sprite
)
{
contents
=
emojiImageTag
(
name
,
fallbackImageSrc
);
...
...
app/assets/javascripts/emoji/support/unicode_support_map.js
View file @
77c47389
...
...
@@ -54,7 +54,8 @@ const unicodeSupportTestMap = {
function
checkPixelInImageDataArray
(
pixelOffset
,
imageDataArray
)
{
// `4 *` because RGBA
const
indexOffset
=
4
*
pixelOffset
;
const
hasColor
=
imageDataArray
[
indexOffset
+
0
]
||
const
hasColor
=
imageDataArray
[
indexOffset
+
0
]
||
imageDataArray
[
indexOffset
+
1
]
||
imageDataArray
[
indexOffset
+
2
];
const
isVisible
=
imageDataArray
[
indexOffset
+
3
];
...
...
@@ -75,23 +76,23 @@ const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatche
const
fontSize
=
16
;
function
generateUnicodeSupportMap
(
testMap
)
{
const
testMapKeys
=
Object
.
keys
(
testMap
);
const
numTestEntries
=
testMapKeys
.
reduce
((
list
,
testKey
)
=>
list
.
concat
(
testMap
[
testKey
]),
[]).
length
;
const
numTestEntries
=
testMapKeys
.
reduce
((
list
,
testKey
)
=>
list
.
concat
(
testMap
[
testKey
]),
[])
.
length
;
const
canvas
=
document
.
createElement
(
'
canvas
'
);
(
window
.
gl
||
window
).
testEmojiUnicodeSupportMapCanvas
=
canvas
;
const
ctx
=
canvas
.
getContext
(
'
2d
'
);
canvas
.
width
=
(
2
*
fontSize
)
;
canvas
.
height
=
(
numTestEntries
*
fontSize
)
;
canvas
.
width
=
2
*
fontSize
;
canvas
.
height
=
numTestEntries
*
fontSize
;
ctx
.
fillStyle
=
'
#000000
'
;
ctx
.
textBaseline
=
'
middle
'
;
ctx
.
font
=
`
${
fontSize
}
px "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`
;
// Write each emoji to the canvas vertically
let
writeIndex
=
0
;
testMapKeys
.
forEach
(
(
testKey
)
=>
{
testMapKeys
.
forEach
(
testKey
=>
{
const
testEntry
=
testMap
[
testKey
];
[].
concat
(
testEntry
).
forEach
(
(
emojiUnicode
)
=>
{
ctx
.
fillText
(
emojiUnicode
,
0
,
(
writeIndex
*
fontSize
)
+
(
fontSize
/
2
)
);
[].
concat
(
testEntry
).
forEach
(
emojiUnicode
=>
{
ctx
.
fillText
(
emojiUnicode
,
0
,
writeIndex
*
fontSize
+
fontSize
/
2
);
writeIndex
+=
1
;
});
});
...
...
@@ -99,29 +100,25 @@ function generateUnicodeSupportMap(testMap) {
// Read from the canvas
const
resultMap
=
{};
let
readIndex
=
0
;
testMapKeys
.
forEach
(
(
testKey
)
=>
{
testMapKeys
.
forEach
(
testKey
=>
{
const
testEntry
=
testMap
[
testKey
];
// This needs to be a `reduce` instead of `every` because we need to
// keep the `readIndex` in sync from the writes by running all entries
const
isTestSatisfied
=
[].
concat
(
testEntry
).
reduce
(
(
isSatisfied
)
=>
{
const
isTestSatisfied
=
[].
concat
(
testEntry
).
reduce
(
isSatisfied
=>
{
// Sample along the vertical-middle for a couple of characters
const
imageData
=
ctx
.
getImageData
(
0
,
(
readIndex
*
fontSize
)
+
(
fontSize
/
2
),
2
*
fontSize
,
1
,
).
data
;
const
imageData
=
ctx
.
getImageData
(
0
,
readIndex
*
fontSize
+
fontSize
/
2
,
2
*
fontSize
,
1
)
.
data
;
let
isValidEmoji
=
false
;
for
(
let
currentPixel
=
0
;
currentPixel
<
64
;
currentPixel
+=
1
)
{
const
isLookingAtFirstChar
=
currentPixel
<
fontSize
;
const
isLookingAtSecondChar
=
currentPixel
>=
(
fontSize
+
(
fontSize
/
2
))
;
const
isLookingAtSecondChar
=
currentPixel
>=
fontSize
+
fontSize
/
2
;
// Check for the emoji somewhere along the row
if
(
isLookingAtFirstChar
&&
checkPixelInImageDataArray
(
currentPixel
,
imageData
))
{
isValidEmoji
=
true
;
// Check to see that nothing is rendered next to the first character
// to ensure that the ZWJ sequence rendered as one piece
// Check to see that nothing is rendered next to the first character
// to ensure that the ZWJ sequence rendered as one piece
}
else
if
(
isLookingAtSecondChar
&&
checkPixelInImageDataArray
(
currentPixel
,
imageData
))
{
isValidEmoji
=
false
;
break
;
...
...
@@ -170,7 +167,10 @@ export default function getUnicodeSupportMap() {
if
(
isLocalStorageAvailable
)
{
window
.
localStorage
.
setItem
(
'
gl-emoji-version
'
,
GL_EMOJI_VERSION
);
window
.
localStorage
.
setItem
(
'
gl-emoji-user-agent
'
,
navigator
.
userAgent
);
window
.
localStorage
.
setItem
(
'
gl-emoji-unicode-support-map
'
,
JSON
.
stringify
(
unicodeSupportMap
));
window
.
localStorage
.
setItem
(
'
gl-emoji-unicode-support-map
'
,
JSON
.
stringify
(
unicodeSupportMap
),
);
}
}
...
...
app/assets/stylesheets/emoji_sprites.scss
0 → 100644
View file @
77c47389
This diff is collapsed.
Click to expand it.
app/assets/stylesheets/framework.scss
View file @
77c47389
@import
"framework/variables"
;
@import
"framework/mixins"
;
@import
'framework/variables'
;
@import
'framework/mixins'
;
@import
'framework/tw_bootstrap_variables'
;
@import
'framework/tw_bootstrap'
;
@import
"framework/layout"
;
@import
'framework/layout'
;
@import
"framework/animations"
;
@import
"framework/vue_transitions"
;
@import
"framework/avatar"
;
@import
"framework/asciidoctor"
;
@import
"framework/banner"
;
@import
"framework/blocks"
;
@import
"framework/buttons"
;
@import
"framework/badges"
;
@import
"framework/calendar"
;
@import
"framework/callout"
;
@import
"framework/common"
;
@import
"framework/dropdowns"
;
@import
"framework/files"
;
@import
"framework/filters"
;
@import
"framework/flash"
;
@import
"framework/forms"
;
@import
"framework/gfm"
;
@import
"framework/gitlab_theme"
;
@import
"framework/header"
;
@import
"framework/highlight"
;
@import
"framework/issue_box"
;
@import
"framework/jquery"
;
@import
"framework/lists"
;
@import
"framework/logo"
;
@import
"framework/markdown_area"
;
@import
"framework/media_object"
;
@import
"framework/mobile"
;
@import
"framework/modal"
;
@import
"framework/pagination"
;
@import
"framework/panels"
;
@import
"framework/popup"
;
@import
"framework/secondary_navigation_elements"
;
@import
"framework/selects"
;
@import
"framework/sidebar"
;
@import
"framework/contextual_sidebar"
;
@import
"framework/tables"
;
@import
"framework/notes"
;
@import
"framework/tabs"
;
@import
"framework/timeline"
;
@import
"framework/tooltips"
;
@import
"framework/toggle"
;
@import
"framework/typography"
;
@import
"framework/zen"
;
@import
"framework/blank"
;
@import
"framework/wells"
;
@import
"framework/page_header"
;
@import
"framework/awards"
;
@import
"framework/images"
;
@import
"framework/broadcast_messages"
;
@import
"framework/emojis"
;
@import
"framework/emoji_sprites"
;
@import
"framework/icons"
;
@import
"framework/snippets"
;
@import
"framework/memory_graph"
;
@import
"framework/responsive_tables"
;
@import
"framework/stacked_progress_bar"
;
@import
"framework/ci_variable_list"
;
@import
"framework/feature_highlight"
;
@import
'framework/animations'
;
@import
'framework/vue_transitions'
;
@import
'framework/avatar'
;
@import
'framework/asciidoctor'
;
@import
'framework/banner'
;
@import
'framework/blocks'
;
@import
'framework/buttons'
;
@import
'framework/badges'
;
@import
'framework/calendar'
;
@import
'framework/callout'
;
@import
'framework/common'
;
@import
'framework/dropdowns'
;
@import
'framework/files'
;
@import
'framework/filters'
;
@import
'framework/flash'
;
@import
'framework/forms'
;
@import
'framework/gfm'
;
@import
'framework/gitlab_theme'
;
@import
'framework/header'
;
@import
'framework/highlight'
;
@import
'framework/issue_box'
;
@import
'framework/jquery'
;
@import
'framework/lists'
;
@import
'framework/logo'
;
@import
'framework/markdown_area'
;
@import
'framework/media_object'
;
@import
'framework/mobile'
;
@import
'framework/modal'
;
@import
'framework/pagination'
;
@import
'framework/panels'
;
@import
'framework/popup'
;
@import
'framework/secondary_navigation_elements'
;
@import
'framework/selects'
;
@import
'framework/sidebar'
;
@import
'framework/contextual_sidebar'
;
@import
'framework/tables'
;
@import
'framework/notes'
;
@import
'framework/tabs'
;
@import
'framework/timeline'
;
@import
'framework/tooltips'
;
@import
'framework/toggle'
;
@import
'framework/typography'
;
@import
'framework/zen'
;
@import
'framework/blank'
;
@import
'framework/wells'
;
@import
'framework/page_header'
;
@import
'framework/awards'
;
@import
'framework/images'
;
@import
'framework/broadcast_messages'
;
@import
'framework/emojis'
;
@import
'framework/icons'
;
@import
'framework/snippets'
;
@import
'framework/memory_graph'
;
@import
'framework/responsive_tables'
;
@import
'framework/stacked_progress_bar'
;
@import
'framework/ci_variable_list'
;
@import
'framework/feature_highlight'
;
app/assets/stylesheets/framework/emoji_sprites.scss
deleted
100644 → 0
View file @
c7c9f38d
This diff is collapsed.
Click to expand it.
app/assets/stylesheets/pages/repo.scss.orig
deleted
100644 → 0
View file @
c7c9f38d
.project-refs-form,
.project-refs-target-form {
display: inline-block;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.commit-message {
@include str-truncated(250px);
}
.editable-mode {
display: inline-block;
}
.ide-view {
display: flex;
height: calc(100vh - #{$header-height});
margin-top: 40px;
color: $almost-black;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
&.is-collapsed {
.ide-file-list {
max-width: 250px;
}
}
.file-status-icon {
width: 10px;
height: 10px;
}
}
.ide-file-list {
flex: 1;
.file {
cursor: pointer;
&.file-open {
background: $white-normal;
}
.ide-file-name {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
svg {
vertical-align: middle;
margin-right: 2px;
}
.loading-container {
margin-right: 4px;
display: inline-block;
}
}
.ide-file-changed-icon {
margin-left: auto;
}
.ide-new-btn {
display: none;
margin-bottom: -4px;
margin-right: -8px;
}
&:hover {
.ide-new-btn {
display: block;
}
}
&.folder {
svg {
fill: $gl-text-color-secondary;
}
}
}
a {
color: $gl-text-color;
}
th {
position: sticky;
top: 0;
}
}
.file-name,
.file-col-commit-message {
display: flex;
overflow: visible;
padding: 6px 12px;
}
.multi-file-loading-container {
margin-top: 10px;
padding: 10px;
.animation-container {
background: $gray-light;
div {
background: $gray-light;
}
}
}
.multi-file-table-col-commit-message {
white-space: nowrap;
width: 50%;
}
.multi-file-edit-pane {
display: flex;
flex-direction: column;
flex: 1;
border-left: 1px solid $white-dark;
overflow: hidden;
}
.multi-file-tabs {
display: flex;
background-color: $white-normal;
box-shadow: inset 0 -1px $white-dark;
> ul {
display: flex;
overflow-x: auto;
}
li {
position: relative;
}
.dropdown {
display: flex;
margin-left: auto;
margin-bottom: 1px;
padding: 0 $grid-size;
border-left: 1px solid $white-dark;
background-color: $white-light;
&.shadow {
box-shadow: 0 0 10px $dropdown-shadow-color;
}
.btn {
margin-top: auto;
margin-bottom: auto;
}
}
}
.multi-file-tab {
@include str-truncated(150px);
padding: ($gl-padding / 2) ($gl-padding + 12) ($gl-padding / 2) $gl-padding;
background-color: $gray-normal;
border-right: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
cursor: pointer;
svg {
vertical-align: middle;
}
&.active {
background-color: $white-light;
border-bottom-color: $white-light;
}
}
.multi-file-tab-close {
position: absolute;
right: 8px;
top: 50%;
width: 16px;
height: 16px;
padding: 0;
background: none;
border: 0;
border-radius: $border-radius-default;
color: $theme-gray-900;
transform: translateY(-50%);
svg {
position: relative;
top: -1px;
}
&:hover {
background-color: $theme-gray-200;
}
&:focus {
background-color: $blue-500;
color: $white-light;
outline: 0;
svg {
fill: currentColor;
}
}
}
.multi-file-edit-pane-content {
flex: 1;
height: 0;
}
.blob-editor-container {
flex: 1;
height: 0;
display: flex;
flex-direction: column;
justify-content: center;
.vertical-center {
min-height: auto;
}
.monaco-editor .lines-content .cigr {
display: none;
}
.monaco-diff-editor.vs {
.editor.modified {
box-shadow: none;
}
.diagonal-fill {
display: none !important;
}
.diffOverview {
background-color: $white-light;
border-left: 1px solid $white-dark;
cursor: ns-resize;
}
.diffViewport {
display: none;
}
.char-insert {
background-color: $line-added-dark;
}
.char-delete {
background-color: $line-removed-dark;
}
.line-numbers {
color: $black-transparent;
}
.view-overlays {
.line-insert {
background-color: $line-added;
}
.line-delete {
background-color: $line-removed;
}
}
.margin {
background-color: $gray-light;
border-right: 1px solid $white-normal;
.line-insert {
border-right: 1px solid $line-added-dark;
}
.line-delete {
border-right: 1px solid $line-removed-dark;
}
}
.margin-view-overlays .insert-sign,
.margin-view-overlays .delete-sign {
opacity: 0.4;
}
.cursors-layer {
display: none;
}
}
}
.multi-file-editor-holder {
height: 100%;
}
.multi-file-editor-btn-group {
padding: $gl-bar-padding $gl-padding;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
background: $white-light;
}
.ide-status-bar {
padding: $gl-bar-padding $gl-padding;
background: $white-light;
display: flex;
justify-content: space-between;
svg {
vertical-align: middle;
}
}
// Not great, but this is to deal with our current output
.multi-file-preview-holder {
height: 100%;
overflow: scroll;
.file-content.code {
display: flex;
i {
margin-left: -10px;
}
}
.line-numbers {
min-width: 50px;
}
.file-content,
.line-numbers,
.blob-content,
.code {
min-height: 100%;
}
}
.file-content.blob-no-preview {
a {
margin-left: auto;
margin-right: auto;
}
}
.multi-file-commit-panel {
display: flex;
position: relative;
flex-direction: column;
width: 340px;
padding: 0;
background-color: $gray-light;
padding-right: 3px;
.projects-sidebar {
display: flex;
flex-direction: column;