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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
36a917e1
Commit
36a917e1
authored
Sep 22, 2017
by
Fatih Acet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
RepoEditor: Implement line and range linking.
parent
92173ac5
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
151 additions
and
146 deletions
+151
-146
app/assets/javascripts/line_highlighter.js
app/assets/javascripts/line_highlighter.js
+142
-141
app/assets/javascripts/repo/components/repo_preview.vue
app/assets/javascripts/repo/components/repo_preview.vue
+9
-5
No files found.
app/assets/javascripts/line_highlighter.js
View file @
36a917e1
...
...
@@ -28,148 +28,149 @@
// </div>
// </div>
//
(
function
()
{
this
.
LineHighlighter
=
(
function
()
{
// CSS class applied to highlighted lines
LineHighlighter
.
prototype
.
highlightClass
=
'
hll
'
;
// Internal copy of location.hash so we're not dependent on `location` in tests
LineHighlighter
.
prototype
.
_hash
=
''
;
function
LineHighlighter
(
hash
)
{
if
(
hash
==
null
)
{
// Initialize a LineHighlighter object
//
// hash - String URL hash for dependency injection in tests
hash
=
location
.
hash
;
}
this
.
setHash
=
this
.
setHash
.
bind
(
this
);
this
.
highlightLine
=
this
.
highlightLine
.
bind
(
this
);
this
.
clickHandler
=
this
.
clickHandler
.
bind
(
this
);
this
.
highlightHash
=
this
.
highlightHash
.
bind
(
this
);
this
.
_hash
=
hash
;
this
.
bindEvents
();
this
.
highlightHash
();
}
LineHighlighter
.
prototype
.
bindEvents
=
function
()
{
const
$fileHolder
=
$
(
'
.file-holder
'
);
$fileHolder
.
on
(
'
click
'
,
'
a[data-line-number]
'
,
this
.
clickHandler
);
$fileHolder
.
on
(
'
highlight:line
'
,
this
.
highlightHash
);
};
LineHighlighter
.
prototype
.
highlightHash
=
function
()
{
var
range
;
if
(
this
.
_hash
!==
''
)
{
range
=
this
.
hashToRange
(
this
.
_hash
);
if
(
range
[
0
])
{
this
.
highlightRange
(
range
);
$
.
scrollTo
(
"
#L
"
+
range
[
0
],
{
// Scroll to the first highlighted line on initial load
// Offset -50 for the sticky top bar, and another -100 for some context
offset
:
-
150
});
}
}
};
LineHighlighter
.
prototype
.
clickHandler
=
function
(
event
)
{
var
current
,
lineNumber
,
range
;
event
.
preventDefault
();
this
.
clearHighlight
();
lineNumber
=
$
(
event
.
target
).
closest
(
'
a
'
).
data
(
'
line-number
'
);
current
=
this
.
hashToRange
(
this
.
_hash
);
if
(
!
(
current
[
0
]
&&
event
.
shiftKey
))
{
// If there's no current selection, or there is but Shift wasn't held,
// treat this like a single-line selection.
this
.
setHash
(
lineNumber
);
return
this
.
highlightLine
(
lineNumber
);
}
else
if
(
event
.
shiftKey
)
{
if
(
lineNumber
<
current
[
0
])
{
range
=
[
lineNumber
,
current
[
0
]];
}
else
{
range
=
[
current
[
0
],
lineNumber
];
}
this
.
setHash
(
range
[
0
],
range
[
1
]);
return
this
.
highlightRange
(
range
);
}
};
LineHighlighter
.
prototype
.
clearHighlight
=
function
()
{
return
$
(
"
.
"
+
this
.
highlightClass
).
removeClass
(
this
.
highlightClass
);
// Unhighlight previously highlighted lines
};
// Convert a URL hash String into line numbers
//
// hash - Hash String
//
// Examples:
//
// hashToRange('#L5') # => [5, null]
// hashToRange('#L5-15') # => [5, 15]
// hashToRange('#foo') # => [null, null]
//
// Returns an Array
LineHighlighter
.
prototype
.
hashToRange
=
function
(
hash
)
{
var
first
,
last
,
matches
;
// ?L(\d+)(?:-(\d+))?$/)
matches
=
hash
.
match
(
/^#
?
L
(\d
+
)(?:
-
(\d
+
))?
$/
);
if
(
matches
&&
matches
.
length
)
{
first
=
parseInt
(
matches
[
1
],
10
);
last
=
matches
[
2
]
?
parseInt
(
matches
[
2
],
10
)
:
null
;
return
[
first
,
last
];
}
else
{
return
[
null
,
null
];
}
};
// Highlight a single line
//
// lineNumber - Line number to highlight
LineHighlighter
.
prototype
.
highlightLine
=
function
(
lineNumber
)
{
return
$
(
"
#LC
"
+
lineNumber
).
addClass
(
this
.
highlightClass
);
};
// Highlight all lines within a range
//
// range - Array containing the starting and ending line numbers
LineHighlighter
.
prototype
.
highlightRange
=
function
(
range
)
{
var
i
,
lineNumber
,
ref
,
ref1
,
results
;
if
(
range
[
1
])
{
results
=
[];
for
(
lineNumber
=
i
=
ref
=
range
[
0
],
ref1
=
range
[
1
];
ref
<=
ref1
?
i
<=
ref1
:
i
>=
ref1
;
lineNumber
=
ref
<=
ref1
?
(
i
+=
1
)
:
(
i
-=
1
))
{
results
.
push
(
this
.
highlightLine
(
lineNumber
));
}
return
results
;
}
else
{
return
this
.
highlightLine
(
range
[
0
]);
}
};
const
LineHighlighter
=
function
(
options
=
{})
{
options
.
highlightLineClass
=
options
.
highlightLineClass
||
'
hll
'
;
options
.
fileHolderSelector
=
options
.
fileHolderSelector
||
'
.file-holder
'
;
options
.
scrollFileHolder
=
options
.
scrollFileHolder
||
false
;
options
.
hash
=
options
.
hash
||
location
.
hash
;
// Set the URL hash string
LineHighlighter
.
prototype
.
setHash
=
function
(
firstLineNumber
,
lastLineNumber
)
{
var
hash
;
if
(
lastLineNumber
)
{
hash
=
"
#L
"
+
firstLineNumber
+
"
-
"
+
lastLineNumber
;
this
.
options
=
options
;
this
.
_hash
=
options
.
hash
;
this
.
highlightLineClass
=
options
.
highlightLineClass
;
this
.
setHash
=
this
.
setHash
.
bind
(
this
);
this
.
highlightLine
=
this
.
highlightLine
.
bind
(
this
);
this
.
clickHandler
=
this
.
clickHandler
.
bind
(
this
);
this
.
highlightHash
=
this
.
highlightHash
.
bind
(
this
);
this
.
bindEvents
();
this
.
highlightHash
();
};
LineHighlighter
.
prototype
.
bindEvents
=
function
()
{
const
$fileHolder
=
$
(
this
.
options
.
fileHolderSelector
);
$fileHolder
.
on
(
'
click
'
,
'
a[data-line-number]
'
,
this
.
clickHandler
);
$fileHolder
.
on
(
'
highlight:line
'
,
this
.
highlightHash
);
};
LineHighlighter
.
prototype
.
highlightHash
=
function
()
{
var
range
;
if
(
this
.
_hash
!==
''
)
{
range
=
this
.
hashToRange
(
this
.
_hash
);
if
(
range
[
0
])
{
this
.
highlightRange
(
range
);
const
lineSelector
=
`#L
${
range
[
0
]}
`
;
const
scrollOptions
=
{
// Scroll to the first highlighted line on initial load
// Offset -50 for the sticky top bar, and another -100 for some context
offset
:
-
150
};
if
(
this
.
options
.
scrollFileHolder
)
{
$
(
this
.
options
.
fileHolderSelector
).
scrollTo
(
lineSelector
,
scrollOptions
);
}
else
{
hash
=
"
#L
"
+
firstLineNumber
;
$
.
scrollTo
(
lineSelector
,
scrollOptions
)
;
}
this
.
_hash
=
hash
;
return
this
.
__setLocationHash__
(
hash
);
};
// Make the actual hash change in the browser
//
// This method is stubbed in tests.
LineHighlighter
.
prototype
.
__setLocationHash__
=
function
(
value
)
{
return
history
.
pushState
({
url
:
value
// We're using pushState instead of assigning location.hash directly to
// prevent the page from scrolling on the hashchange event
},
document
.
title
,
value
);
};
return
LineHighlighter
;
})();
}).
call
(
window
);
}
}
};
LineHighlighter
.
prototype
.
clickHandler
=
function
(
event
)
{
var
current
,
lineNumber
,
range
;
event
.
preventDefault
();
this
.
clearHighlight
();
lineNumber
=
$
(
event
.
target
).
closest
(
'
a
'
).
data
(
'
line-number
'
);
current
=
this
.
hashToRange
(
this
.
_hash
);
if
(
!
(
current
[
0
]
&&
event
.
shiftKey
))
{
// If there's no current selection, or there is but Shift wasn't held,
// treat this like a single-line selection.
this
.
setHash
(
lineNumber
);
return
this
.
highlightLine
(
lineNumber
);
}
else
if
(
event
.
shiftKey
)
{
if
(
lineNumber
<
current
[
0
])
{
range
=
[
lineNumber
,
current
[
0
]];
}
else
{
range
=
[
current
[
0
],
lineNumber
];
}
this
.
setHash
(
range
[
0
],
range
[
1
]);
return
this
.
highlightRange
(
range
);
}
};
LineHighlighter
.
prototype
.
clearHighlight
=
function
()
{
return
$
(
"
.
"
+
this
.
highlightLineClass
).
removeClass
(
this
.
highlightLineClass
);
};
// Convert a URL hash String into line numbers
//
// hash - Hash String
//
// Examples:
//
// hashToRange('#L5') # => [5, null]
// hashToRange('#L5-15') # => [5, 15]
// hashToRange('#foo') # => [null, null]
//
// Returns an Array
LineHighlighter
.
prototype
.
hashToRange
=
function
(
hash
)
{
var
first
,
last
,
matches
;
// ?L(\d+)(?:-(\d+))?$/)
matches
=
hash
.
match
(
/^#
?
L
(\d
+
)(?:
-
(\d
+
))?
$/
);
if
(
matches
&&
matches
.
length
)
{
first
=
parseInt
(
matches
[
1
],
10
);
last
=
matches
[
2
]
?
parseInt
(
matches
[
2
],
10
)
:
null
;
return
[
first
,
last
];
}
else
{
return
[
null
,
null
];
}
};
// Highlight a single line
//
// lineNumber - Line number to highlight
LineHighlighter
.
prototype
.
highlightLine
=
function
(
lineNumber
)
{
return
$
(
"
#LC
"
+
lineNumber
).
addClass
(
this
.
highlightLineClass
);
};
// Highlight all lines within a range
//
// range - Array containing the starting and ending line numbers
LineHighlighter
.
prototype
.
highlightRange
=
function
(
range
)
{
var
i
,
lineNumber
,
ref
,
ref1
,
results
;
if
(
range
[
1
])
{
results
=
[];
for
(
lineNumber
=
i
=
ref
=
range
[
0
],
ref1
=
range
[
1
];
ref
<=
ref1
?
i
<=
ref1
:
i
>=
ref1
;
lineNumber
=
ref
<=
ref1
?
(
i
+=
1
)
:
(
i
-=
1
))
{
results
.
push
(
this
.
highlightLine
(
lineNumber
));
}
return
results
;
}
else
{
return
this
.
highlightLine
(
range
[
0
]);
}
};
// Set the URL hash string
LineHighlighter
.
prototype
.
setHash
=
function
(
firstLineNumber
,
lastLineNumber
)
{
var
hash
;
if
(
lastLineNumber
)
{
hash
=
"
#L
"
+
firstLineNumber
+
"
-
"
+
lastLineNumber
;
}
else
{
hash
=
"
#L
"
+
firstLineNumber
;
}
this
.
_hash
=
hash
;
return
this
.
__setLocationHash__
(
hash
);
};
// Make the actual hash change in the browser
//
// This method is stubbed in tests.
LineHighlighter
.
prototype
.
__setLocationHash__
=
function
(
value
)
{
return
history
.
pushState
({
url
:
value
// We're using pushState instead of assigning location.hash directly to
// prevent the page from scrolling on the hashchange event
},
document
.
title
,
value
);
};
window
.
LineHighlighter
=
LineHighlighter
;
app/assets/javascripts/repo/components/repo_preview.vue
View file @
36a917e1
<
script
>
/* global LineHighlighter */
import
Store
from
'
../stores/repo_store
'
;
export
default
{
data
:
()
=>
Store
,
mounted
()
{
this
.
highlightFile
();
},
computed
:
{
html
()
{
return
this
.
activeFile
.
html
;
},
},
methods
:
{
highlightFile
()
{
$
(
this
.
$el
).
find
(
'
.file-content
'
).
syntaxHighlight
();
},
},
mounted
()
{
this
.
highlightFile
();
this
.
lineHighlighter
=
new
LineHighlighter
({
fileHolderSelector
:
'
.blob-viewer-container
'
,
scrollFileHolder
:
true
,
});
},
watch
:
{
html
()
{
this
.
$nextTick
(()
=>
{
...
...
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