PageRenderTime 41ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/Lining.js/0.3.2/lining.js

https://gitlab.com/mba811/static
JavaScript | 918 lines | 543 code | 94 blank | 281 comment | 95 complexity | fbfc6b3b5814d6bac41cfbda3c29182a MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. /**
  2. * lining.js
  3. * Write css style for `line` in typography.
  4. * https://github.com/zmmbreeze/lining.
  5. *
  6. * @author zmmbreeze / @zhoumm
  7. */
  8. /* jshint sub:true, camelcase:false */
  9. (function (win, doc) {
  10. var emptyNodeNames = {
  11. 'STYLE': true,
  12. 'SCRIPT': true,
  13. 'LINK': true,
  14. 'BR': true
  15. };
  16. var notEmptyNodeNames = {
  17. 'TEXTAREA': true,
  18. 'IMG': true,
  19. 'INPUT': true,
  20. 'SELECT': true,
  21. 'HR': true
  22. };
  23. var util = {
  24. /**
  25. * fire event
  26. * @param {Element} element
  27. * @param {string} type
  28. * @param {boolean} cancelable
  29. * @return {boolean} cancelled or not
  30. */
  31. fireEvent: function (element, type, cancelable) {
  32. var event = doc.createEvent('Event');
  33. event.initEvent(type, true, cancelable);
  34. return element.dispatchEvent(event);
  35. },
  36. /**
  37. * Insert css text.
  38. *
  39. * @param {string} css css style text.
  40. */
  41. createStyle: function (css) {
  42. var style = doc.createElement('style');
  43. style.type = 'text/css';
  44. if (style.styleSheet) {
  45. // IE
  46. style.styleSheet.cssText = css;
  47. }
  48. else {
  49. style.appendChild(doc.createTextNode(css));
  50. }
  51. doc.getElementsByTagName('head')[0].appendChild(style);
  52. },
  53. /**
  54. * Init this plugin at the first time.
  55. */
  56. init: function initStyle() {
  57. if (initStyle.inited) {
  58. return;
  59. }
  60. initStyle.inited = true;
  61. // init style
  62. util.createStyle(
  63. ''
  64. + 'text-line {'
  65. + 'display:block;'
  66. + 'text-indent:0;'
  67. + '}'
  68. + 'pre text-line {'
  69. + 'display:inline;'
  70. + '}'
  71. + 'text-line[first-in-element]:first-child {'
  72. + 'text-indent:inherit;'
  73. + '}'
  74. );
  75. },
  76. /**
  77. * remove childNodes
  78. * <span>aaa|<b>bbb</b>ccc</span>
  79. * ==>
  80. * <span>aaa</span>
  81. *
  82. * @param {Element} node
  83. * @param {number} from
  84. * @param {number=} opt_to
  85. * @return {Array.<Element>} children
  86. */
  87. removeChildren: function (node, from, opt_to) {
  88. if (from < 0) {
  89. from = 0;
  90. }
  91. var children = node.childNodes;
  92. var to = opt_to == null ? children.length : opt_to;
  93. if (from >= to) {
  94. return [];
  95. }
  96. var removed = [];
  97. var i = to - 1;
  98. var lastChild;
  99. while (i >= from) {
  100. lastChild = children[i];
  101. removed.push(lastChild);
  102. node.removeChild(lastChild);
  103. i--;
  104. }
  105. return removed;
  106. },
  107. /**
  108. * append children
  109. * @param {Element} parent
  110. * @param {Array.<Element>} children
  111. */
  112. appendChildren: function (parent, children) {
  113. while (children.length) {
  114. parent.appendChild(children.pop());
  115. }
  116. },
  117. /**
  118. * split node.
  119. * <span>aaa|<b>bbb</b>ccc</span>
  120. * ==>
  121. * <span>aaa</span>|<span><b>bbb</b>ccc</span>
  122. *
  123. * @param {Element} node
  124. * @param {number} offset
  125. */
  126. splitNode: function (node, offset) {
  127. var parent = node.parentNode;
  128. var clone = node.cloneNode(false);
  129. util.appendChildren(clone, util.removeChildren(node, offset));
  130. parent.insertBefore(clone, node.nextSibling);
  131. return parent;
  132. },
  133. /**
  134. * get node's offset
  135. * @param {Element} node
  136. * @return {number} offset
  137. */
  138. getNodeOffset: function (node, ignoreTextNode) {
  139. var prev = node;
  140. var i = 0;
  141. while (prev = prev.previousSibling) {
  142. i++;
  143. }
  144. return i;
  145. },
  146. /**
  147. * if it has no text.
  148. *
  149. * @param {Element} node
  150. * @return {boolean} true or false.
  151. */
  152. isEmptyNode: function (node) {
  153. if (node.nodeType === 3) {
  154. return node.nodeValue.trim() === '';
  155. }
  156. var nodeName = node.nodeName;
  157. if (emptyNodeNames[nodeName]) {
  158. return true;
  159. }
  160. if (notEmptyNodeNames[nodeName]) {
  161. return false;
  162. }
  163. var children = node.childNodes;
  164. if (!children.length) {
  165. return true;
  166. }
  167. for (var i = 0, l = children.length; i < l; i++) {
  168. if (!util.isEmptyNode(children[i])) {
  169. return false;
  170. }
  171. }
  172. return true;
  173. },
  174. /**
  175. * get the next node which has content,
  176. * like text, img, textarea, input node.
  177. *
  178. * @param {Element} container
  179. * @return {Array} [container, offset] next node which has content.
  180. */
  181. getFirstContentNode: function (container) {
  182. if (container.nodeType === 3) {
  183. // is text node
  184. return [container, 0];
  185. }
  186. if (notEmptyNodeNames[container.nodeName]) {
  187. return [container.parentNode, util.getNodeOffset(container)];
  188. }
  189. var start = container.firstChild;
  190. if (!util.isEmptyNode(start)) {
  191. return util.getFirstContentNode(start);
  192. }
  193. var tmp = start;
  194. while (util.isEmptyNode(start)) {
  195. tmp = start.nextSibling;
  196. if (!tmp) {
  197. return null;
  198. }
  199. start = tmp;
  200. }
  201. return util.getFirstContentNode(start);
  202. },
  203. /**
  204. * adjust or split node.
  205. *
  206. * ancestor = p
  207. * <p><span>aaa<b>|bbb</b>ccc</span></p>
  208. * ==>
  209. * <p><span>aaa</span>|<span><b>bbb</b>ccc</span></p>
  210. *
  211. * @param {Element} ancestor
  212. * @param {Element} node
  213. * @param {number} offset
  214. * @return {Array} [container, offset]
  215. */
  216. adjustOrSplitNode: function (ancestor, node, offset) {
  217. var parent;
  218. var tmpOffset;
  219. while (node !== ancestor) {
  220. parent = node.parentNode;
  221. tmpOffset = util.getNodeOffset(node);
  222. switch (offset) {
  223. case 0:
  224. break;
  225. case node.childNodes.length:
  226. tmpOffset++;
  227. break;
  228. default:
  229. util.splitNode(node, offset);
  230. tmpOffset++;
  231. break;
  232. }
  233. node = parent;
  234. offset = tmpOffset;
  235. }
  236. return [node, offset];
  237. },
  238. /**
  239. * find the content sibling, forward or backward
  240. *
  241. * @param {Element} node
  242. * @param {string} direction forward / backward
  243. * @return {Array} siblingIsEmpty, offset from current node.
  244. */
  245. findContentSibling: function (node, direction) {
  246. var offset = 0;
  247. var siblingIsEmpty = true;
  248. direction = direction === 'forward'
  249. ? 'nextSibling'
  250. : 'previousSibling';
  251. var next = node[direction];
  252. while (next) {
  253. if (!util.isEmptyNode(next)) {
  254. siblingIsEmpty = false;
  255. break;
  256. }
  257. offset++;
  258. next = next[direction];
  259. }
  260. return [siblingIsEmpty, offset];
  261. },
  262. /**
  263. * this browser support lining.js or not
  264. * @return {boolean}
  265. */
  266. isSupported: function () {
  267. if (util.isSupported.re != null) {
  268. return util.isSupported.re;
  269. }
  270. var Selection = win['Selection'];
  271. var result = !!(Selection && Selection.prototype && Selection.prototype.modify);
  272. doc.documentElement.className += ' nolining';
  273. util.isSupported.re = result;
  274. return result;
  275. },
  276. /**
  277. * is node inside `line` node
  278. * @param {Element} node
  279. * @param {Element} root
  280. * @return {boolean}
  281. */
  282. isInLine: function (node, root) {
  283. node = node.parentNode;
  284. while (root.contains(node)) {
  285. if (node.nodeName === 'TEXT-LINE') {
  286. return true;
  287. }
  288. node = node.parentNode;
  289. }
  290. return false;
  291. },
  292. /**
  293. * is node inside `line` node
  294. * @param {Element} root
  295. * @return {Array.<Element>}
  296. */
  297. getAllOutSideBr: function (root) {
  298. var brs = root.getElementsByTagName('br');
  299. var br;
  300. var outSideBrs = [];
  301. for (var i = 0, l = brs.length; i < l; i++) {
  302. br = brs[i];
  303. if (!util.isInLine(br, root)) {
  304. outSideBrs.push(br);
  305. }
  306. }
  307. return outSideBrs;
  308. }
  309. };
  310. /**
  311. * Lining
  312. *
  313. * @constructor
  314. * @param {Element} element
  315. * @param {Object=} opt_option
  316. */
  317. var Lining = function (element, opt_option) {
  318. var opt = opt_option || {};
  319. /**
  320. * if auto resize when window resize trigger.
  321. * @type {boolean}
  322. * @private
  323. */
  324. this._autoResize = opt['autoResize'] == null
  325. ? element.hasAttribute('data-auto-resize')
  326. : opt['autoResize'];
  327. /**
  328. * from line number
  329. * @type {number}
  330. */
  331. this.from = (opt['from'] - 1)
  332. || (parseInt(element.getAttribute('data-from'), 10) - 1)
  333. || 0;
  334. this.from = Math.max(this.from, 0);
  335. /**
  336. * end line number
  337. * @type {number}
  338. */
  339. this.to = opt['to']
  340. || parseInt(element.getAttribute('data-to'), 10)
  341. || null;
  342. /**
  343. * line class name
  344. * @type {string}
  345. */
  346. this.lineClassName = opt['lineClass']
  347. || element.getAttribute('data-line-class')
  348. || 'line';
  349. /**
  350. * element
  351. * @type {Element}
  352. * @private
  353. */
  354. this._e = element;
  355. /**
  356. * @type {number}
  357. * @private
  358. */
  359. this._oldWidth = -1;
  360. /**
  361. * @type {Document}
  362. */
  363. this.doc = null;
  364. /**
  365. * @type {Window}
  366. */
  367. this.win = null;
  368. /**
  369. * @type {Element}
  370. * @private
  371. */
  372. this._ancestor = null;
  373. /**
  374. * @type {Element}
  375. * @private
  376. */
  377. this._start = null;
  378. /**
  379. * @type {number}
  380. * @private
  381. */
  382. this._startOffset = 0;
  383. /**
  384. * @type {Element}
  385. * @private
  386. */
  387. this._end = null;
  388. /**
  389. * @type {number}
  390. * @private
  391. */
  392. this._endOffset = 0;
  393. /**
  394. * @type {boolean}
  395. * @private
  396. */
  397. this._collapsed = false;
  398. /**
  399. * line count
  400. * @type {number}
  401. */
  402. this.count = 0;
  403. /**
  404. * @type {Element}
  405. * @private
  406. */
  407. this._currentLine = null;
  408. /**
  409. * inited
  410. * @type {boolean}
  411. * @private
  412. */
  413. this._inited = false;
  414. util.init();
  415. };
  416. /**
  417. * init and start
  418. */
  419. Lining.prototype.init = function () {
  420. var that = this;
  421. if (that._inited) {
  422. return;
  423. }
  424. that._inited = true;
  425. if (!util.isSupported()) {
  426. this._e.removeAttribute('data-lining');
  427. return;
  428. }
  429. that.doc = that._e.ownerDocument;
  430. that.win = that.doc.defaultView;
  431. that.relining();
  432. if (!this._autoResize) {
  433. return that;
  434. }
  435. // setup auto resize when window resized.
  436. var timeout;
  437. that.win.addEventListener('resize', function () {
  438. if (timeout) {
  439. clearTimeout(timeout);
  440. timeout = null;
  441. }
  442. timeout = setTimeout(function () {
  443. that.relining();
  444. }, 1000);
  445. }, false);
  446. return that;
  447. };
  448. /**
  449. * remove all line tags
  450. */
  451. Lining.prototype.unlining = function () {
  452. if (!util.isSupported()) {
  453. return;
  454. }
  455. util.fireEvent(this._e, 'beforeunlining', false);
  456. var lines = this._e.getElementsByTagName('text-line');
  457. var line;
  458. var removed;
  459. var parent;
  460. for (var i = 0, l = lines.length; i < l; i++) {
  461. line = lines[i];
  462. parent = line.parentNode;
  463. removed = util.removeChildren(line, 0);
  464. while (removed.length) {
  465. parent.insertBefore(removed.pop(), line);
  466. }
  467. }
  468. while (lines.length) {
  469. line = lines[lines.length - 1];
  470. line.parentNode.removeChild(line);
  471. }
  472. var brs = util.getAllOutSideBr(this._e);
  473. while (brs.length) {
  474. brs.pop().style.display = 'block';
  475. }
  476. this._e.normalize();
  477. this._e.setAttribute('data-lining', '');
  478. // reset
  479. this._currentLine = null;
  480. this._oldWidth = -1;
  481. this.count = 0;
  482. util.fireEvent(this._e, 'afterunlining', false);
  483. };
  484. /**
  485. * Remove all line tags if needed,
  486. * and create new line tags.
  487. * @param {boolean} opt_force
  488. */
  489. Lining.prototype.relining = function (opt_force) {
  490. if (!util.isSupported()) {
  491. return;
  492. }
  493. var newWidth = this._e.offsetWidth;
  494. var isLininged = (this._oldWidth >= 0) || (this._e.getAttribute('data-lining') === 'end');
  495. // 宽度改变了,或者强制开始
  496. var widthChanged = opt_force || this._oldWidth !== newWidth;
  497. if ((isLininged && !widthChanged) || !util.fireEvent(this._e, 'beforelining', true)) {
  498. return;
  499. }
  500. if (isLininged && widthChanged) {
  501. this.unlining();
  502. }
  503. this._currentLine = null;
  504. this._oldWidth = newWidth;
  505. this.count = this.from;
  506. var s = this.win.getSelection();
  507. while (this._selectNextLine(s)) {
  508. if (this.count < this.from) {
  509. continue;
  510. }
  511. this._createLine(s);
  512. }
  513. if (this._currentLine) {
  514. this._currentLine.setAttribute('last', '');
  515. this._adjustLine(this._currentLine, s);
  516. }
  517. s.removeAllRanges();
  518. var brs = util.getAllOutSideBr(this._e);
  519. while (brs.length) {
  520. brs.pop().style.display = 'none';
  521. }
  522. this._e.setAttribute('data-lining', 'end');
  523. util.fireEvent(this._e, 'afterlining', false);
  524. };
  525. /**
  526. * update container
  527. * @param {Range} r
  528. */
  529. Lining.prototype._update = function (r) {
  530. this._start = r.startContainer;
  531. this._startOffset = r.startOffset;
  532. this._end = r.endContainer;
  533. this._endOffset = r.endOffset;
  534. this._ancestor = r.commonAncestorContainer;
  535. this._collapsed = r.collapsed;
  536. };
  537. /**
  538. * set cursor.
  539. * @param {ELement} start
  540. * @param {number} startOffset
  541. * @param {Selection} opt_s
  542. */
  543. Lining.prototype._setCursor = function (start, startOffset, opt_s) {
  544. var s = opt_s || this.win.getSelection();
  545. var r = this.doc.createRange();
  546. r.setStart(start, startOffset);
  547. r.collapse(true);
  548. s.removeAllRanges();
  549. s.addRange(r);
  550. return r;
  551. };
  552. /**
  553. * select one line.
  554. *
  555. * @param {number} i
  556. * @return {boolean} success
  557. */
  558. Lining.prototype.selectLine = function (i) {
  559. var s = this.win.getSelection();
  560. this._setCursor(this._e, 0, s);
  561. // For webkit(chrome, safari),
  562. // if next character is a space, extend line wouldn't work right.
  563. s.modify('extend', 'forward', 'character');
  564. s.modify('extend', 'forward', 'lineboundary');
  565. var oldR;
  566. var tmp;
  567. while (i > 1) {
  568. i--;
  569. oldR = s.getRangeAt(0);
  570. tmp = this._getNextLineStartPoint(oldR.endContainer, oldR.endOffset);
  571. if (!tmp) {
  572. s.removeAllRanges();
  573. return false;
  574. }
  575. this._setCursor(tmp[0], tmp[1], s);
  576. // For webkit(chrome, safari),
  577. // if next character is a space, extend line wouldn't work right.
  578. s.modify('extend', 'forward', 'character');
  579. s.modify('extend', 'forward', 'lineboundary');
  580. }
  581. this._update(s.getRangeAt(0));
  582. return true;
  583. };
  584. /**
  585. * get the next line's start point.
  586. * @param {Element} end endContainer or end node
  587. * @param {number} endOffset endOffset
  588. * @return {Array} [start, startOffset]
  589. */
  590. Lining.prototype._getNextLineStartPoint = function (end, endOffset) {
  591. var current;
  592. if (end.nodeType === 3) {
  593. // if it's a text node
  594. if (end.nodeValue.slice(endOffset).trim() !== '') {
  595. // and `endOffset` is not the end.
  596. return [end, endOffset];
  597. }
  598. else {
  599. current = end;
  600. endOffset = util.getNodeOffset(end) + 1;
  601. end = end.parentNode;
  602. }
  603. }
  604. else {
  605. current = end.childNodes[endOffset - 1];
  606. }
  607. var r = util.findContentSibling(current, 'forward');
  608. var nextSiblingIsEmpty = r[0];
  609. var nextContentNodeOffset = r[1];
  610. if (nextSiblingIsEmpty) {
  611. if (this._e.contains(end.parentNode)) {
  612. return this._getNextLineStartPoint(
  613. end.parentNode,
  614. util.getNodeOffset(end) + 1
  615. );
  616. }
  617. else {
  618. return null;
  619. }
  620. }
  621. endOffset += nextContentNodeOffset;
  622. return util.getFirstContentNode(end.childNodes[endOffset]);
  623. };
  624. /**
  625. * select next line.
  626. *
  627. * @param {Selection} s
  628. * @return {boolean} if selected;
  629. */
  630. Lining.prototype._selectNextLine = function (s) {
  631. if (this.to && this.count >= this.to) {
  632. return false;
  633. }
  634. var line = this._currentLine;
  635. if (line) {
  636. var start = line;
  637. var startOffset = util.getNodeOffset(start) + 1;
  638. start = start.parentNode;
  639. var nextPoint = this._getNextLineStartPoint(start, startOffset);
  640. if (nextPoint) {
  641. this._setCursor(nextPoint[0], nextPoint[1], s);
  642. // For webkit(chrome, safari),
  643. // if next character is a space, extend line wouldn't work right.
  644. s.modify('extend', 'forward', 'character');
  645. s.modify('extend', 'forward', 'lineboundary');
  646. this._update(s.getRangeAt(0));
  647. }
  648. return !!nextPoint;
  649. }
  650. else {
  651. return this.selectLine(this.from + 1);
  652. }
  653. };
  654. /**
  655. * get range at 0
  656. * @return {Range} range.
  657. */
  658. Lining.prototype._getRange = function () {
  659. return this.win.getSelection().getRangeAt(0);
  660. };
  661. /**
  662. * adjust line
  663. * @param {Element} line
  664. * @param {Selection} s
  665. */
  666. Lining.prototype._adjustLine = function (line, s) {
  667. var r = this._setCursor(line, 0, s);
  668. s.modify('extend', 'forward', 'character');
  669. s.modify('extend', 'forward', 'lineboundary');
  670. r = s.getRangeAt(0);
  671. this._update(r);
  672. if (line !== this._end && line.contains(this._end)) {
  673. // split text node
  674. this._adjustTextBoundary();
  675. // append rest of nodes after line
  676. // split node
  677. var tmp = util.adjustOrSplitNode(line, this._end, this._endOffset);
  678. this._end = tmp[0];
  679. this._endOffset = tmp[1];
  680. }
  681. // append rest of nodes after line
  682. var removed = util.removeChildren(this._end, this._endOffset);
  683. var parent = this._end.parentNode;
  684. var next = this._end.nextSibling;
  685. while (removed.length) {
  686. parent.insertBefore(removed.pop(), next);
  687. }
  688. };
  689. /**
  690. * create line.
  691. * @param {Selection} s
  692. */
  693. Lining.prototype._createLine = function (s) {
  694. var line = doc.createElement('text-line');
  695. line.className = this.lineClassName;
  696. line.setAttribute('index', ++this.count);
  697. try {
  698. this._getRange().surroundContents(line);
  699. }
  700. catch (e) {
  701. this.surroundContents(line);
  702. }
  703. if (!this._currentLine) {
  704. line.setAttribute('first', '');
  705. }
  706. this._currentLine = line;
  707. if (!line.previousSibling
  708. || util.findContentSibling(line, 'backward')[0]) {
  709. line.setAttribute('first-in-element', '');
  710. }
  711. this._adjustLine(line, s);
  712. };
  713. /**
  714. * adjust text boundary into node boundary.
  715. */
  716. Lining.prototype._adjustTextBoundary = function () {
  717. if (this._ancestor.nodeType === 3) {
  718. this._ancestor = this._ancestor.parentNode;
  719. }
  720. var offsetAdjust = 0;
  721. var start = this._start;
  722. var startOffset = this._startOffset;
  723. var newStart = start;
  724. if (start.nodeType === 3) {
  725. if (startOffset !== 0 && startOffset !== start.nodeValue.length) {
  726. newStart = start.splitText(startOffset);
  727. if (this._start === this._end) {
  728. offsetAdjust = this._start.nodeValue.length;
  729. }
  730. }
  731. this._start = newStart.parentNode;
  732. this._startOffset = util.getNodeOffset(newStart);
  733. }
  734. var end = offsetAdjust ? this._end.nextSibling : this._end;
  735. var endOffset = this._endOffset - offsetAdjust;
  736. if (end.nodeType === 3) {
  737. if (endOffset !== 0 && endOffset !== end.nodeValue.length) {
  738. end.splitText(endOffset);
  739. }
  740. this._end = end.parentNode;
  741. this._endOffset = util.getNodeOffset(end) + 1;
  742. }
  743. };
  744. /**
  745. * adjust or split node
  746. *
  747. * ancestor = p
  748. * <p><span>aaa<b>b|bb</b>ccc</span></p>
  749. * ==>
  750. * <p><span>aaa<b>b</b></span>|<span><b>bb</b>ccc</span></p>
  751. *
  752. * @param {boolean} isStart
  753. */
  754. Lining.prototype._adjustOrSplitNode = function (isStart) {
  755. var commonAncestor = this._ancestor;
  756. var node;
  757. var offset;
  758. if (isStart) {
  759. node = this._start;
  760. offset = this._startOffset;
  761. }
  762. else {
  763. node = this._end;
  764. offset = this._endOffset;
  765. }
  766. var r = util.adjustOrSplitNode(commonAncestor, node, offset);
  767. if (isStart) {
  768. this._start = r[0];
  769. this._startOffset = r[1];
  770. }
  771. else {
  772. this._end = r[0];
  773. this._endOffset = r[1];
  774. }
  775. };
  776. /**
  777. * adjust boundary
  778. *
  779. * ancestor = p
  780. * start = b.firstChild
  781. * startOffset = 1
  782. * end = p.lastChild
  783. * endOffset = 1
  784. * <p>111<span>aaa<b>b[bb</b>ccc</span>2]22</p>
  785. * ==>
  786. * <p>111<span>aaa<b>b</b></span><line><span><b>bb</b>ccc</span>2</line>22</p>
  787. * @param {Element} line
  788. */
  789. Lining.prototype.surroundContents = function (line) {
  790. this._adjustTextBoundary();
  791. this._adjustOrSplitNode(true);
  792. this._adjustOrSplitNode(false);
  793. // if come to this step
  794. // then this._ancestor === this._start === this._end
  795. var removed = util.removeChildren(this._ancestor, this._startOffset, this._endOffset);
  796. util.appendChildren(line, removed);
  797. var i = this._startOffset;
  798. this._ancestor.insertBefore(line, this._ancestor.childNodes[i]);
  799. };
  800. /**
  801. * lining.
  802. *
  803. * @param {string|Element} element id or element
  804. * @param {Object=} opt_option
  805. */
  806. var lining = win.lining = function (element, opt_option) {
  807. return new Lining(
  808. typeof element === 'string' ?
  809. doc.getElementById(element) :
  810. element,
  811. opt_option
  812. ).init();
  813. };
  814. lining.Lining = Lining;
  815. lining.util = util;
  816. win.addEventListener('load', function () {
  817. var elements = doc.querySelectorAll('[data-lining]');
  818. var e;
  819. for (var i = 0, l = elements.length; i < l; i++) {
  820. e = elements[i];
  821. lining(e);
  822. }
  823. }, false);
  824. })(window, document);