I want to create a link with read more text. if there are more than 3 lines in a paragraph this link should be visible and clicking on this it show display all the lines. >
There can be some workaround.
basic idea is like this
1. at first, use javascript to calculate the original height
2. if higher than 3 lines , set the overflow to hidden and show a button. The button is used to toggle state
3. if not, do nothing
About the button.
If the button is out of text area, it's no problem for you I think. If you need the button inline within the element, there are 2 possibilitis.
if you want it position fixed at right-bottom, create a gradient background for the button, fade-out effect. It looks nice and very simple.
here is jsfiddle: http://jsfiddle.net/sunderls/HYHZ6/ . Everytime toggling the state, you actually change the class of the element.
if you want it right after the end of text? it's a little tricky, since even if text height is 3 lines, you cannot be sure whether it remains 3 lines height , after appending a button next to it.
I think one way is to use Range API, to calculate the paragraph dimensions, (I've used the api in my collamark.com, it's powerful but different browsers have different behaviors). Actually you can get the dimensions of every lines dynamically. And by some backwards loops, you can get the appropriate substring of the text, to show in collapsed mode, which is just right for 3 lines height with a button. (the api doc is here: https://developer.mozilla.org/en-US/docs/Web/API/range)
So now every time you toggle the state, you actually is change the text. not the class.
first, this kind of feature is a standalone module which you can reuse everywhere, so in your template, we create a new directive autoFolded
, sth like this:
Some text here, maybe long maybe short
then we handle all the logic in directive definition( sorry for writing in coffee though)
directive('autoFolded',[
'$window'
($window) ->
return {
restrict: 'E'
transclude: true
template: ''
link: (scope, element, attrs)->
$$window = $ $window
content = $(element).find('.auto-folded')
toggleFoldedState = ->
if content.hasClass 'auto-folded--folded'
content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded')
else if content.hasClass 'auto-folded--unfolded'
content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded')
return
scope.toggleFoldedState = toggleFoldedState
init = ()->
contentHeight = content.outerHeight()
if contentHeight > 48
content.addClass 'auto-folded--folded'
content.show()
$$window.on 'ngcontentloaded',init
}
])
for this directive contains text it doesn't know, so it's a translucent direcitve. Like a modal popup, it contains the Text and a toggle button.
restrict: 'E'
transclude: true
template: ''
when clicking the button, it actually do the toggling. If unfolded, then fold it; If foled, then unfolded. We accomplish this by toggling the classNames, the cold is straightforward
toggleFoldedState = ->
content.css 'color','red'
if content.hasClass 'auto-folded--folded'
content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded')
else if content.hasClass 'auto-folded--unfolded'
content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded')
return
and we use ng-click="toggleFoldedState()"
to bind this action to the toggling button
We have to do some initial work to fold the text if it's tall enough at page loaded. However, link
function of directive is to create the actual Dom, before dom rendering.So in link
, we cannot know the height, that's why we register the init()
to ngcontentloaded
event:
init = ()->
contentHeight = content.outerHeight()
if contentHeight > 48
content.addClass 'auto-folded--folded'
content.show()
$$window.on 'ngcontentloaded',init
here I use 48px as 3-line-height, you can define your own, or calculate dynamically from the dom, like content.css('lineHeight')
.
since this is done after dom rendering, so the text is already displayed before init(). There will be a ugly slideUp effect. That's why we first hide the dom using css(as following), and content.show()
in init
So we are done with directive, the folded/unfoled state are controlled by className. here we go.
(sorry I wrote it in sass
)
.auto-folded
display: none //only display after init()
position: relative
.auto-folded--more //the button is placed at right-bottom, and default to hidden
display: none
position: absolute
right: 0
bottom: 0
&.auto-folded--folded //when folded, set maxHeight, and overflow to hidden
max-height: 48px
overflow: hidden
.auto-folded--more // toggling button is displayed,
display: block
&:before // and it's text is "more"
content: "more"
&.auto-folded--unfolded //when unfoled, s
.auto-folded--more // toggling button is displayed
display: block
&:before // and it's text is "hide"
content: "hide"
So the text of toggling button and visibility of it , are all controlled by the class of its parent.
for the parent
1. if text is not 3-line height, it will only have 'auto-folded'
as css class, so the button is hidden
init()
process, it's classNames will be 'auto-folded auto-folded--folded'
.'auto-folded--folded'
and 'auto-folded--unfolded'