Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
7179ee19
Commit
7179ee19
authored
Apr 14, 2016
by
Nick Stenning
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3201 from hypothesis/markdown-input-refactor
Markdown editor input refactor and additional tests
parents
3f39169f
37405915
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
127 additions
and
51 deletions
+127
-51
annotation.js
h/static/scripts/directive/annotation.js
+4
-0
markdown.js
h/static/scripts/directive/markdown.js
+24
-34
markdown-test.js
h/static/scripts/directive/test/markdown-test.js
+82
-8
util.js
h/static/scripts/directive/test/util.js
+8
-3
annotation.html
h/templates/client/annotation.html
+2
-1
markdown.html
h/templates/client/markdown.html
+7
-5
No files found.
h/static/scripts/directive/annotation.js
View file @
7179ee19
...
@@ -713,6 +713,10 @@ function AnnotationController(
...
@@ -713,6 +713,10 @@ function AnnotationController(
$scope
.
$digest
();
$scope
.
$digest
();
};
};
vm
.
setText
=
function
(
text
)
{
vm
.
form
.
text
=
text
;
};
init
();
init
();
}
}
...
...
h/static/scripts/directive/markdown.js
View file @
7179ee19
...
@@ -15,11 +15,10 @@ var mediaEmbedder = require('../media-embedder');
...
@@ -15,11 +15,10 @@ var mediaEmbedder = require('../media-embedder');
* the markdown editor.
* the markdown editor.
*/
*/
// @ngInject
// @ngInject
module
.
exports
=
function
(
$filter
,
$sanitize
,
$sce
)
{
module
.
exports
=
function
(
$filter
,
$sanitize
)
{
return
{
return
{
link
:
function
(
scope
,
elem
,
attr
,
ctrl
)
{
controller
:
function
()
{},
if
(
!
(
typeof
ctrl
!==
"undefined"
&&
ctrl
!==
null
))
{
return
;
}
link
:
function
(
scope
,
elem
)
{
var
input
=
elem
[
0
].
querySelector
(
'.js-markdown-input'
);
var
input
=
elem
[
0
].
querySelector
(
'.js-markdown-input'
);
var
inputEl
=
angular
.
element
(
input
);
var
inputEl
=
angular
.
element
(
input
);
var
output
=
elem
[
0
].
querySelector
(
'.js-markdown-preview'
);
var
output
=
elem
[
0
].
querySelector
(
'.js-markdown-preview'
);
...
@@ -128,17 +127,8 @@ module.exports = function($filter, $sanitize, $sce) {
...
@@ -128,17 +127,8 @@ module.exports = function($filter, $sanitize, $sce) {
});
});
scope
.
preview
=
false
;
scope
.
preview
=
false
;
scope
.
togglePreview
=
function
()
{
scope
.
togglePreview
=
function
()
{
if
(
!
scope
.
readOnly
)
{
scope
.
preview
=
!
scope
.
preview
;
scope
.
preview
=
!
scope
.
preview
;
if
(
scope
.
preview
)
{
output
.
style
.
height
=
input
.
style
.
height
;
return
ctrl
.
$render
();
}
else
{
input
.
style
.
height
=
output
.
style
.
height
;
focusInput
();
}
}
};
};
var
renderInlineMath
=
function
(
textToCheck
)
{
var
renderInlineMath
=
function
(
textToCheck
)
{
...
@@ -229,38 +219,38 @@ module.exports = function($filter, $sanitize, $sce) {
...
@@ -229,38 +219,38 @@ module.exports = function($filter, $sanitize, $sce) {
return
domElement
.
innerHTML
;
return
domElement
.
innerHTML
;
};
};
// React to the changes to the input
inputEl
.
bind
(
'blur change keyup'
,
function
()
{
scope
.
onEditText
({
text
:
input
.
value
});
});
// Re-render the markdown when the view needs updating.
// Re-render the markdown when the view needs updating.
ctrl
.
$render
=
function
()
{
scope
.
$watch
(
'text'
,
function
()
{
if
(
!
scope
.
readOnly
&&
!
scope
.
preview
)
{
output
.
innerHTML
=
renderMathAndMarkdown
(
scope
.
text
||
''
);
input
.
value
=
ctrl
.
$viewValue
||
''
;
})
;
}
var
value
=
ctrl
.
$viewValue
||
''
;
scope
.
showEditor
=
function
()
{
output
.
innerHTML
=
renderMathAndMarkdown
(
value
)
;
return
!
scope
.
readOnly
&&
!
scope
.
preview
;
};
};
// React to the changes to the input
scope
.
$watch
(
'readOnly'
,
function
()
{
inputEl
.
bind
(
'blur change keyup'
,
function
()
{
// Exit preview mode when editor stops
ctrl
.
$setViewValue
(
input
.
value
)
;
scope
.
preview
=
false
;
});
});
// Reset height of output div in case it has been changed.
scope
.
$watch
(
'showEditor()'
,
function
(
show
)
{
// Re-render when it becomes uneditable.
if
(
show
)
{
// Auto-focus the input box when the widget becomes editable.
input
.
value
=
scope
.
text
||
''
;
scope
.
$watch
(
'readOnly'
,
function
(
readOnly
)
{
scope
.
preview
=
false
;
output
.
style
.
height
=
""
;
ctrl
.
$render
();
if
(
!
readOnly
)
{
focusInput
();
focusInput
();
}
}
});
});
},
},
require
:
'?ngModel'
,
restrict
:
'E'
,
restrict
:
'E'
,
scope
:
{
scope
:
{
readOnly
:
'<'
,
readOnly
:
'<'
,
required
:
'@'
text
:
'<?'
,
onEditText
:
'&'
,
},
},
template
:
require
(
'../../../templates/client/markdown.html'
),
template
:
require
(
'../../../templates/client/markdown.html'
),
};
};
...
...
h/static/scripts/directive/test/markdown-test.js
View file @
7179ee19
...
@@ -66,7 +66,7 @@ describe('markdown', function () {
...
@@ -66,7 +66,7 @@ describe('markdown', function () {
it
(
'should show the rendered view when readOnly is true'
,
function
()
{
it
(
'should show the rendered view when readOnly is true'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
true
,
readOnly
:
true
,
ngModel
:
'Hello World'
,
text
:
'Hello World'
,
});
});
assert
.
isTrue
(
isHidden
(
inputElement
(
editor
)));
assert
.
isTrue
(
isHidden
(
inputElement
(
editor
)));
assert
.
isFalse
(
isHidden
(
viewElement
(
editor
)));
assert
.
isFalse
(
isHidden
(
viewElement
(
editor
)));
...
@@ -75,7 +75,7 @@ describe('markdown', function () {
...
@@ -75,7 +75,7 @@ describe('markdown', function () {
it
(
'should show the editor when readOnly is false'
,
function
()
{
it
(
'should show the editor when readOnly is false'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
readOnly
:
false
,
ngModel
:
'Hello World'
,
text
:
'Hello World'
,
});
});
assert
.
isFalse
(
isHidden
(
inputElement
(
editor
)));
assert
.
isFalse
(
isHidden
(
inputElement
(
editor
)));
assert
.
isTrue
(
isHidden
(
viewElement
(
editor
)));
assert
.
isTrue
(
isHidden
(
viewElement
(
editor
)));
...
@@ -86,17 +86,22 @@ describe('markdown', function () {
...
@@ -86,17 +86,22 @@ describe('markdown', function () {
it
(
'should render input markdown'
,
function
()
{
it
(
'should render input markdown'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
true
,
readOnly
:
true
,
ngModel
:
'Hello World'
,
text
:
'Hello World'
,
});
});
assert
.
equal
(
getRenderedHTML
(
editor
),
'rendered:Hello World'
);
assert
.
equal
(
getRenderedHTML
(
editor
),
'rendered:Hello World'
);
});
});
it
(
'should render nothing if no text is provided'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
true
});
assert
.
equal
(
getRenderedHTML
(
editor
),
'rendered:'
);
});
});
});
describe
(
'math rendering'
,
function
()
{
describe
(
'math rendering'
,
function
()
{
it
(
'should render LaTeX'
,
function
()
{
it
(
'should render LaTeX'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
true
,
readOnly
:
true
,
ngModel
:
'$$x*2$$'
,
text
:
'$$x*2$$'
,
});
});
assert
.
equal
(
getRenderedHTML
(
editor
),
assert
.
equal
(
getRenderedHTML
(
editor
),
'rendered:math:
\\
displaystyle {x*2}rendered:'
);
'rendered:math:
\\
displaystyle {x*2}rendered:'
);
...
@@ -107,7 +112,7 @@ describe('markdown', function () {
...
@@ -107,7 +112,7 @@ describe('markdown', function () {
it
(
'should apply formatting when clicking toolbar buttons'
,
function
()
{
it
(
'should apply formatting when clicking toolbar buttons'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
readOnly
:
false
,
ngModel
:
'Hello World'
,
text
:
'Hello World'
,
});
});
var
input
=
inputElement
(
editor
);
var
input
=
inputElement
(
editor
);
var
buttons
=
editor
[
0
].
querySelectorAll
(
'.markdown-tools-button'
);
var
buttons
=
editor
[
0
].
querySelectorAll
(
'.markdown-tools-button'
);
...
@@ -120,15 +125,84 @@ describe('markdown', function () {
...
@@ -120,15 +125,84 @@ describe('markdown', function () {
});
});
describe
(
'editing'
,
function
()
{
describe
(
'editing'
,
function
()
{
it
(
'should update the input model'
,
function
()
{
it
(
'should populate the input with the current text'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
text
:
'initial comment'
,
onEditText
:
function
()
{},
});
var
input
=
inputElement
(
editor
);
assert
.
equal
(
input
.
value
,
'initial comment'
);
});
it
(
'should populate the input with empty text if no text is specified'
,
function
()
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
onEditText
:
function
()
{},
});
var
input
=
inputElement
(
editor
);
assert
.
equal
(
input
.
value
,
''
);
});
it
(
'should call onEditText() callback when text changes'
,
function
()
{
var
onEditText
=
sinon
.
stub
();
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
var
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
readOnly
:
false
,
ngModel
:
'Hello World'
,
text
:
'Hello World'
,
onEditText
:
{
args
:
[
'text'
],
callback
:
onEditText
,
},
});
});
var
input
=
inputElement
(
editor
);
var
input
=
inputElement
(
editor
);
input
.
value
=
'new text'
;
input
.
value
=
'new text'
;
util
.
sendEvent
(
input
,
'change'
);
util
.
sendEvent
(
input
,
'change'
);
assert
.
equal
(
editor
.
scope
.
ngModel
,
'new text'
);
assert
.
called
(
onEditText
);
assert
.
calledWith
(
onEditText
,
'new text'
);
});
});
describe
(
'preview state'
,
function
()
{
var
editor
;
function
togglePreview
()
{
var
toggle
=
editor
[
0
].
querySelector
(
'.markdown-tools-toggle'
);
angular
.
element
(
toggle
).
click
();
editor
.
scope
.
$digest
();
}
function
isPreviewing
()
{
return
editor
.
isolateScope
().
preview
;
}
beforeEach
(
function
()
{
// Create a new editor, initially in editing mode
editor
=
util
.
createDirective
(
document
,
'markdown'
,
{
readOnly
:
false
,
text
:
'Hello World'
,
});
});
it
(
'enters preview mode when clicking the "Preview" toggle button'
,
function
()
{
togglePreview
();
assert
.
isTrue
(
isPreviewing
());
});
it
(
'should hide the input when previewing changes'
,
function
()
{
togglePreview
();
assert
.
isTrue
(
isHidden
(
inputElement
(
editor
)));
});
it
(
'should show the rendered markdown when previewing changes'
,
function
()
{
togglePreview
();
assert
.
isFalse
(
isHidden
(
viewElement
(
editor
)));
});
it
(
'exits preview mode when switching to read-only mode'
,
function
()
{
togglePreview
();
editor
.
scope
.
readOnly
=
true
;
editor
.
scope
.
$digest
();
assert
.
isFalse
(
isPreviewing
());
});
});
});
});
});
});
h/static/scripts/directive/test/util.js
View file @
7179ee19
...
@@ -96,8 +96,8 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
...
@@ -96,8 +96,8 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
opts
=
opts
||
{};
opts
=
opts
||
{};
opts
.
parentElement
=
opts
.
parentElement
||
document
.
body
;
opts
.
parentElement
=
opts
.
parentElement
||
document
.
body
;
//
c
reate a template consisting of a single element, the directive
//
C
reate a template consisting of a single element, the directive
// we want to create and compile it
// we want to create and compile it
.
var
$compile
;
var
$compile
;
var
$scope
;
var
$scope
;
angular
.
mock
.
inject
(
function
(
_$compile_
,
_$rootScope_
)
{
angular
.
mock
.
inject
(
function
(
_$compile_
,
_$rootScope_
)
{
...
@@ -109,15 +109,20 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
...
@@ -109,15 +109,20 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
var
attrName
=
hyphenate
(
key
);
var
attrName
=
hyphenate
(
key
);
var
attrKey
=
key
;
var
attrKey
=
key
;
if
(
typeof
attrs
[
key
]
===
'function'
)
{
if
(
typeof
attrs
[
key
]
===
'function'
)
{
// If the input property is a function, generate a function expression,
// eg. `<my-component on-event="onEvent()">`
attrKey
+=
'()'
;
attrKey
+=
'()'
;
}
else
if
(
attrs
[
key
].
callback
)
{
}
else
if
(
attrs
[
key
].
callback
)
{
// If the input property is a function which accepts arguments,
// generate the argument list.
// eg. `<my-component on-change="onChange(newValue)">`
attrKey
+=
'('
+
attrs
[
key
].
args
.
join
(
','
)
+
')'
;
attrKey
+=
'('
+
attrs
[
key
].
args
.
join
(
','
)
+
')'
;
}
}
templateElement
.
setAttribute
(
attrName
,
attrKey
);
templateElement
.
setAttribute
(
attrName
,
attrKey
);
});
});
templateElement
.
innerHTML
=
initialHtml
;
templateElement
.
innerHTML
=
initialHtml
;
//
a
dd the element to the document's body so that
//
A
dd the element to the document's body so that
// it responds to events, becomes visible, reports correct
// it responds to events, becomes visible, reports correct
// values for its dimensions etc.
// values for its dimensions etc.
opts
.
parentElement
.
appendChild
(
templateElement
);
opts
.
parentElement
.
appendChild
(
templateElement
);
...
...
h/templates/client/annotation.html
View file @
7179ee19
...
@@ -80,7 +80,8 @@
...
@@ -80,7 +80,8 @@
collapsed-height=
"400"
collapsed-height=
"400"
overflow-hysteresis=
"20"
overflow-hysteresis=
"20"
content-data=
"vm.form.text"
>
content-data=
"vm.form.text"
>
<markdown
ng-model=
"vm.form.text"
<markdown
text=
"vm.form.text"
on-edit-text=
"vm.setText(text)"
read-only=
"!vm.editing()"
>
read-only=
"!vm.editing()"
>
</markdown>
</markdown>
</excerpt>
</excerpt>
...
...
h/templates/client/markdown.html
View file @
7179ee19
<div
ng-
hide=
"
readOnly"
class=
"markdown-tools"
ng-class=
"preview && 'disable'"
>
<div
ng-
if=
"!
readOnly"
class=
"markdown-tools"
ng-class=
"preview && 'disable'"
>
<span
class=
"markdown-preview-toggle"
>
<span
class=
"markdown-preview-toggle"
>
<a
class=
"markdown-tools-badge h-icon-markdown"
href=
"https://help.github.com/articles/markdown-basics"
title=
"Parsed as Markdown"
target=
"_blank"
></a>
<a
class=
"markdown-tools-badge h-icon-markdown"
href=
"https://help.github.com/articles/markdown-basics"
title=
"Parsed as Markdown"
target=
"_blank"
></a>
<a
href=
""
class=
"markdown-tools-toggle"
ng-click=
"togglePreview()"
ng-show=
"!preview"
>
Preview
</a>
<a
href=
""
class=
"markdown-tools-toggle"
ng-click=
"togglePreview()"
ng-show=
"!preview"
>
Preview
</a>
...
@@ -14,7 +14,9 @@
...
@@ -14,7 +14,9 @@
<i
class=
"h-icon-format-list-bulleted markdown-tools-button"
ng-click=
"insertList()"
title=
"Insert list"
></i>
<i
class=
"h-icon-format-list-bulleted markdown-tools-button"
ng-click=
"insertList()"
title=
"Insert list"
></i>
</div>
</div>
<textarea
class=
"form-input form-textarea js-markdown-input"
<textarea
class=
"form-input form-textarea js-markdown-input"
ng-hide=
"readOnly || preview"
ng-show=
"showEditor()"
ng-click=
"$event.stopPropagation()"
ng-click=
"$event.stopPropagation()"
></textarea>
ng-required=
"required"
></textarea>
<div
class=
"styled-text js-markdown-preview"
<div
class=
"styled-text js-markdown-preview"
ng-class=
"preview && 'markdown-preview'"
ng-dblclick=
"togglePreview()"
ng-show=
"readOnly || preview"
></div>
ng-class=
"preview && 'markdown-preview'"
ng-dblclick=
"togglePreview()"
ng-show=
"!showEditor()"
></div>
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