docfx.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.
  2. $(function () {
  3. var active = 'active';
  4. var expanded = 'in';
  5. var collapsed = 'collapsed';
  6. var filtered = 'filtered';
  7. var show = 'show';
  8. var hide = 'hide';
  9. var util = new utility();
  10. highlight();
  11. enableSearch();
  12. renderTables();
  13. renderAlerts();
  14. renderLinks();
  15. renderNavbar();
  16. renderSidebar();
  17. renderAffix();
  18. renderFooter();
  19. renderLogo();
  20. breakText();
  21. window.refresh = function (article) {
  22. // Update markup result
  23. if (typeof article == 'undefined' || typeof article.content == 'undefined')
  24. console.error("Null Argument");
  25. $("article.content").html(article.content);
  26. highlight();
  27. renderTables();
  28. renderAlerts();
  29. renderAffix();
  30. }
  31. function breakText() {
  32. $(".xref").addClass("text-break");
  33. var texts = $(".text-break");
  34. texts.each(function () {
  35. $(this).text(function (index, text) {
  36. return util.breakText(text);
  37. })
  38. });
  39. }
  40. // Styling for tables in conceptual documents using Bootstrap.
  41. // See http://getbootstrap.com/css/#tables
  42. function renderTables() {
  43. $('table').addClass('table table-bordered table-striped table-condensed');
  44. }
  45. // Styling for alerts.
  46. function renderAlerts() {
  47. $('.NOTE, .TIP').addClass('alert alert-info');
  48. $('.WARNING').addClass('alert alert-warning');
  49. $('.IMPORTANT, .CAUTION').addClass('alert alert-danger');
  50. }
  51. // Enable anchors for headings.
  52. (function () {
  53. anchors.options = {
  54. placement: 'left',
  55. visible: 'touch'
  56. };
  57. anchors.add('article h2:not(.no-anchor), article h3:not(.no-anchor), article h4:not(.no-anchor)');
  58. })();
  59. // Open links to different host in a new window.
  60. function renderLinks() {
  61. if ($("meta[property='docfx:newtab']").attr("content") === "true") {
  62. $(document.links).filter(function () {
  63. return this.hostname !== window.location.hostname;
  64. }).attr('target', '_blank');
  65. }
  66. }
  67. // Enable highlight.js
  68. function highlight() {
  69. $('pre code').each(function (i, block) {
  70. hljs.highlightBlock(block);
  71. });
  72. $('pre code[highlight-lines]').each(function (i, block) {
  73. if (block.innerHTML === "") return;
  74. var lines = block.innerHTML.split('\n');
  75. queryString = block.getAttribute('highlight-lines');
  76. if (!queryString) return;
  77. var ranges = queryString.split(',');
  78. for (var j = 0, range; range = ranges[j++];) {
  79. var found = range.match(/^(\d+)\-(\d+)?$/);
  80. if (found) {
  81. // consider region as `{startlinenumber}-{endlinenumber}`, in which {endlinenumber} is optional
  82. var start = +found[1];
  83. var end = +found[2];
  84. if (isNaN(end) || end > lines.length) {
  85. end = lines.length;
  86. }
  87. } else {
  88. // consider region as a sigine line number
  89. if (isNaN(range)) continue;
  90. var start = +range;
  91. var end = start;
  92. }
  93. if (start <= 0 || end <= 0 || start > end || start > lines.length) {
  94. // skip current region if invalid
  95. continue;
  96. }
  97. lines[start - 1] = '<span class="line-highlight">' + lines[start - 1];
  98. lines[end - 1] = lines[end - 1] + '</span>';
  99. }
  100. block.innerHTML = lines.join('\n');
  101. });
  102. }
  103. // Support full-text-search
  104. function enableSearch() {
  105. var query;
  106. var relHref = $("meta[property='docfx\\:rel']").attr("content");
  107. if (typeof relHref === 'undefined') {
  108. return;
  109. }
  110. try {
  111. var worker = new Worker(relHref + 'styles/search-worker.js');
  112. if (!worker && !window.worker) {
  113. localSearch();
  114. } else {
  115. webWorkerSearch();
  116. }
  117. renderSearchBox();
  118. highlightKeywords();
  119. addSearchEvent();
  120. } catch (e) {
  121. console.error(e);
  122. }
  123. //Adjust the position of search box in navbar
  124. function renderSearchBox() {
  125. autoCollapse();
  126. $(window).on('resize', autoCollapse);
  127. $(document).on('click', '.navbar-collapse.in', function (e) {
  128. if ($(e.target).is('a')) {
  129. $(this).collapse('hide');
  130. }
  131. });
  132. function autoCollapse() {
  133. var navbar = $('#autocollapse');
  134. if (navbar.height() === null) {
  135. setTimeout(autoCollapse, 300);
  136. }
  137. navbar.removeClass(collapsed);
  138. if (navbar.height() > 60) {
  139. navbar.addClass(collapsed);
  140. }
  141. }
  142. }
  143. // Search factory
  144. function localSearch() {
  145. console.log("using local search");
  146. var lunrIndex = lunr(function () {
  147. this.ref('href');
  148. this.field('title', { boost: 50 });
  149. this.field('keywords', { boost: 20 });
  150. });
  151. lunr.tokenizer.seperator = /[\s\-\.]+/;
  152. var searchData = {};
  153. var searchDataRequest = new XMLHttpRequest();
  154. var indexPath = relHref + "index.json";
  155. if (indexPath) {
  156. searchDataRequest.open('GET', indexPath);
  157. searchDataRequest.onload = function () {
  158. if (this.status != 200) {
  159. return;
  160. }
  161. searchData = JSON.parse(this.responseText);
  162. for (var prop in searchData) {
  163. if (searchData.hasOwnProperty(prop)){
  164. lunrIndex.add(searchData[prop]);
  165. }
  166. }
  167. }
  168. searchDataRequest.send();
  169. }
  170. $("body").bind("queryReady", function () {
  171. var hits = lunrIndex.search(query);
  172. var results = [];
  173. hits.forEach(function (hit) {
  174. var item = searchData[hit.ref];
  175. results.push({ 'href': item.href, 'title': item.title, 'keywords': item.keywords });
  176. });
  177. handleSearchResults(results);
  178. });
  179. }
  180. function webWorkerSearch() {
  181. console.log("using Web Worker");
  182. var indexReady = $.Deferred();
  183. worker.onmessage = function (oEvent) {
  184. switch (oEvent.data.e) {
  185. case 'index-ready':
  186. indexReady.resolve();
  187. break;
  188. case 'query-ready':
  189. var hits = oEvent.data.d;
  190. handleSearchResults(hits);
  191. break;
  192. }
  193. }
  194. indexReady.promise().done(function () {
  195. $("body").bind("queryReady", function () {
  196. worker.postMessage({ q: query });
  197. });
  198. });
  199. }
  200. // Highlight the searching keywords
  201. function highlightKeywords() {
  202. var q = url('?q');
  203. if (q !== null) {
  204. var keywords = q.split("%20");
  205. keywords.forEach(function (keyword) {
  206. if (keyword !== "") {
  207. $('.data-searchable *').mark(keyword);
  208. $('article *').mark(keyword);
  209. }
  210. });
  211. }
  212. }
  213. function addSearchEvent() {
  214. $('body').bind("searchEvent", function () {
  215. $('#search-query').keypress(function (e) {
  216. return e.which !== 13;
  217. });
  218. $('#search-query').keyup(function () {
  219. query = $(this).val();
  220. if (query.length < 3) {
  221. flipContents("show");
  222. } else {
  223. flipContents("hide");
  224. $("body").trigger("queryReady");
  225. $('#search-results>.search-list').text('Search Results for "' + query + '"');
  226. }
  227. }).off("keydown");
  228. });
  229. }
  230. function flipContents(action) {
  231. if (action === "show") {
  232. $('.hide-when-search').show();
  233. $('#search-results').hide();
  234. } else {
  235. $('.hide-when-search').hide();
  236. $('#search-results').show();
  237. }
  238. }
  239. function relativeUrlToAbsoluteUrl(currentUrl, relativeUrl) {
  240. var currentItems = currentUrl.split(/\/+/);
  241. var relativeItems = relativeUrl.split(/\/+/);
  242. var depth = currentItems.length - 1;
  243. var items = [];
  244. for (var i = 0; i < relativeItems.length; i++) {
  245. if (relativeItems[i] === '..') {
  246. depth--;
  247. } else if (relativeItems[i] !== '.') {
  248. items.push(relativeItems[i]);
  249. }
  250. }
  251. return currentItems.slice(0, depth).concat(items).join('/');
  252. }
  253. function extractContentBrief(content) {
  254. var briefOffset = 512;
  255. var words = query.split(/\s+/g);
  256. var queryIndex = content.indexOf(words[0]);
  257. var briefContent;
  258. if (queryIndex > briefOffset) {
  259. return "..." + content.slice(queryIndex - briefOffset, queryIndex + briefOffset) + "...";
  260. } else if (queryIndex <= briefOffset) {
  261. return content.slice(0, queryIndex + briefOffset) + "...";
  262. }
  263. }
  264. function handleSearchResults(hits) {
  265. var numPerPage = 10;
  266. $('#pagination').empty();
  267. $('#pagination').removeData("twbs-pagination");
  268. if (hits.length === 0) {
  269. $('#search-results>.sr-items').html('<p>No results found</p>');
  270. } else {
  271. $('#pagination').twbsPagination({
  272. totalPages: Math.ceil(hits.length / numPerPage),
  273. visiblePages: 5,
  274. onPageClick: function (event, page) {
  275. var start = (page - 1) * numPerPage;
  276. var curHits = hits.slice(start, start + numPerPage);
  277. $('#search-results>.sr-items').empty().append(
  278. curHits.map(function (hit) {
  279. var currentUrl = window.location.href;
  280. var itemRawHref = relativeUrlToAbsoluteUrl(currentUrl, relHref + hit.href);
  281. var itemHref = relHref + hit.href + "?q=" + query;
  282. var itemTitle = hit.title;
  283. var itemBrief = extractContentBrief(hit.keywords);
  284. var itemNode = $('<div>').attr('class', 'sr-item');
  285. var itemTitleNode = $('<div>').attr('class', 'item-title').append($('<a>').attr('href', itemHref).attr("target", "_blank").text(itemTitle));
  286. var itemHrefNode = $('<div>').attr('class', 'item-href').text(itemRawHref);
  287. var itemBriefNode = $('<div>').attr('class', 'item-brief').text(itemBrief);
  288. itemNode.append(itemTitleNode).append(itemHrefNode).append(itemBriefNode);
  289. return itemNode;
  290. })
  291. );
  292. query.split(/\s+/).forEach(function (word) {
  293. if (word !== '') {
  294. $('#search-results>.sr-items *').mark(word);
  295. }
  296. });
  297. }
  298. });
  299. }
  300. }
  301. };
  302. // Update href in navbar
  303. function renderNavbar() {
  304. var navbar = $('#navbar ul')[0];
  305. if (typeof (navbar) === 'undefined') {
  306. loadNavbar();
  307. } else {
  308. $('#navbar ul a.active').parents('li').addClass(active);
  309. renderBreadcrumb();
  310. }
  311. function loadNavbar() {
  312. var navbarPath = $("meta[property='docfx\\:navrel']").attr("content");
  313. if (!navbarPath) {
  314. return;
  315. }
  316. navbarPath = navbarPath.replace(/\\/g, '/');
  317. var tocPath = $("meta[property='docfx\\:tocrel']").attr("content") || '';
  318. if (tocPath) tocPath = tocPath.replace(/\\/g, '/');
  319. $.get(navbarPath, function (data) {
  320. $(data).find("#toc>ul").appendTo("#navbar");
  321. if ($('#search-results').length !== 0) {
  322. $('#search').show();
  323. $('body').trigger("searchEvent");
  324. }
  325. var index = navbarPath.lastIndexOf('/');
  326. var navrel = '';
  327. if (index > -1) {
  328. navrel = navbarPath.substr(0, index + 1);
  329. }
  330. $('#navbar>ul').addClass('navbar-nav');
  331. var currentAbsPath = util.getAbsolutePath(window.location.pathname);
  332. // set active item
  333. $('#navbar').find('a[href]').each(function (i, e) {
  334. var href = $(e).attr("href");
  335. if (util.isRelativePath(href)) {
  336. href = navrel + href;
  337. $(e).attr("href", href);
  338. // TODO: currently only support one level navbar
  339. var isActive = false;
  340. var originalHref = e.name;
  341. if (originalHref) {
  342. originalHref = navrel + originalHref;
  343. if (util.getDirectory(util.getAbsolutePath(originalHref)) === util.getDirectory(util.getAbsolutePath(tocPath))) {
  344. isActive = true;
  345. }
  346. } else {
  347. if (util.getAbsolutePath(href) === currentAbsPath) {
  348. isActive = true;
  349. }
  350. }
  351. if (isActive) {
  352. $(e).addClass(active);
  353. }
  354. }
  355. });
  356. renderNavbar();
  357. });
  358. }
  359. }
  360. function renderSidebar() {
  361. var sidetoc = $('#sidetoggle .sidetoc')[0];
  362. if (typeof (sidetoc) === 'undefined') {
  363. loadToc();
  364. } else {
  365. registerTocEvents();
  366. if ($('footer').is(':visible')) {
  367. $('.sidetoc').addClass('shiftup');
  368. }
  369. // Scroll to active item
  370. var top = 0;
  371. $('#toc a.active').parents('li').each(function (i, e) {
  372. $(e).addClass(active).addClass(expanded);
  373. $(e).children('a').addClass(active);
  374. top += $(e).position().top;
  375. })
  376. $('.sidetoc').scrollTop(top - 50);
  377. if ($('footer').is(':visible')) {
  378. $('.sidetoc').addClass('shiftup');
  379. }
  380. renderBreadcrumb();
  381. }
  382. function registerTocEvents() {
  383. $('.toc .nav > li > .expand-stub').click(function (e) {
  384. $(e.target).parent().toggleClass(expanded);
  385. });
  386. $('.toc .nav > li > .expand-stub + a:not([href])').click(function (e) {
  387. $(e.target).parent().toggleClass(expanded);
  388. });
  389. $('#toc_filter_input').on('input', function (e) {
  390. var val = this.value;
  391. if (val === '') {
  392. // Clear 'filtered' class
  393. $('#toc li').removeClass(filtered).removeClass(hide);
  394. return;
  395. }
  396. // Get leaf nodes
  397. $('#toc li>a').filter(function (i, e) {
  398. return $(e).siblings().length === 0
  399. }).each(function (i, anchor) {
  400. var text = $(anchor).attr('title');
  401. var parent = $(anchor).parent();
  402. var parentNodes = parent.parents('ul>li');
  403. for (var i = 0; i < parentNodes.length; i++) {
  404. var parentText = $(parentNodes[i]).children('a').attr('title');
  405. if (parentText) text = parentText + '.' + text;
  406. };
  407. if (filterNavItem(text, val)) {
  408. parent.addClass(show);
  409. parent.removeClass(hide);
  410. } else {
  411. parent.addClass(hide);
  412. parent.removeClass(show);
  413. }
  414. });
  415. $('#toc li>a').filter(function (i, e) {
  416. return $(e).siblings().length > 0
  417. }).each(function (i, anchor) {
  418. var parent = $(anchor).parent();
  419. if (parent.find('li.show').length > 0) {
  420. parent.addClass(show);
  421. parent.addClass(filtered);
  422. parent.removeClass(hide);
  423. } else {
  424. parent.addClass(hide);
  425. parent.removeClass(show);
  426. parent.removeClass(filtered);
  427. }
  428. })
  429. function filterNavItem(name, text) {
  430. if (!text) return true;
  431. if (name.toLowerCase().indexOf(text.toLowerCase()) > -1) return true;
  432. return false;
  433. }
  434. });
  435. }
  436. function loadToc() {
  437. var tocPath = $("meta[property='docfx\\:tocrel']").attr("content");
  438. if (!tocPath) {
  439. return;
  440. }
  441. tocPath = tocPath.replace(/\\/g, '/');
  442. $('#sidetoc').load(tocPath + " #sidetoggle > div", function () {
  443. var index = tocPath.lastIndexOf('/');
  444. var tocrel = '';
  445. if (index > -1) {
  446. tocrel = tocPath.substr(0, index + 1);
  447. }
  448. var currentHref = util.getAbsolutePath(window.location.pathname);
  449. $('#sidetoc').find('a[href]').each(function (i, e) {
  450. var href = $(e).attr("href");
  451. if (util.isRelativePath(href)) {
  452. href = tocrel + href;
  453. $(e).attr("href", href);
  454. }
  455. if (util.getAbsolutePath(e.href) === currentHref) {
  456. $(e).addClass(active);
  457. }
  458. $(e).text(function (index, text) {
  459. return util.breakText(text);
  460. })
  461. });
  462. renderSidebar();
  463. });
  464. }
  465. }
  466. function renderBreadcrumb() {
  467. var breadcrumb = [];
  468. $('#navbar a.active').each(function (i, e) {
  469. breadcrumb.push({
  470. href: e.href,
  471. name: e.innerHTML
  472. });
  473. })
  474. $('#toc a.active').each(function (i, e) {
  475. breadcrumb.push({
  476. href: e.href,
  477. name: e.innerHTML
  478. });
  479. })
  480. var html = util.formList(breadcrumb, 'breadcrumb');
  481. $('#breadcrumb').html(html);
  482. }
  483. //Setup Affix
  484. function renderAffix() {
  485. var hierarchy = getHierarchy();
  486. if (hierarchy.length > 0) {
  487. var html = '<h5 class="title">In This Article</h5>'
  488. html += util.formList(hierarchy, ['nav', 'bs-docs-sidenav']);
  489. $("#affix").empty().append(html);
  490. if ($('footer').is(':visible')) {
  491. $(".sideaffix").css("bottom", "70px");
  492. }
  493. $('#affix').on('activate.bs.scrollspy', function (e) {
  494. if (e.target) {
  495. if ($(e.target).find('li.active').length > 0) {
  496. return;
  497. }
  498. var top = $(e.target).position().top;
  499. $(e.target).parents('li').each(function (i, e) {
  500. top += $(e).position().top;
  501. });
  502. var container = $('#affix > ul');
  503. var height = container.height();
  504. container.scrollTop(container.scrollTop() + top - height / 2);
  505. }
  506. })
  507. }
  508. function getHierarchy() {
  509. // supported headers are h1, h2, h3, and h4
  510. // The topest header is ignored
  511. var selector = ".article article";
  512. var affixSelector = "#affix";
  513. var headers = ['h4', 'h3', 'h2', 'h1'];
  514. var hierarchy = [];
  515. var toppestIndex = -1;
  516. var startIndex = -1;
  517. // 1. get header hierarchy
  518. for (var i = headers.length - 1; i >= 0; i--) {
  519. var header = $(selector + " " + headers[i]);
  520. var length = header.length;
  521. // If contains no header in current selector, find the next one
  522. if (length === 0) continue;
  523. // If the toppest header contains only one item, e.g. title, ignore
  524. if (length === 1 && hierarchy.length === 0 && toppestIndex < 0) {
  525. toppestIndex = i;
  526. continue;
  527. }
  528. // Get second level children
  529. var nextLevelSelector = i > 0 ? headers[i - 1] : null;
  530. var prevSelector;
  531. for (var j = length - 1; j >= 0; j--) {
  532. var e = header[j];
  533. var id = e.id;
  534. if (!id) continue; // For affix, id is a must-have
  535. var item = {
  536. name: htmlEncode($(e).text()),
  537. href: "#" + id,
  538. items: []
  539. };
  540. if (nextLevelSelector) {
  541. var selector = '#' + cssEscape(id) + "~" + nextLevelSelector;
  542. var currentSelector = selector;
  543. if (prevSelector) currentSelector += ":not(" + prevSelector + ")";
  544. $(header[j]).siblings(currentSelector).each(function (index, e) {
  545. if (e.id) {
  546. item.items.push({
  547. name: htmlEncode($(e).text()), // innerText decodes text while innerHTML not
  548. href: "#" + e.id
  549. })
  550. }
  551. })
  552. prevSelector = selector;
  553. }
  554. hierarchy.push(item);
  555. }
  556. break;
  557. };
  558. hierarchy.reverse();
  559. return hierarchy;
  560. }
  561. function htmlEncode(str) {
  562. if (!str) return str;
  563. return str
  564. .replace(/&/g, '&amp;')
  565. .replace(/"/g, '&quot;')
  566. .replace(/'/g, '&#39;')
  567. .replace(/</g, '&lt;')
  568. .replace(/>/g, '&gt;');
  569. }
  570. function htmlDecode(value) {
  571. if (!str) return str;
  572. return value
  573. .replace(/&quot;/g, '"')
  574. .replace(/&#39;/g, "'")
  575. .replace(/&lt;/g, '<')
  576. .replace(/&gt;/g, '>')
  577. .replace(/&amp;/g, '&');
  578. }
  579. function cssEscape(str) {
  580. // see: http://stackoverflow.com/questions/2786538/need-to-escape-a-special-character-in-a-jquery-selector-string#answer-2837646
  581. if (!str) return str;
  582. return str
  583. .replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&");
  584. }
  585. }
  586. // Show footer
  587. function renderFooter() {
  588. initFooter();
  589. $(window).on("scroll", showFooterCore);
  590. function initFooter() {
  591. if (needFooter()) {
  592. shiftUpBottomCss();
  593. $("footer").show();
  594. } else {
  595. resetBottomCss();
  596. $("footer").hide();
  597. }
  598. }
  599. function showFooterCore() {
  600. if (needFooter()) {
  601. shiftUpBottomCss();
  602. $("footer").fadeIn();
  603. } else {
  604. resetBottomCss();
  605. $("footer").fadeOut();
  606. }
  607. }
  608. function needFooter() {
  609. var scrollHeight = $(document).height();
  610. var scrollPosition = $(window).height() + $(window).scrollTop();
  611. return (scrollHeight - scrollPosition) < 1;
  612. }
  613. function resetBottomCss() {
  614. $(".sidetoc").removeClass("shiftup");
  615. $(".sideaffix").removeClass("shiftup");
  616. }
  617. function shiftUpBottomCss() {
  618. $(".sidetoc").addClass("shiftup");
  619. $(".sideaffix").addClass("shiftup");
  620. }
  621. }
  622. function renderLogo() {
  623. // For LOGO SVG
  624. // Replace SVG with inline SVG
  625. // http://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement
  626. jQuery('img.svg').each(function () {
  627. var $img = jQuery(this);
  628. var imgID = $img.attr('id');
  629. var imgClass = $img.attr('class');
  630. var imgURL = $img.attr('src');
  631. jQuery.get(imgURL, function (data) {
  632. // Get the SVG tag, ignore the rest
  633. var $svg = jQuery(data).find('svg');
  634. // Add replaced image's ID to the new SVG
  635. if (typeof imgID !== 'undefined') {
  636. $svg = $svg.attr('id', imgID);
  637. }
  638. // Add replaced image's classes to the new SVG
  639. if (typeof imgClass !== 'undefined') {
  640. $svg = $svg.attr('class', imgClass + ' replaced-svg');
  641. }
  642. // Remove any invalid XML tags as per http://validator.w3.org
  643. $svg = $svg.removeAttr('xmlns:a');
  644. // Replace image with new SVG
  645. $img.replaceWith($svg);
  646. }, 'xml');
  647. });
  648. }
  649. function utility() {
  650. this.getAbsolutePath = getAbsolutePath;
  651. this.isRelativePath = isRelativePath;
  652. this.isAbsolutePath = isAbsolutePath;
  653. this.getDirectory = getDirectory;
  654. this.formList = formList;
  655. this.breakText = breakText;
  656. function getAbsolutePath(href) {
  657. // Use anchor to normalize href
  658. var anchor = $('<a href="' + href + '"></a>')[0];
  659. // Ignore protocal, remove search and query
  660. return anchor.host + anchor.pathname;
  661. }
  662. function isRelativePath(href) {
  663. return !isAbsolutePath(href);
  664. }
  665. function isAbsolutePath(href) {
  666. return (/^(?:[a-z]+:)?\/\//i).test(href);
  667. }
  668. function getDirectory(href) {
  669. if (!href) return '';
  670. var index = href.lastIndexOf('/');
  671. if (index == -1) return '';
  672. if (index > -1) {
  673. return href.substr(0, index);
  674. }
  675. }
  676. function formList(item, classes) {
  677. var level = 1;
  678. var model = {
  679. items: item
  680. };
  681. var cls = [].concat(classes).join(" ");
  682. return getList(model, cls);
  683. function getList(model, cls) {
  684. if (!model || !model.items) return null;
  685. var l = model.items.length;
  686. if (l === 0) return null;
  687. var html = '<ul class="level' + level + ' ' + (cls || '') + '">';
  688. level++;
  689. for (var i = 0; i < l; i++) {
  690. var item = model.items[i];
  691. var href = item.href;
  692. var name = item.name;
  693. if (!name) continue;
  694. html += href ? '<li><a href="' + href + '">' + name + '</a>' : '<li>' + name;
  695. html += getList(item, cls) || '';
  696. html += '</li>';
  697. }
  698. html += '</ul>';
  699. return html;
  700. }
  701. }
  702. function breakText(text) {
  703. if (!text) return text;
  704. return text.replace(/([a-z])([A-Z])|(\.)(\w)/g, '$1$3\u200B$2$4')
  705. }
  706. }
  707. })