diff --git a/docs/userGuide/syntax/popovers.md b/docs/userGuide/syntax/popovers.md index fb474595bc..d214271e4c 100644 --- a/docs/userGuide/syntax/popovers.md +++ b/docs/userGuide/syntax/popovers.md @@ -53,6 +53,17 @@

+

Content using src

+

+ + This is loaded from a .html file + +

+

+ + This is loaded from a .md file + +

Wrap Text

What do you say @@ -76,13 +87,24 @@ This is the same trigger as last one. ****Options**** -Name | Type | Default | Description ----- | ---- | ------- | ------ -trigger | `String` | `hover` | How the Popover is triggered.
Supports: `click`, `focus`, `hover`. -header{{slot_info_trigger}} | `String` | `''` | Popover header, supports MarkDown text. -content{{slot_info_trigger}} | `String` | `''` | Popover content, supports MarkDown text. -placement | `String` | `top` | How to position the Popover.
Supports: `top`, `left`, `right`, `bottom`. +| Name | Type | Default | Description | +| ---------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------| +| trigger | `String` | `hover` | How the Popover is triggered.
Supports: `click`, `focus`, `hover`. | +| header{{slot_info_trigger}} | `String` | `''` | Popover header, supports MarkDown text. | +| content{{slot_info_trigger}} | `String` | `''` | Popover content, supports MarkDown text. | +| src | `String` | | The url to the remote page to be loaded as the content of the popover.
Both `.md` and `.html` are accepted. | +| placement | `String` | `top` | How to position the Popover.
Supports: `top`, `left`, `right`, `bottom`. | + + + +MarkBind supports the `src` attribute, `content` attribute and `content` slot for popovers. +Usually, only one of these would be used at a time. +If multiple of these are used, MarkBind will prioritise in the following order: + 1. `content` slot + 1. `content` attribute + 1. `src` attribute + diff --git a/packages/cli/test/functional/test_site/expected/siteData.json b/packages/cli/test/functional/test_site/expected/siteData.json index 61e05c11b4..6a4d87dbe5 100644 --- a/packages/cli/test/functional/test_site/expected/siteData.json +++ b/packages/cli/test/functional/test_site/expected/siteData.json @@ -214,6 +214,17 @@ "headings": {}, "headingKeywords": {} }, + { + "src": "testPopovers.md", + "title": "Test: Popovers", + "headings": { + "nested-panel": "Nested Panel", + "normal-panel-content-heading": "Normal panel content heading", + "some-heading": "Some heading", + "some-heading-2": "Some heading" + }, + "headingKeywords": {} + }, { "src": "testPopoverTrigger.md", "title": "Popover initiated by trigger should honor trigger attribute", diff --git a/packages/cli/test/functional/test_site/expected/testPopovers.html b/packages/cli/test/functional/test_site/expected/testPopovers.html new file mode 100644 index 0000000000..c889d03ae6 --- /dev/null +++ b/packages/cli/test/functional/test_site/expected/testPopovers.html @@ -0,0 +1,338 @@ + + + + + + + + + + + + + Test: Popovers + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + +
  • Open Bugs
  • +
    +
    +
    + Test Jumbotron
    +
    +
    +
    +

    Relative Link Test This is a relative Intra-Site link in a layout (see link)

    +
    +
    + + + + +
    +

    Popover with attributes

    + + Hover popover + +
    + + Click popover + +
    +

    Popover with slots

    + + + Hover popover + +
    + + + + Click popover + +
    +

    Popover with slots overriding attributes

    + + + Hover popover + +
    + + + + Click popover + +
    +

    Popover with src attribute

    + + src from a .md file with absolute links + +
    + + src from a .md file with relative links + +
    + + src from a .html file with absolute links + +
    + + src from a .html file with relative links + +
    + + src with a fragment + +
    + + + src containing reactive content + +
    +

    Popover contents should use the priority of content slot > content attribute > src attribute

    + + Content attribute overrides src attribute + +
    + + + Content slot overrides content attribute overrides src attribute + +
    + + + Content slot overrides content attribute overrides src attribute + +
    +

    URLs are not valid src

    +
    URLs are not allowed in the 'src' attribute
    + +
    + + + +
    +
    +
    +

    Heading in footer should not be indexed

    +
    + This is a dynamic height footer that supports markdown 😄! +
    +
    +
    +
    + + + + + + + + + + + \ No newline at end of file diff --git a/packages/cli/test/functional/test_site/expected/testPopovers.page-vue-render.js b/packages/cli/test/functional/test_site/expected/testPopovers.page-vue-render.js new file mode 100644 index 0000000000..364ed7810d --- /dev/null +++ b/packages/cli/test/functional/test_site/expected/testPopovers.page-vue-render.js @@ -0,0 +1,34 @@ + + var pageVueRenderFn = function anonymous( +) { +with(this){return _c('div',{attrs:{"id":"app"}},[_c('div',[_c('header',[_c('navbar',{attrs:{"type":"dark","default-highlight-on":"sibling-or-child"},scopedSlots:_u([{key:"brand",fn:function(){return [_c('a',{staticClass:"navbar-brand",attrs:{"href":"/","title":"Home"}},[_v("Markbind Test Site")])]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"/test_site/bugs/index.html"}},[_v("Open Bugs")])])]),_v(" "),_m(0)],1),_v(" "),_m(1)]),_v(" "),_c('div',{attrs:{"id":"flex-body"}},[_c('overlay-source',{staticClass:"fixed-header-padding",attrs:{"id":"site-nav","tag-name":"nav","to":"site-nav"}},[_c('div',{staticClass:"site-nav-top"},[_c('div',{staticClass:"font-weight-bold mb-2",staticStyle:{"font-size":"1.25rem"}},[_c('div',[_c('h2',{attrs:{"id":"default-layout"}},[_c('span',{staticClass:"anchor",attrs:{"id":"default-layout"}}),_v("Default Layout"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#default-layout","onclick":"event.stopPropagation()"}})])])])]),_v(" "),_c('div',{staticClass:"nav-component slim-scroll"},[_c('div',[_c('site-nav',[_c('overlay-source',{staticClass:"site-nav-list site-nav-list-root",attrs:{"tag-name":"ul","to":"mb-site-nav"}},[_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"/test_site/index.html"}},[_v("Home 🏠")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"/test_site/bugs/index.html"}},[_v("Open Bugs 🐛")])])]),_v(" "),_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-0"},[_c('h3',{attrs:{"id":"testing-site-nav"}},[_c('span',{staticClass:"anchor",attrs:{"id":"testing-site-nav"}}),_v("Testing Site-Nav"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing-site-nav","onclick":"event.stopPropagation()"}})])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('strong',[_v("Dropdown ")]),_v(" "),_c('span',{staticClass:"glyphicon glyphicon-search",attrs:{"aria-hidden":"true"}}),_v(" title ✏️ "),_v(" "),_c('i',{staticClass:"site-nav-dropdown-btn-icon site-nav-rotate-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-dropdown-container-open site-nav-list"},[_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_v("Dropdown link one")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_v("Html within site-nav "),_c('span',{staticStyle:{"color":"red"}},[_v("should")]),_v(" be displayed properly")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Nested Dropdown title 📐\n\n"),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-2",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_c('strong',[_v("Nested")]),_v(" Dropdown link one")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-2",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_c('strong',[_v("Nested")]),_v(" Dropdown link two")])])])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_v("Dropdown link two")])])])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_c('mark',[_v("Third Link")]),_v(" 📋")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Filler text "),_c('a',{attrs:{"href":"https://www.youtube.com/"}},[_c('span',{staticClass:"glyphicon glyphicon-facetime-video",attrs:{"aria-hidden":"true"}}),_v(" Youtube 📺")]),_v(" filler text"),_v(" "),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}},[_v("The answer to everything in the universe")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('mark',[_v("Dropdown title")]),_v(" "),_c('span',{staticClass:"glyphicon glyphicon-comment",attrs:{"aria-hidden":"true"}}),_v(" ✏️ "),_v(" "),_c('i',{staticClass:"site-nav-dropdown-btn-icon site-nav-rotate-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-dropdown-container-open site-nav-list"},[_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-2",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"https://www.google.com/"}},[_c('strong',[_v("Nested")]),_v(" Dropdown link one")])])])])])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Really Long Dropdown Title Really Long Dropdown Title Really Long Dropdown Title Really Long Dropdown\n\n"),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-1"},[_v("Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text Really Really Long Text")]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Nested Dropdown Title\n\n"),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-2"},[_v("Hello Doge Hello Doge 🐶")]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-2",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"/test_site/index.html"}},[_c('strong',[_v("NESTED LINK")]),_v(" Home 🏠")])])]),_v(" "),_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-2"},[_v("Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit Text cut off from height limit")])])])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-0",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Test line break in navigation layout\n\n"),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-1"},[_v("Nested line break text ✂️")]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_c('a',{attrs:{"href":"/test_site/index.html"}},[_v("Nested line break href")]),_v(" "),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-2"},[_v("Nested Nested line break text ✂️")])])]),_v(" "),_c('li',[_c('div',{staticClass:"site-nav-default-list-item site-nav-list-item-1",attrs:{"onclick":"handleSiteNavClick(this)"}},[_v("Nested line break dropdown menu\n\n"),_c('i',{staticClass:"site-nav-dropdown-btn-icon",attrs:{"onclick":"handleSiteNavClick(this.parentNode, false); event.stopPropagation();"}},[_c('span',{staticClass:"glyphicon glyphicon-menu-down",attrs:{"aria-hidden":"true"}})])]),_c('ul',{staticClass:"site-nav-dropdown-container site-nav-list"},[_c('li',{staticClass:"site-nav-custom-list-item site-nav-list-item-2"},[_v("Line break item 2 📘")])])])])])])],1)],1)])]),_v(" "),_c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_m(2),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_v("Correct content")]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n Hover popover\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{attrs:{"trigger":"click"},scopedSlots:_u([{key:"content",fn:function(){return [_v("Correct content")]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n Click popover\n")]),_v(" "),_c('br'),_v(" "),_m(3),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v("\n Hover popover\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{attrs:{"trigger":"click"},scopedSlots:_u([{key:"header",fn:function(){return [_c('span',[_v("Correct header")])]},proxy:true},{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v(" "),_v("\n Click popover\n")]),_v(" "),_c('br'),_v(" "),_m(4),_v(" "),_c('popover',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Correct header")]},proxy:true},{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v(" "),_v("\n Hover popover\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{attrs:{"trigger":"click"},scopedSlots:_u([{key:"header",fn:function(){return [_c('span',[_v("Correct header")])]},proxy:true},{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v(" "),_v("\n Click popover\n")]),_v(" "),_c('br'),_v(" "),_m(5),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('h1',{attrs:{"id":"some-heading"}},[_c('span',{staticClass:"anchor",attrs:{"id":"some-heading"}}),_v("Some heading"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#some-heading","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The "),_c('strong',[_v("quick")]),_v(" brown fox jumps "),_c('em',[_v("over")]),_v(" the lazy dog.")])]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n src from a .md file with absolute links\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('h1',{attrs:{"id":"some-heading-2"}},[_c('span',{staticClass:"anchor",attrs:{"id":"some-heading-2"}}),_v("Some heading"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#some-heading-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The "),_c('strong',[_v("quick")]),_v(" brown fox jumps "),_c('em',[_v("over")]),_v(" the lazy dog.")])]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n src from a .md file with relative links\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('p',[_v("This is a HTML document")]),_v(" "),_c('span',[_v("It is "),_c('strong',[_v("possible")]),_v(" to use Markdown in HTML")])]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n src from a .html file with absolute links\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('p',[_v("This is a HTML document")]),_v(" "),_c('span',[_v("It is "),_c('strong',[_v("possible")]),_v(" to use Markdown in HTML")])]},proxy:true},{key:"header",fn:function(){return [_v("Correct header")]},proxy:true}])},[_v("\n src from a .html file with relative links\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_v("content fragment")]},proxy:true}])},[_v("\n src with a fragment\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_c('panel',{attrs:{"src":"/test_site/testPanels/NormalPanelContent._include_.html","expanded":"","panelId":"nested-panel"},scopedSlots:_u([{key:"header",fn:function(){return [_c('h2',{attrs:{"id":"nested-panel"}},[_c('span',{staticClass:"anchor",attrs:{"id":"nested-panel"}}),_v("Nested Panel"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nested-panel","onclick":"event.stopPropagation()"}})])]},proxy:true}])})]},proxy:true},{key:"header",fn:function(){return [_c('span',[_v("Reactive content")])]},proxy:true}])},[_v(" "),_v("\n src containing reactive content\n")]),_v(" "),_c('br'),_v(" "),_m(6),_v(" "),_c('popover',{scopedSlots:_u([{key:"content",fn:function(){return [_v("Correct content")]},proxy:true},{key:"header",fn:function(){return [_v("Content slot > content attrib > src attrib")]},proxy:true}])},[_v("\n Content attribute overrides src attribute\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Content slot > content attrib > src attrib")]},proxy:true},{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v(" "),_v("\n Content slot overrides content attribute overrides src attribute\n")]),_v(" "),_c('br'),_v(" "),_c('popover',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Content slot > content attrib > src attrib")]},proxy:true},{key:"content",fn:function(){return [_c('span',[_v("Correct content")])]},proxy:true}])},[_v(" "),_v("\n Content slot overrides content attribute overrides src attribute\n")]),_v(" "),_c('br'),_v(" "),_m(7),_v(" "),_c('div',{staticStyle:{"color":"red"}},[_v("URLs are not allowed in the 'src' attribute")]),_v(" "),_c('i',{staticClass:"fa fa-arrow-circle-up fa-lg d-print-none",attrs:{"id":"scroll-top-button","onclick":"handleScrollTop()","aria-hidden":"true"}})],1),_v(" "),_c('overlay-source',{staticClass:"fixed-header-padding",attrs:{"id":"page-nav","tag-name":"nav","to":"page-nav"}},[_c('div',{staticClass:"nav-component slim-scroll"})])],1),_v(" "),_m(8)])} +}; + var pageVueStaticRenderFns = [function anonymous( +) { +with(this){return _c('div',{staticClass:"bg-info display-4 text-center text-white"},[_c('br'),_v("\n Test Jumbotron"),_c('br'),_v(" "),_c('br')])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Relative Link Test")]),_v(" This is a relative Intra-Site link in a layout (see "),_c('a',{attrs:{"href":"/test_site/index.html#heading-with-hidden-keyword"}},[_v("link")]),_v(")")])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Popover with attributes")])])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Popover with slots")])])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Popover with slots overriding attributes")])])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Popover with src attribute")])])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("Popover contents should use the priority of content slot > content attribute > src attribute")])])} +},function anonymous( +) { +with(this){return _c('p',[_c('strong',[_v("URLs are not valid src")])])} +},function anonymous( +) { +with(this){return _c('div',[_c('footer',[_c('h1',{attrs:{"id":"heading-in-footer-should-not-be-indexed"}},[_c('span',{staticClass:"anchor",attrs:{"id":"heading-in-footer-should-not-be-indexed"}}),_v("Heading in footer should not be indexed"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#heading-in-footer-should-not-be-indexed","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"text-center"},[_v("\n This is a dynamic height footer that supports markdown "),_c('span',[_v("😄")]),_v("!\n ")])])])} +}]; + \ No newline at end of file diff --git a/packages/cli/test/functional/test_site/site.json b/packages/cli/test/functional/test_site/site.json index 4353353ba7..264c38fa73 100644 --- a/packages/cli/test/functional/test_site/site.json +++ b/packages/cli/test/functional/test_site/site.json @@ -74,6 +74,10 @@ "src": "testIncludeMultipleModals.md", "title": "Multiple inclusions of a modal should be supported" }, + { + "src": "testPopovers.md", + "title": "Test: Popovers" + }, { "src": "testPopoverTrigger.md", "title": "Popover initiated by trigger should honor trigger attribute" diff --git a/packages/cli/test/functional/test_site/testPopovers.md b/packages/cli/test/functional/test_site/testPopovers.md new file mode 100644 index 0000000000..8a775e75bf --- /dev/null +++ b/packages/cli/test/functional/test_site/testPopovers.md @@ -0,0 +1,115 @@ +**Popover with attributes** + + + Hover popover + + +
    + + + Click popover + + +
    + +**Popover with slots** + + + Correct content + Hover popover + + +
    + + + Correct header + Correct content + Click popover + + +
    + +**Popover with slots overriding attributes** + + + Correct content + Hover popover + + +
    + + + Correct header + Correct content + Click popover + + +
    + +**Popover with src attribute** + + + src from a .md file with absolute links + + +
    + + + src from a .md file with relative links + + +
    + + + src from a .html file with absolute links + + +
    + + + src from a .html file with relative links + + +
    + + + src with a fragment + + +
    + + + Reactive content + src containing reactive content + + +
    + +**Popover contents should use the priority of content slot > content attribute > src attribute** + + + Content attribute overrides src attribute + + +
    + + + Correct content + Content slot overrides content attribute overrides src attribute + + +
    + + + Correct content + Content slot overrides content attribute overrides src attribute + + +
    + +**URLs are not valid src** + + + URLs should not be valid + + diff --git a/packages/cli/test/functional/test_site_algolia_plugin/expected/index.html b/packages/cli/test/functional/test_site_algolia_plugin/expected/index.html index 8887cdb1b2..aef10816f6 100644 --- a/packages/cli/test/functional/test_site_algolia_plugin/expected/index.html +++ b/packages/cli/test/functional/test_site_algolia_plugin/expected/index.html @@ -59,7 +59,7 @@ - +

    Tooltip content should have algolia-no-index class

    diff --git a/packages/cli/test/functional/test_site_algolia_plugin/expected/index.page-vue-render.js b/packages/cli/test/functional/test_site_algolia_plugin/expected/index.page-vue-render.js index a3d16f29f7..7da6194163 100644 --- a/packages/cli/test/functional/test_site_algolia_plugin/expected/index.page-vue-render.js +++ b/packages/cli/test/functional/test_site_algolia_plugin/expected/index.page-vue-render.js @@ -1,7 +1,7 @@ var pageVueRenderFn = function anonymous( ) { -with(this){return _c('div',{attrs:{"id":"app"}},[_c('p'),_m(0),_v(" "),_m(1),_v(" "),_c('dropdown',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Dropdown")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/"}},[_v("One")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/"}},[_v("Two")])])]),_v(" "),_m(2),_v(" "),_c('b-modal',{ref:"modal:trigger_id",staticClass:"algolia-no-index",attrs:{"id":"modal:trigger_id","hide-footer":"","size":"","modal-class":"mb-zoom"},scopedSlots:_u([{key:"modal-title",fn:function(){return [_v("Modal")]},proxy:true}])},[_v("\n Content should have `algolia-no-index` class\n")]),_v(" "),_c('trigger',{attrs:{"for":"modal:trigger_id"}},[_v("Trigger should not have `algolia-no-index` class")]),_v(" "),_m(3),_v(" "),_c('panel',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_v("Panel")])]},proxy:true}])},[_v("\n Content\n")]),_v(" "),_c('panel',{attrs:{"expanded":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_v("Panel")])]},proxy:true}])},[_v("\n Content\n")]),_v(" "),_m(4),_v(" "),_c('popover',{attrs:{"placement":"top"},scopedSlots:_u([{key:"header",fn:function(){return [_v("Title")]},proxy:true},{key:"content",fn:function(){return [_c('div',[_v("Content should have `algolia-no-index` class")])]},proxy:true}])},[_v(" "),_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_c('popover',{attrs:{"placement":"top"},scopedSlots:_u([{key:"header",fn:function(){return [_v("Title")]},proxy:true},{key:"content",fn:function(){return [_v("Content should have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("algolia-no-index")]),_v(" class")]},proxy:true}])},[_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_m(5),_v(" "),_c('tooltip',{attrs:{"placement":"top"},scopedSlots:_u([{key:"content",fn:function(){return [_v("Content should have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("algolia-no-index")]),_v(" class")]},proxy:true}])},[_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_m(6),_v(" "),_c('question',{scopedSlots:_u([{key:"hint",fn:function(){return [_c('div',{staticClass:"algolia-no-index"},[_v("Hint should have `algolia-no-index` class")])]},proxy:true},{key:"answer",fn:function(){return [_c('div',{staticClass:"algolia-no-index"},[_v("Answer should have `algolia-no-index` class")])]},proxy:true}])},[_v("\n Question should not have `algolia-no-index` class\n ")]),_v(" "),_m(7),_v(" "),_c('tabs',[_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tabs',[_c('tab-group',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Group")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tab-group',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Group")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1)],1),_v(" "),_c('tabs',[_c('tab-group',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Outer One")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Outer Two")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('i',{staticClass:"fa fa-arrow-circle-up fa-lg d-print-none",attrs:{"id":"scroll-top-button","onclick":"handleScrollTop()","aria-hidden":"true"}}),_c('p')],1)} +with(this){return _c('div',{attrs:{"id":"app"}},[_c('p'),_m(0),_v(" "),_m(1),_v(" "),_c('dropdown',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Dropdown")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/"}},[_v("One")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/"}},[_v("Two")])])]),_v(" "),_m(2),_v(" "),_c('b-modal',{ref:"modal:trigger_id",staticClass:"algolia-no-index",attrs:{"id":"modal:trigger_id","hide-footer":"","size":"","modal-class":"mb-zoom"},scopedSlots:_u([{key:"modal-title",fn:function(){return [_v("Modal")]},proxy:true}])},[_v("\n Content should have `algolia-no-index` class\n")]),_v(" "),_c('trigger',{attrs:{"for":"modal:trigger_id"}},[_v("Trigger should not have `algolia-no-index` class")]),_v(" "),_m(3),_v(" "),_c('panel',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_v("Panel")])]},proxy:true}])},[_v("\n Content\n")]),_v(" "),_c('panel',{attrs:{"expanded":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_v("Panel")])]},proxy:true}])},[_v("\n Content\n")]),_v(" "),_m(4),_v(" "),_c('popover',{attrs:{"placement":"top"},scopedSlots:_u([{key:"header",fn:function(){return [_v("Title")]},proxy:true},{key:"content",fn:function(){return [_c('div',[_v("Content should have `algolia-no-index` class")])]},proxy:true}])},[_v(" "),_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_c('popover',{attrs:{"placement":"top"},scopedSlots:_u([{key:"content",fn:function(){return [_v("Content should have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("algolia-no-index")]),_v(" class")]},proxy:true},{key:"header",fn:function(){return [_v("Title")]},proxy:true}])},[_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_m(5),_v(" "),_c('tooltip',{attrs:{"placement":"top"},scopedSlots:_u([{key:"content",fn:function(){return [_v("Content should have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("algolia-no-index")]),_v(" class")]},proxy:true}])},[_v(" "),_c('button',{staticClass:"btn btn-secondary"},[_v("Trigger should not have `algolia-no-index` class")])]),_v(" "),_m(6),_v(" "),_c('question',{scopedSlots:_u([{key:"hint",fn:function(){return [_c('div',{staticClass:"algolia-no-index"},[_v("Hint should have `algolia-no-index` class")])]},proxy:true},{key:"answer",fn:function(){return [_c('div',{staticClass:"algolia-no-index"},[_v("Answer should have `algolia-no-index` class")])]},proxy:true}])},[_v("\n Question should not have `algolia-no-index` class\n ")]),_v(" "),_m(7),_v(" "),_c('tabs',[_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tabs',[_c('tab-group',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Group")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tab-group',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Group")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1)],1),_v(" "),_c('tabs',[_c('tab-group',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Outer One")]},proxy:true}])},[_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("First Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")]),_v(" "),_c('tab',{staticClass:"algolia-no-index",scopedSlots:_u([{key:"header",fn:function(){return [_v("Second Tab")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('tab',{scopedSlots:_u([{key:"header",fn:function(){return [_v("Outer Two")]},proxy:true}])},[_v("\n Content"),_c('br'),_v("Content"),_c('br'),_v("Content"),_c('br'),_v("Content\n ")])],1),_v(" "),_c('i',{staticClass:"fa fa-arrow-circle-up fa-lg d-print-none",attrs:{"id":"scroll-top-button","onclick":"handleScrollTop()","aria-hidden":"true"}}),_c('p')],1)} }; var pageVueStaticRenderFns = [function anonymous( ) { diff --git a/packages/core/src/html/MdAttributeRenderer.js b/packages/core/src/html/MdAttributeRenderer.js index f572378ad2..b792b7417e 100644 --- a/packages/core/src/html/MdAttributeRenderer.js +++ b/packages/core/src/html/MdAttributeRenderer.js @@ -44,9 +44,50 @@ class MdAttributeRenderer { delete node.attribs[attribute]; } - processPopover(node) { + /** + * Checks if the node has both the given slot and the given attribute, + * deleting the attribute and logging a warning if both the slot and attribute exist. + * @param node Element to process + * @param attribute Attribute name to process + * @param slotName Name attribute of the element to insert, which defaults to the attribute name + * @returns {boolean} whether the node has both the slot and attribute + */ + // eslint-disable-next-line class-methods-use-this + hasSlotOverridingAttribute(node, attribute, slotName = attribute) { + const hasNamedSlot = node.children + && node.children.some(child => getVslotShorthandName(child) === slotName); + if (!hasNamedSlot) { + return false; + } + + // If the slot is present, remove the attribute as the attribute has no effect. + const hasAttribute = _.has(node.attribs, attribute); + if (hasAttribute) { + logger.warn(`${node.name} has a ${slotName} slot, '${attribute}' attribute has no effect.`); + delete node.attribs[attribute]; + } + + return hasAttribute; + } + + processPopoverAttributes(node) { + if (!this.hasSlotOverridingAttribute(node, 'header')) { + this.processAttributeWithoutOverride(node, 'header', true); + } + + // Warn if there is a content slot overriding the attributes 'content' or 'src' + const hasSlotAndContentAttribute = this.hasSlotOverridingAttribute(node, 'content', 'content'); + const hasSlotAndSrcAttribute = this.hasSlotOverridingAttribute(node, 'src', 'content'); + if (hasSlotAndContentAttribute || hasSlotAndSrcAttribute) { + return; + } + + if (_.has(node.attribs, 'content') && _.has(node.attribs, 'src')) { + logger.warn(`${node.name} has a 'content' attribute, 'src' attribute has no effect.`); + delete node.attribs.src; + } + this.processAttributeWithoutOverride(node, 'content', true); - this.processAttributeWithoutOverride(node, 'header', true); } processTooltip(node) { diff --git a/packages/core/src/html/NodeProcessor.js b/packages/core/src/html/NodeProcessor.js index 07451d8f59..2b5fee139c 100644 --- a/packages/core/src/html/NodeProcessor.js +++ b/packages/core/src/html/NodeProcessor.js @@ -12,7 +12,7 @@ _.has = require('lodash/has'); _.find = require('lodash/find'); const { PageNavProcessor, renderSiteNav, addSitePageNavPortal } = require('./siteAndPageNavProcessor'); -const { processInclude, processPanelSrc } = require('./includePanelProcessor'); +const { processInclude, processPanelSrc, processPopoverSrc } = require('./includePanelProcessor'); const { Context } = require('./Context'); const linkProcessor = require('./linkProcessor'); const { highlightCodeBlock, setCodeLineNumbers } = require('./codeblockProcessor'); @@ -160,8 +160,9 @@ class NodeProcessor { this.mdAttributeRenderer.processQuiz(node); break; case 'popover': - this.mdAttributeRenderer.processPopover(node); - break; + this.mdAttributeRenderer.processPopoverAttributes(node); + return processPopoverSrc(node, context, this.pageSources, this.variableProcessor, + text => this.markdownProcessor.renderMd(text), this.config); case 'tooltip': this.mdAttributeRenderer.processTooltip(node); break; diff --git a/packages/core/src/html/elements.js b/packages/core/src/html/elements.js index acbea46839..3891422ffc 100644 --- a/packages/core/src/html/elements.js +++ b/packages/core/src/html/elements.js @@ -13,4 +13,8 @@ module.exports = { createEmptyNode() { return cheerio.parseHTML('
    ', true)[0]; }, + + createSlotTemplateNode(slotName, content) { + return cheerio.parseHTML(``, true); + }, }; diff --git a/packages/core/src/html/includePanelProcessor.js b/packages/core/src/html/includePanelProcessor.js index 9e624b89c2..50c8194963 100644 --- a/packages/core/src/html/includePanelProcessor.js +++ b/packages/core/src/html/includePanelProcessor.js @@ -2,7 +2,7 @@ const cheerio = require('cheerio'); require('../patches/htmlparser2'); const path = require('path'); const url = require('url'); -const { createErrorNode, createEmptyNode } = require('./elements'); +const { createErrorNode, createEmptyNode, createSlotTemplateNode } = require('./elements'); const { CyclicReferenceError } = require('../errors'); const fsUtil = require('../utils/fsUtil'); @@ -255,7 +255,98 @@ function processInclude(node, context, pageSources, variableProcessor, renderMd, return childContext; } +/** + * PreProcesses popovers with the src attribute. + * Replaces it with an error node if the specified src is invalid. + * Else, appends the content to the node. + */ +function processPopoverSrc(node, context, pageSources, variableProcessor, renderMd, config) { + if (!_.has(node.attribs, 'src')) { + return context; + } + + if (_.isEmpty(node.attribs.src)) { + const error = new Error(`Empty src attribute in include in: ${context.cwf}`); + logger.error(error); + cheerio(node).replaceWith(createErrorNode(node, error)); + return context; + } + + const { + isUrl, + hash, + filePath, + actualFilePath, + } = _getSrcFlagsAndFilePaths(node, config); + + // No need to process url contents + if (isUrl) { + const error = new Error('URLs are not allowed in the \'src\' attribute'); + logger.error(error); + cheerio(node).replaceWith(createErrorNode(node, error)); + return context; + } + + const fileExistsNode = _getFileExistsNode(node, context, actualFilePath, pageSources); + if (fileExistsNode) { + return fileExistsNode; + } + + pageSources.staticIncludeSrc.push({ + from: context.cwf, + to: actualFilePath, + }); + + const { + nunjucksProcessed, + childContext, + } = variableProcessor.renderIncludeFile(actualFilePath, pageSources, node, context, filePath); + + let actualContent = nunjucksProcessed; + if (fsUtil.isMarkdownFileExt(path.extname(actualFilePath))) { + actualContent = renderMd(actualContent); + } + + // Process sources with or without hash, retrieving and appending + // the appropriate children to a wrapped include element + if (hash) { + const $ = cheerio.load(actualContent); + actualContent = $(hash).html(); + + if (actualContent === null) { + const error = new Error(`No such segment '${hash}' in file: ${actualFilePath}\n` + + `Missing reference in ${context.cwf}`); + logger.error(error); + + cheerio(node).replaceWith(createErrorNode(node, error)); + + return context; + } + } + + actualContent = actualContent.trim(); + + if (node.children && node.children.length > 0) { + childContext.addCwfToCallstack(context.cwf); + + if (childContext.hasExceededMaxCallstackSize()) { + const error = new CyclicReferenceError(childContext.callStack); + logger.error(error); + cheerio(node).replaceWith(createErrorNode(node, error)); + return context; + } + } + + const attributeSlotElement = createSlotTemplateNode('content', actualContent); + node.children = node.children ? attributeSlotElement.concat(node.children) : attributeSlotElement; + + delete node.attribs.src; + + return childContext; +} + module.exports = { processInclude, + processPopoverSrc, processPanelSrc, }; diff --git a/packages/core/src/html/linkProcessor.js b/packages/core/src/html/linkProcessor.js index 4f225a4386..bf4588fe7c 100644 --- a/packages/core/src/html/linkProcessor.js +++ b/packages/core/src/html/linkProcessor.js @@ -19,6 +19,7 @@ const defaultTagLinkMap = { link: 'href', include: 'src', panel: 'src', + popover: 'src', script: 'src', }; diff --git a/packages/core/test/unit/html/NodeProcessor.data.js b/packages/core/test/unit/html/NodeProcessor.data.js index 32878fb688..85c4861022 100644 --- a/packages/core/test/unit/html/NodeProcessor.data.js +++ b/packages/core/test/unit/html/NodeProcessor.data.js @@ -146,7 +146,7 @@ module.exports.PROCESS_POPOVER_ATTRIBUTES = ` `; module.exports.PROCESS_POPOVER_ATTRIBUTES_EXPECTED = ` - + Content and header attributes should be processed and inserted under panel as slots and deleted. `; diff --git a/packages/vue-components/README.md b/packages/vue-components/README.md index 3bfd4b1aa5..5f054bb3bf 100644 --- a/packages/vue-components/README.md +++ b/packages/vue-components/README.md @@ -50,8 +50,8 @@ Some custom components and directives are also added for MarkBind's use. ### BootstrapVue components included in the bundle - Modals -- Popovers -- Tooltips +- Popover.vue +- Tooltip.vue ## Installation