Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
81429f61
Commit
81429f61
authored
Feb 06, 2019
by
Tim Zallmann
Committed by
Phil Hughes
Feb 06, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reduce Bundle Size by lazy loading markdown-it
parent
7c54409f
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
177 additions
and
74 deletions
+177
-74
app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
+22
-11
app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
...ets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
+23
-19
spec/features/markdown/copy_as_gfm_spec.rb
spec/features/markdown/copy_as_gfm_spec.rb
+15
-2
spec/javascripts/behaviors/copy_as_gfm_spec.js
spec/javascripts/behaviors/copy_as_gfm_spec.js
+26
-7
spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
...avascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
+91
-35
No files found.
app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
View file @
81429f61
import
$
from
'
jquery
'
;
import
{
DOMParser
}
from
'
prosemirror-model
'
;
import
{
getSelectedFragment
}
from
'
~/lib/utils/common_utils
'
;
import
schema
from
'
./schema
'
;
import
markdownSerializer
from
'
./serializer
'
;
export
class
CopyAsGFM
{
constructor
()
{
...
...
@@ -39,9 +36,13 @@ export class CopyAsGFM {
div
.
appendChild
(
el
.
cloneNode
(
true
));
const
html
=
div
.
innerHTML
;
clipboardData
.
setData
(
'
text/plain
'
,
el
.
textContent
);
clipboardData
.
setData
(
'
text/x-gfm
'
,
this
.
nodeToGFM
(
el
));
clipboardData
.
setData
(
'
text/html
'
,
html
);
CopyAsGFM
.
nodeToGFM
(
el
)
.
then
(
res
=>
{
clipboardData
.
setData
(
'
text/plain
'
,
el
.
textContent
);
clipboardData
.
setData
(
'
text/x-gfm
'
,
res
);
clipboardData
.
setData
(
'
text/html
'
,
html
);
})
.
catch
(()
=>
{});
}
static
pasteGFM
(
e
)
{
...
...
@@ -137,11 +138,21 @@ export class CopyAsGFM {
}
static
nodeToGFM
(
node
)
{
const
wrapEl
=
document
.
createElement
(
'
div
'
);
wrapEl
.
appendChild
(
node
.
cloneNode
(
true
));
const
doc
=
DOMParser
.
fromSchema
(
schema
).
parse
(
wrapEl
);
return
markdownSerializer
.
serialize
(
doc
);
return
Promise
.
all
([
import
(
/* webpackChunkName: 'gfm_copy_extra' */
'
prosemirror-model
'
),
import
(
/* webpackChunkName: 'gfm_copy_extra' */
'
./schema
'
),
import
(
/* webpackChunkName: 'gfm_copy_extra' */
'
./serializer
'
),
])
.
then
(([
prosemirrorModel
,
schema
,
markdownSerializer
])
=>
{
const
{
DOMParser
}
=
prosemirrorModel
;
const
wrapEl
=
document
.
createElement
(
'
div
'
);
wrapEl
.
appendChild
(
node
.
cloneNode
(
true
));
const
doc
=
DOMParser
.
fromSchema
(
schema
.
default
).
parse
(
wrapEl
);
const
res
=
markdownSerializer
.
default
.
serialize
(
doc
);
return
res
;
})
.
catch
(()
=>
{});
}
}
...
...
app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
View file @
81429f61
...
...
@@ -64,26 +64,30 @@ export default class ShortcutsIssuable extends Shortcuts {
const
el
=
CopyAsGFM
.
transformGFMSelection
(
documentFragment
.
cloneNode
(
true
));
const
blockquoteEl
=
document
.
createElement
(
'
blockquote
'
);
blockquoteEl
.
appendChild
(
el
);
const
text
=
CopyAsGFM
.
nodeToGFM
(
blockquoteEl
);
if
(
text
.
trim
()
===
''
)
{
return
false
;
}
// If replyField already has some content, add a newline before our quote
const
separator
=
(
$replyField
.
val
().
trim
()
!==
''
&&
'
\n\n
'
)
||
''
;
$replyField
.
val
((
a
,
current
)
=>
`
${
current
}${
separator
}${
text
}
\n\n`
)
.
trigger
(
'
input
'
)
.
trigger
(
'
change
'
);
// Trigger autosize
const
event
=
document
.
createEvent
(
'
Event
'
);
event
.
initEvent
(
'
autosize:update
'
,
true
,
false
);
$replyField
.
get
(
0
).
dispatchEvent
(
event
);
CopyAsGFM
.
nodeToGFM
(
blockquoteEl
)
.
then
(
text
=>
{
if
(
text
.
trim
()
===
''
)
{
return
false
;
}
// If replyField already has some content, add a newline before our quote
const
separator
=
(
$replyField
.
val
().
trim
()
!==
''
&&
'
\n\n
'
)
||
''
;
$replyField
.
val
((
a
,
current
)
=>
`
${
current
}${
separator
}${
text
}
\n\n`
)
.
trigger
(
'
input
'
)
.
trigger
(
'
change
'
);
// Trigger autosize
const
event
=
document
.
createEvent
(
'
Event
'
);
event
.
initEvent
(
'
autosize:update
'
,
true
,
false
);
$replyField
.
get
(
0
).
dispatchEvent
(
event
);
// Focus the input field
$replyField
.
focus
();
// Focus the input field
$replyField
.
focus
();
return
false
;
})
.
catch
(()
=>
{});
return
false
;
}
...
...
spec/features/markdown/copy_as_gfm_spec.rb
View file @
81429f61
...
...
@@ -843,6 +843,7 @@ describe 'Copy as GFM', :js do
def
verify
(
selector
,
gfm
,
target:
nil
)
html
=
html_for_selector
(
selector
)
output_gfm
=
html_to_gfm
(
html
,
'transformCodeSelection'
,
target:
target
)
wait_for_requests
expect
(
output_gfm
.
strip
).
to
eq
(
gfm
.
strip
)
end
end
...
...
@@ -861,6 +862,9 @@ describe 'Copy as GFM', :js do
def
html_to_gfm
(
html
,
transformer
=
'transformGFMSelection'
,
target:
nil
)
js
=
<<~
JS
(function(html) {
// Setting it off so the import already starts
window.CopyAsGFM.nodeToGFM(document.createElement('div'));
var transformer = window.CopyAsGFM[
#{
transformer
.
inspect
}
];
var node = document.createElement('div');
...
...
@@ -875,9 +879,18 @@ describe 'Copy as GFM', :js do
node = transformer(node, target);
if (!node) return null;
return window.CopyAsGFM.nodeToGFM(node);
window.gfmCopytestRes = null;
window.CopyAsGFM.nodeToGFM(node)
.then((res) => {
window.gfmCopytestRes = res;
});
})("
#{
escape_javascript
(
html
)
}
")
JS
page
.
evaluate_script
(
js
)
page
.
execute_script
(
js
)
loop
until
page
.
evaluate_script
(
'window.gfmCopytestRes !== null'
)
page
.
evaluate_script
(
'window.gfmCopytestRes'
)
end
end
spec/javascripts/behaviors/copy_as_gfm_spec.js
View file @
81429f61
import
{
CopyAsGFM
}
from
'
~/behaviors/markdown/copy_as_gfm
'
;
import
initCopyAsGFM
,
{
CopyAsGFM
}
from
'
~/behaviors/markdown/copy_as_gfm
'
;
describe
(
'
CopyAsGFM
'
,
()
=>
{
describe
(
'
CopyAsGFM.pasteGFM
'
,
()
=>
{
...
...
@@ -79,27 +79,46 @@ describe('CopyAsGFM', () => {
return
clipboardData
;
};
beforeAll
(
done
=>
{
initCopyAsGFM
();
// Fake call to nodeToGfm so the import of lazy bundle happened
CopyAsGFM
.
nodeToGFM
(
document
.
createElement
(
'
div
'
))
.
then
(()
=>
{
done
();
})
.
catch
(
done
.
fail
);
});
beforeEach
(()
=>
spyOn
(
clipboardData
,
'
setData
'
));
describe
(
'
list handling
'
,
()
=>
{
it
(
'
uses correct gfm for unordered lists
'
,
()
=>
{
it
(
'
uses correct gfm for unordered lists
'
,
done
=>
{
const
selection
=
stubSelection
(
'
<li>List Item1</li><li>List Item2</li>
\n
'
,
'
UL
'
);
spyOn
(
window
,
'
getSelection
'
).
and
.
returnValue
(
selection
);
simulateCopy
();
const
expectedGFM
=
'
* List Item1
\n\n
* List Item2
'
;
setTimeout
(()
=>
{
const
expectedGFM
=
'
* List Item1
\n\n
* List Item2
'
;
expect
(
clipboardData
.
setData
).
toHaveBeenCalledWith
(
'
text/x-gfm
'
,
expectedGFM
);
expect
(
clipboardData
.
setData
).
toHaveBeenCalledWith
(
'
text/x-gfm
'
,
expectedGFM
);
done
();
});
});
it
(
'
uses correct gfm for ordered lists
'
,
()
=>
{
it
(
'
uses correct gfm for ordered lists
'
,
done
=>
{
const
selection
=
stubSelection
(
'
<li>List Item1</li><li>List Item2</li>
\n
'
,
'
OL
'
);
spyOn
(
window
,
'
getSelection
'
).
and
.
returnValue
(
selection
);
simulateCopy
();
const
expectedGFM
=
'
1. List Item1
\n\n
1. List Item2
'
;
setTimeout
(()
=>
{
const
expectedGFM
=
'
1. List Item1
\n\n
1. List Item2
'
;
expect
(
clipboardData
.
setData
).
toHaveBeenCalledWith
(
'
text/x-gfm
'
,
expectedGFM
);
expect
(
clipboardData
.
setData
).
toHaveBeenCalledWith
(
'
text/x-gfm
'
,
expectedGFM
);
done
();
});
});
});
});
...
...
spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
View file @
81429f61
...
...
@@ -3,17 +3,26 @@
*/
import
$
from
'
jquery
'
;
import
initCopyAsGFM
from
'
~/behaviors/markdown/copy_as_gfm
'
;
import
initCopyAsGFM
,
{
CopyAsGFM
}
from
'
~/behaviors/markdown/copy_as_gfm
'
;
import
ShortcutsIssuable
from
'
~/behaviors/shortcuts/shortcuts_issuable
'
;
initCopyAsGFM
();
const
FORM_SELECTOR
=
'
.js-main-target-form .js-vue-comment-form
'
;
describe
(
'
ShortcutsIssuable
'
,
function
()
{
const
fixtureName
=
'
snippets/show.html.raw
'
;
preloadFixtures
(
fixtureName
);
beforeAll
(
done
=>
{
initCopyAsGFM
();
// Fake call to nodeToGfm so the import of lazy bundle happened
CopyAsGFM
.
nodeToGFM
(
document
.
createElement
(
'
div
'
))
.
then
(()
=>
{
done
();
})
.
catch
(
done
.
fail
);
});
beforeEach
(()
=>
{
loadFixtures
(
fixtureName
);
$
(
'
body
'
).
append
(
...
...
@@ -63,17 +72,22 @@ describe('ShortcutsIssuable', function() {
stubSelection
(
'
<p>Selected text.</p>
'
);
});
it
(
'
leaves existing input intact
'
,
()
=>
{
it
(
'
leaves existing input intact
'
,
done
=>
{
$
(
FORM_SELECTOR
).
val
(
'
This text was already here.
'
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
This text was already here.
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
This text was already here.
\n\n
> Selected text.
\n\n
'
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
This text was already here.
\n\n
> Selected text.
\n\n
'
,
);
done
();
});
});
it
(
'
triggers `input`
'
,
()
=>
{
it
(
'
triggers `input`
'
,
done
=>
{
let
triggered
=
false
;
$
(
FORM_SELECTOR
).
on
(
'
input
'
,
()
=>
{
triggered
=
true
;
...
...
@@ -81,36 +95,48 @@ describe('ShortcutsIssuable', function() {
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
triggered
).
toBe
(
true
);
setTimeout
(()
=>
{
expect
(
triggered
).
toBe
(
true
);
done
();
});
});
it
(
'
triggers `focus`
'
,
()
=>
{
it
(
'
triggers `focus`
'
,
done
=>
{
const
spy
=
spyOn
(
document
.
querySelector
(
FORM_SELECTOR
),
'
focus
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
spy
).
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
spy
).
toHaveBeenCalled
();
done
();
});
});
});
describe
(
'
with a one-line selection
'
,
()
=>
{
it
(
'
quotes the selection
'
,
()
=>
{
it
(
'
quotes the selection
'
,
done
=>
{
stubSelection
(
'
<p>This text has been selected.</p>
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> This text has been selected.
\n\n
'
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> This text has been selected.
\n\n
'
);
done
();
});
});
});
describe
(
'
with a multi-line selection
'
,
()
=>
{
it
(
'
quotes the selected lines as a group
'
,
()
=>
{
it
(
'
quotes the selected lines as a group
'
,
done
=>
{
stubSelection
(
'
<p>Selected line one.</p>
\n
<p>Selected line two.</p>
\n
<p>Selected line three.</p>
'
,
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> Selected line one.
\n
>
\n
> Selected line two.
\n
>
\n
> Selected line three.
\n\n
'
,
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> Selected line one.
\n
>
\n
> Selected line two.
\n
>
\n
> Selected line three.
\n\n
'
,
);
done
();
});
});
});
...
...
@@ -119,17 +145,23 @@ describe('ShortcutsIssuable', function() {
stubSelection
(
'
<p>Selected text.</p>
'
,
true
);
});
it
(
'
does not add anything to the input
'
,
()
=>
{
it
(
'
does not add anything to the input
'
,
done
=>
{
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
''
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
''
);
done
();
});
});
it
(
'
triggers `focus`
'
,
()
=>
{
it
(
'
triggers `focus`
'
,
done
=>
{
const
spy
=
spyOn
(
document
.
querySelector
(
FORM_SELECTOR
),
'
focus
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
spy
).
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
spy
).
toHaveBeenCalled
();
done
();
});
});
});
...
...
@@ -138,20 +170,26 @@ describe('ShortcutsIssuable', function() {
stubSelection
(
'
<div class="md">Selected text.</div><p>Invalid selected text.</p>
'
,
true
);
});
it
(
'
only adds the valid part to the input
'
,
()
=>
{
it
(
'
only adds the valid part to the input
'
,
done
=>
{
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> Selected text.
\n\n
'
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> Selected text.
\n\n
'
);
done
();
});
});
it
(
'
triggers `focus`
'
,
()
=>
{
it
(
'
triggers `focus`
'
,
done
=>
{
const
spy
=
spyOn
(
document
.
querySelector
(
FORM_SELECTOR
),
'
focus
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
spy
).
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
spy
).
toHaveBeenCalled
();
done
();
});
});
it
(
'
triggers `input`
'
,
()
=>
{
it
(
'
triggers `input`
'
,
done
=>
{
let
triggered
=
false
;
$
(
FORM_SELECTOR
).
on
(
'
input
'
,
()
=>
{
triggered
=
true
;
...
...
@@ -159,7 +197,10 @@ describe('ShortcutsIssuable', function() {
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
triggered
).
toBe
(
true
);
setTimeout
(()
=>
{
expect
(
triggered
).
toBe
(
true
);
done
();
});
});
});
...
...
@@ -183,20 +224,26 @@ describe('ShortcutsIssuable', function() {
});
});
it
(
'
adds the quoted selection to the input
'
,
()
=>
{
it
(
'
adds the quoted selection to the input
'
,
done
=>
{
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> *Selected text.*
\n\n
'
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
'
> *Selected text.*
\n\n
'
);
done
();
});
});
it
(
'
triggers `focus`
'
,
()
=>
{
it
(
'
triggers `focus`
'
,
done
=>
{
const
spy
=
spyOn
(
document
.
querySelector
(
FORM_SELECTOR
),
'
focus
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
spy
).
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
spy
).
toHaveBeenCalled
();
done
();
});
});
it
(
'
triggers `input`
'
,
()
=>
{
it
(
'
triggers `input`
'
,
done
=>
{
let
triggered
=
false
;
$
(
FORM_SELECTOR
).
on
(
'
input
'
,
()
=>
{
triggered
=
true
;
...
...
@@ -204,7 +251,10 @@ describe('ShortcutsIssuable', function() {
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
triggered
).
toBe
(
true
);
setTimeout
(()
=>
{
expect
(
triggered
).
toBe
(
true
);
done
();
});
});
});
...
...
@@ -228,17 +278,23 @@ describe('ShortcutsIssuable', function() {
});
});
it
(
'
does not add anything to the input
'
,
()
=>
{
it
(
'
does not add anything to the input
'
,
done
=>
{
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
''
);
setTimeout
(()
=>
{
expect
(
$
(
FORM_SELECTOR
).
val
()).
toBe
(
''
);
done
();
});
});
it
(
'
triggers `focus`
'
,
()
=>
{
it
(
'
triggers `focus`
'
,
done
=>
{
const
spy
=
spyOn
(
document
.
querySelector
(
FORM_SELECTOR
),
'
focus
'
);
ShortcutsIssuable
.
replyWithSelectedText
(
true
);
expect
(
spy
).
toHaveBeenCalled
();
setTimeout
(()
=>
{
expect
(
spy
).
toHaveBeenCalled
();
done
();
});
});
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment