You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

docfx.js 23 KiB

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