PageRenderTime 29ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/files/cutter.js/1.0/cutter.developer.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 546 lines | 281 code | 10 blank | 255 comment | 60 complexity | cc99ee09931b20e405044b1e7f7ff11f MD5 | raw file
  1. (function (win, doc) {
  2. 'use strict';
  3. var CutterClasses = null,
  4. CutterTexts = null,
  5. Cutter = null;
  6. /**
  7. * CutterClasses is the config singleton for classes used in Cutter
  8. * @class CutterClasses
  9. * @constructor
  10. * @author Tomas Corral Casas
  11. * @version 1.0
  12. * @type Object
  13. */
  14. CutterClasses = function () {
  15. this.more = "more";
  16. };
  17. /**
  18. * CutterTexts is the config singleton for texts used in Cutter
  19. * @class CutterTexts
  20. * @constructor
  21. * @author Tomas Corral Casas
  22. * @version 1.0
  23. * @type Object
  24. */
  25. CutterTexts = function () {
  26. this.more = "View more";
  27. };
  28. /**
  29. * Cutter is a class that allows HTML code to cut a number of words contained in the nodes, keeping intact the HTML markup.
  30. * @author Tomas Corral Casas
  31. * @version 1.0
  32. * @class Cutter
  33. * @constructor
  34. * @type Object
  35. */
  36. Cutter = function () {
  37. /**
  38. * oApplyTo is the Dom object where we want to use the cutter.
  39. * @member Cutter.prototype
  40. * @author Tomas Corral Casas
  41. * @type Object
  42. */
  43. this.oApplyTo = null;
  44. /**
  45. * oBackupApplyTo is the clone from Dom object to get it when showing the content.
  46. * @member Cutter.prototype
  47. * @author Tomas Corral Casas
  48. * @type Object
  49. */
  50. this.oBackupApplyTo = null;
  51. /**
  52. * oTarget is the Dom object where to put the cutted code
  53. * @member Cutter.prototype
  54. * @author Tomas Corral Casas
  55. * @type Object
  56. */
  57. this.oTarget = null;
  58. /**
  59. * oClasses is the config singleton for classes used in Cutter
  60. * @member Cutter.prototype
  61. * @author Tomas Corral Casas
  62. * @type Object
  63. */
  64. this.oClasses = new CutterClasses();
  65. /**
  66. * oTexts is the config singleton for texts used in Cutter
  67. * @member Cutter.prototype
  68. * @author Tomas Corral Casas
  69. * @type Object
  70. */
  71. this.oTexts = new CutterTexts();
  72. /**
  73. * nWords is the number of words to Cut
  74. * @member Cutter.prototype
  75. * @author Tomas Corral Casas
  76. * @type Number
  77. */
  78. this.nWords = 0;
  79. /**
  80. * nWordsCounter is the counter of words when finding them in code
  81. * @member Cutter.prototype
  82. * @author Tomas Corral Casas
  83. * @type Number
  84. */
  85. this.nWordsCounter = 0;
  86. /**
  87. * oViewMore is a reference to the "see more" link.
  88. * @member Cutter.prototype
  89. * @author Tomas Corral Casas
  90. * @type Object
  91. */
  92. this.oViewMore = null;
  93. /**
  94. * oSerialized is the JSON object where Cutter serializes all the DOM objects inside the oApplyTo Dom element
  95. * @member Cutter.prototype
  96. * @author Tomas Corral Casas
  97. * @type Object
  98. */
  99. this.oSerialized = {};
  100. /**
  101. * oDocumentFragment is the DocumentFragment where the Dom elements are inserted before insert on Target
  102. * @member Cutter.prototype
  103. * @author Tomas Corral Casas
  104. * @type Object
  105. */
  106. this.oDocumentFragment = doc.createDocumentFragment();
  107. /**
  108. * bTest is a property to now if you want to test the Cutter class
  109. * This is used to change the type of id for each element.
  110. * false by default.
  111. * @member Cutter.prototype
  112. * @author Tomas Corral Casas
  113. * @type Boolean
  114. */
  115. this.bTest = false;
  116. /**
  117. * nIdTest is the property for testing that will save the order for id.
  118. * 0 by default.
  119. * @member Cutter.prototype
  120. * @author Tomas Corral Casas
  121. * @type Number
  122. */
  123. this.nIdTest = 0;
  124. /**
  125. * bNeedViewMore is a property that will check it it's necessary to add the link to view more or not
  126. * It checks if its necessary if for some reason the content is cutted.
  127. * false by default.
  128. * @member Cutter.prototype
  129. * @author Tomas Corral Casas
  130. * @type Boolean
  131. */
  132. this.bNeedViewMore = false;
  133. /**
  134. * bNotViewMore is a property that could be setted by the user to add or not the link to view more content if needed.
  135. * false by default.
  136. * @member Cutter.prototype
  137. * @author Tomas Corral Casas
  138. * @type Boolean
  139. */
  140. this.bNotViewMore = false;
  141. };
  142. /**
  143. * applyTo is the method that sets the Dom object where to apply the cutter
  144. * @member Cutter.prototype
  145. * @author Tomas Corral Casas
  146. * @param {object} oApplyTo This is the Dom element
  147. * @return the instance of the Cutter
  148. * @type Object
  149. */
  150. Cutter.prototype.applyTo = function (oApplyTo) {
  151. if (!oApplyTo) {
  152. return this;
  153. }
  154. this.oApplyTo = oApplyTo;
  155. this.oBackupApplyTo = oApplyTo.cloneNode(true);
  156. return this;
  157. };
  158. /**
  159. * setTarget is the method that sets the Dom object where to put the cutted code
  160. * @member Cutter.prototype
  161. * @author Tomas Corral Casas
  162. * @param {object} oTarget This is the Dom element
  163. * @return the instance of the Cutter
  164. * @type Object
  165. */
  166. Cutter.prototype.setTarget = function (oTarget) {
  167. if (!oTarget) {
  168. return this;
  169. }
  170. this.oTarget = oTarget;
  171. return this;
  172. };
  173. /**
  174. * setClasses is the method that sets the config singleton of Classes used in Cutter
  175. * @member Cutter.prototype
  176. * @author Tomas Corral Casas
  177. * @param {object} oClasses This is the singleton config
  178. * @return the instance of the Cutter
  179. * @type Object
  180. */
  181. Cutter.prototype.setClasses = function (oClasses) {
  182. if (!oClasses) {
  183. return this;
  184. }
  185. this.oClasses = oClasses;
  186. return this;
  187. };
  188. /**
  189. * setTexts is the method that sets the config singleton of Texts used in Cutter
  190. * @member Cutter.prototype
  191. * @author Tomas Corral Casas
  192. * @param {object} oTexts This is the singleton config
  193. * @return the instance of the Cutter
  194. * @type Object
  195. */
  196. Cutter.prototype.setTexts = function (oTexts) {
  197. if (!oTexts) {
  198. return this;
  199. }
  200. this.oTexts = oTexts;
  201. return this;
  202. };
  203. /**
  204. * setWords is the method used to set the max number of words before cut the code.
  205. * @member Cutter.prototype
  206. * @author Tomas Corral Casas
  207. * @param {number} nWords This is the number of words to see.
  208. * @return the instance of the Cutter
  209. * @type Object
  210. */
  211. Cutter.prototype.setWords = function (nWords) {
  212. if (!nWords) {
  213. return this;
  214. }
  215. this.nWords = nWords - 1;
  216. return this;
  217. };
  218. /**
  219. * trim is an utilities method used to keep out all the spaces before or after the sentence
  220. * @member Cutter.prototype
  221. * @author Tomas Corral Casas
  222. * @param {string} sString This is the text to be trimmed
  223. * @private
  224. * @return the trimmed string
  225. * @type String
  226. */
  227. Cutter.prototype.trim = function (sString) {
  228. return sString.replace(/^\s+/g, '').replace(/\s+$/g, '');
  229. };
  230. /**
  231. * countWords is an utilities method used to count the words in a String
  232. * @member Cutter.prototype
  233. * @author Tomas Corral Casas
  234. * @param {string} sText The text where to know how many words are.
  235. * @private
  236. * @return the number of words in the string
  237. * @type Number
  238. */
  239. Cutter.prototype.countWords = function (sText) {
  240. return this.trim(sText).split(" ").length;
  241. };
  242. /**
  243. * getOnlyNumberOfWords is an utilities method used to get a number of words from the string
  244. * @member Cutter.prototype
  245. * @author Tomas Corral Casas
  246. * @param {string} sString The text from which to extract the words
  247. * @param {number} nWords The number of words to get
  248. * @private
  249. * @return the number of words in the string
  250. * @type Number
  251. */
  252. Cutter.prototype.getOnlyNumberOfWords = function (sString, nWords) {
  253. return this.trim(sString).split(" ").splice(0, nWords).join(" ");
  254. };
  255. /**
  256. * createViewMore is the method that creates the link to see all the content again
  257. * @member Cutter.prototype
  258. * @author Tomas Corral Casas
  259. * @private
  260. */
  261. Cutter.prototype.createViewMore = function () {
  262. var oLink = doc.createElement("a");
  263. oLink.className = this.oClasses.more;
  264. oLink.title = this.oTexts.more;
  265. oLink.href = "#";
  266. oLink.innerHTML = this.oTexts.more;
  267. this.oViewMore = oLink;
  268. };
  269. /**
  270. * getFirstElementOfObject is an utilities method used to get the first element in a JSON object
  271. * @member Cutter.prototype
  272. * @author Tomas Corral Casas
  273. * @param {object} oObject The JSON object from which to obtain the first element
  274. * @private
  275. * @return the first element in the JSON object
  276. * @type Object
  277. */
  278. Cutter.prototype.getFirstElementOfObject = function (oObject) {
  279. var oFirstElement = null,
  280. sKey = '';
  281. for (sKey in oObject) {
  282. if (oObject.hasOwnProperty(sKey)) {
  283. oFirstElement = oObject[sKey];
  284. break;
  285. }
  286. }
  287. return oFirstElement;
  288. };
  289. /**
  290. * deserializeObject is an utilities method used to deserialize a JSON object in a Dom element
  291. * @member Cutter.prototype
  292. * @author Tomas Corral Casas
  293. * @param {object} oSerialized The JSON object from which to obtain the Dom element information
  294. * @param {object} oParent The Dom element where to add the new Dom element
  295. * @private
  296. */
  297. Cutter.prototype.deserializeObject = function (oSerialized, oParent) {
  298. var oDom = null,
  299. sKey = '';
  300. if (oSerialized.nodeType === 1) {
  301. oDom = doc.createElement(oSerialized.tagName);
  302. if (typeof oSerialized.attributes !== "undefined") {
  303. for (sKey in oSerialized.attributes) {
  304. if (oSerialized.attributes.hasOwnProperty(sKey)) {
  305. oDom.setAttribute(sKey, oSerialized.attributes[sKey]);
  306. }
  307. }
  308. }
  309. oParent.appendChild(oDom);
  310. } else if (oSerialized.nodeType === 3) {
  311. if (typeof oSerialized.textContent !== "undefined") {
  312. oDom = doc.createTextNode(oSerialized.textContent);
  313. } else {
  314. if (oSerialized.data) {
  315. oDom = doc.createTextNode(oSerialized.data);
  316. } else {
  317. oDom = doc.createTextNode(oSerialized.innerText);
  318. }
  319. }
  320. oParent.appendChild(oDom);
  321. }
  322. if (typeof oSerialized.childNodes !== "undefined") {
  323. this.loopOnDeserialize(oSerialized.childNodes, oDom);
  324. }
  325. };
  326. /**
  327. * loopOnDeserialize is an utilities method used to loop over all the serialized elements
  328. * @member Cutter.prototype
  329. * @author Tomas Corral Casas
  330. * @param {object} oSerializedElements The JSON object on which to run the loop
  331. * @private
  332. */
  333. Cutter.prototype.loopOnDeserialize = function (oSerializedElements, oParent) {
  334. var sKey = '';
  335. for (sKey in oSerializedElements) {
  336. if (oSerializedElements.hasOwnProperty(sKey)) {
  337. this.deserializeObject(oSerializedElements[sKey], oParent);
  338. }
  339. }
  340. };
  341. /**
  342. * deserializeSerializedObject is an utilities method used to deserialize all the Dom elements that where serialized and is where the cut is applied.
  343. * This method is the core of the class.
  344. * @member Cutter.prototype
  345. * @author Tomas Corral Casas
  346. * @param {object} oSerialized The JSON object to deserialize
  347. * @param {object} oParent The DOM object where to put the new finished code.
  348. * @private
  349. */
  350. Cutter.prototype.deserializeSerializedObject = function (oSerialized, oParent) {
  351. var bLoopOnChilds = false,
  352. oLayer = null;
  353. if (typeof oSerialized === "undefined") {
  354. oSerialized = this.getFirstElementOfObject(this.oSerialized);
  355. this.oDocumentFragment = doc.createDocumentFragment();
  356. bLoopOnChilds = true;
  357. }
  358. if (typeof oParent === "undefined") {
  359. oLayer = doc.createElement("div");
  360. this.oDocumentFragment.appendChild(oLayer);
  361. oParent = oLayer;
  362. }
  363. this.deserializeObject(oSerialized, oParent);
  364. if (typeof oSerialized.childNodes !== "undefined") {
  365. this.loopOnDeserialize(oSerialized.childNodes, oParent);
  366. }
  367. };
  368. /**
  369. * serializeDomObject is an utilities method used to serialize all the Dom elements in a JSON object
  370. * This method is the brain of the class.
  371. * @member Cutter.prototype
  372. * @author Tomas Corral Casas
  373. * @param {object} oDom The Dom element to serialize
  374. * @param {object} oSerializeObject The JSON object where to serialize the Dom element
  375. * @private
  376. */
  377. Cutter.prototype.serializeDomObject = function (oDom, oSerializeObject) {
  378. var sId = Math.random() * 15412457562,
  379. oSerialized = null,
  380. aAttributes = [],
  381. oAttribute = null,
  382. nAttribute = 0,
  383. nLenAttributes = 0,
  384. nLastWordsCounter = 0,
  385. nChild = 0,
  386. nLenChilds = oDom.childNodes.length;
  387. if (this.bTest) {
  388. sId = "__" + (this.nIdTest += 1) + "__";
  389. }
  390. if (this.nWordsCounter < this.nWords) {
  391. oSerialized = {};
  392. oSerialized.nodeType = oDom.nodeType;
  393. if (typeof oDom.tagName !== "undefined") {
  394. oSerialized.tagName = oDom.tagName.toLowerCase();
  395. }
  396. aAttributes = oDom.attributes;
  397. if (aAttributes) {
  398. oSerialized.attributes = {};
  399. nLenAttributes = aAttributes.length;
  400. for (; nAttribute < nLenAttributes; nAttribute += 1) {
  401. oAttribute = aAttributes[nAttribute];
  402. if (oAttribute.nodeValue) {
  403. oSerialized.attributes[oAttribute.name] = oAttribute.value;
  404. }
  405. }
  406. }
  407. if (oSerialized.nodeType === 3) {
  408. nLastWordsCounter = this.nWordsCounter;
  409. if (typeof oDom.textContent !== "undefined") {
  410. this.nWordsCounter += this.countWords(this.trim(oDom.textContent));
  411. } else {
  412. if (oDom.data) {
  413. this.nWordsCounter += this.countWords(this.trim(oDom.data));
  414. } else {
  415. this.nWordsCounter += this.countWords(this.trim(oDom.innerText));
  416. }
  417. }
  418. if (this.nWordsCounter < this.nWords) {
  419. if (typeof oDom.textContent !== "undefined") {
  420. oSerialized.textContent = oDom.textContent;
  421. } else {
  422. if (oDom.data) {
  423. oSerialized.innerText = oDom.data;
  424. } else {
  425. oSerialized.innerText = oDom.innerText;
  426. }
  427. }
  428. } else {
  429. this.bNeedViewMore = true;
  430. if (nLastWordsCounter < this.nWords && this.nWordsCounter > this.nWords) {
  431. if (typeof oDom.textContent !== "undefined") {
  432. oSerialized.textContent = this.getOnlyNumberOfWords(oDom.textContent, (this.nWords - nLastWordsCounter));
  433. } else {
  434. if (oDom.data) {
  435. oSerialized.innerText = this.getOnlyNumberOfWords(oDom.data, (this.nWords - nLastWordsCounter));
  436. } else {
  437. oSerialized.innerText = this.getOnlyNumberOfWords(oDom.innerText, (this.nWords - nLastWordsCounter));
  438. }
  439. }
  440. } else {
  441. if (doc.body.textContent) {
  442. oSerialized.textContent = "";
  443. } else {
  444. oSerialized.innerText = "";
  445. }
  446. }
  447. }
  448. }
  449. if (oDom.hasChildNodes()) {
  450. oSerialized.childNodes = {};
  451. nChild = 0;
  452. nLenChilds = oDom.childNodes.length;
  453. for (; nChild < nLenChilds; nChild += 1) {
  454. this.serializeDomObject(oDom.childNodes[nChild], oSerialized.childNodes);
  455. }
  456. }
  457. if (typeof oSerializeObject === "undefined") {
  458. this.oSerialized[sId] = oSerialized;
  459. } else {
  460. oSerializeObject[sId] = oSerialized;
  461. }
  462. }
  463. };
  464. Cutter.prototype.addEvent = function (oElement, sType, fpCallback) {
  465. if (oElement.addEventListener) {
  466. oElement.addEventListener(sType, fpCallback, false);
  467. } else if (oElement.attachEvent) {
  468. oElement.attachEvent("on" + sType, fpCallback);
  469. }
  470. };
  471. /**
  472. * setBehaviour is the method that applies the behaviour to the "see more" link to get the full content again when makink click on it
  473. * @member Cutter.prototype
  474. * @author Tomas Corral Casas
  475. * @private
  476. */
  477. Cutter.prototype.setBehaviour = function () {
  478. var self = this;
  479. this.addEvent(this.oViewMore, "click", function () {
  480. self.showAll();
  481. return false;
  482. });
  483. };
  484. /**
  485. * showAll is the method that put the initial content to the target Dom element
  486. * @member Cutter.prototype
  487. * @author Tomas Corral Casas
  488. * @private
  489. */
  490. Cutter.prototype.showAll = function () {
  491. var oTarget = this.oTarget,
  492. oParent = oTarget.parentNode;
  493. oParent.insertBefore(this.oBackupApplyTo, oTarget);
  494. oParent.removeChild(oTarget);
  495. };
  496. /**
  497. * init is the method that makes all the work.
  498. * Serialize the Dom.
  499. * Deserialize the JSON object to Dom elements only with the words that were wanted
  500. * Remove the firstChild in oDocumentFragment because this node is the oApplyTo content.
  501. * Clean the content on oTarget.
  502. * Create the "see more" link
  503. * Append the "see more" link to the oDocumentFragment.
  504. * Insert the oDocumentFragment content in the oTarget element
  505. * At least the behaviour is applied to the link to make possible to get the original content before the cut.
  506. * @member Cutter.prototype
  507. * @author Tomas Corral Casas
  508. */
  509. Cutter.prototype.init = function () {
  510. this.serializeDomObject(this.oApplyTo);
  511. this.deserializeSerializedObject();
  512. var oElement = this.oDocumentFragment.childNodes[0];
  513. oElement.removeChild(this.oDocumentFragment.childNodes[0].childNodes[0]);
  514. this.oTarget.innerHTML = "";
  515. this.createViewMore();
  516. if (this.bNeedViewMore && !this.bNotViewMore) {
  517. oElement.appendChild(doc.createTextNode("..."));
  518. oElement.appendChild(doc.createElement("br"));
  519. oElement.appendChild(this.oViewMore);
  520. this.setBehaviour();
  521. }
  522. this.oTarget.appendChild(this.oDocumentFragment);
  523. };
  524. Cutter.run = function (oApplyTo, oTarget, nWords, oTexts, oClasses) {
  525. var oCutter = new Cutter();
  526. oCutter.applyTo(oApplyTo).setTarget(oTarget).setWords(nWords);
  527. if (typeof oTexts !== "undefined") {
  528. oCutter.setTexts(oTexts);
  529. }
  530. if (typeof oClasses !== "undefined") {
  531. oCutter.setClasses(oClasses);
  532. }
  533. oCutter.init();
  534. };
  535. win.Cutter = Cutter;
  536. }(window, document));