var BCLSVJS = (function (window, document, docData, hljs) { 'use strict'; var title = document.getElementsByTagName('title')[0], // data structures classes = {thisClass: [], parentClass: []}, doc_class, docsPath = 'https://github.com/videojs/video.js/blob/master/src/js/', doc_data = {}, // doc path as an array path = document.location.pathname.split('/'), // paths classFilePath, parentClassFilePath, // elements mainContent, main, doc_body = document.getElementsByTagName('body')[0], // functions isDefined, isItemInArray, copyObj, findObjectInArray, findObjectsInArray, getSubArray, sortArray, createEl, bclslog, findClassObjects, addHeaderContent, addIndex, addMembersContent, addText, highlightCode, init; /** * Logging function - safe for IE * * @param {string} context - description of the data * @param {*} message - the data to be logged by the console */ bclslog = function (context, message) { if (window['console'] && console['log']) { console.log(context, message); } }; /** * tests for all the ways a variable might be undefined or not have a value * * @param {*} x the variable to test * @return {Boolean} true if variable is defined and has a value */ isDefined = function (x) { if (x === '' || x === null || x === undefined || x === NaN) { return false; } return true; }; /** * determines whether specified item is in an array * * @param {array} array to check * @param {string} item to check for * @return {boolean} true if item is in the array, else false */ isItemInArray = function (arr, item) { var i, iMax = arr.length; for (i = 0; i < iMax; i++) { if (arr[i] === item) { return true; } } return false; }; /** * get a copy of (rather than reference to) an object * * @param {object} obj - the object you want a copy * @return {object} the copy */ copyObj = function (obj) { if (isDefined(obj)) { return JSON.parse(JSON.stringify(obj)); } bclslog('no obj passed'); }; /** * find index of an object in array of objects * based on some property value * generally useful for finding a unique object * * @param {array} targetArray - array to search * @param {string} objProperty - object property to search * @param {string|number} value - value of the property to search for * @return {integer} index of first instance if found, otherwise returns -1 */ findObjectInArray = function (targetArray, objProperty, value) { var i, totalItems = targetArray.length, objFound = false; for (i = 0; i < totalItems; i++) { if (targetArray[i][objProperty] === value) { objFound = true; return i; } } if (objFound === false) { return -1; } }; /** * find indexes of a set of object in array of objects * based on some property value * generally useful for finding several objects * * @param {array} targetArray - array to search * @param {string} objProperty - object property to search * @param {string|number} value - value of the property to search for * @return {array} array of indexes for matching objects */ findObjectsInArray = function (targetArray, objProperty, value) { var i, totalItems = targetArray.length, newArr = []; for (i = 0; i < totalItems; i++) { if (targetArray[i][objProperty] === value) { newArr.push(i); } } return newArr; }; /** * get a subset of objects in array of objects * based on some property value * * @param {array} targetArray - array to search * @param {string} objProperty - object property to search * @param {string|number} value - value of the property to search for * @return {array} array of objects with matching property value */ getSubArray = function (targetArray, objProperty, value) { var i, totalItems = targetArray.length, idxArr = []; for (i = 0; i < totalItems; i++) { if (targetArray[i][objProperty] === value) { idxArr.push(targetArray[i]); } } return idxArr; }; /** * sort an array of objects based on an object property * * @param {array} targetArray - array to sort * @param {string} objProperty - property whose value to sort on * @return {array} the sorted array */ sortArray = function (targetArray, objProperty) { targetArray.sort(function (a, b) { var propA = a[objProperty].toLowerCase(), propB = b[objProperty].toLowerCase(); // sort ascending; reverse propA and propB to sort descending if (propA < propB) { return -1; } else if (propA > propB) { return 1; } return 0; }); return targetArray; }; /** * create an element * * @param {string} type - the element type * @param {object} attributes - attributes to add to the element * @return {object} the HTML element */ createEl = function (type, attributes) { var el; if (isDefined(type)) { el = document.createElement(type); if (isDefined(attributes)) { var attr; for (attr in attributes) { el.setAttribute(attr, attributes[attr]); } } return el; } }; /** * creates a text node and adds it to an element * @param {object|node} el - the node (element) to add the text to * @param {string} str - the text to add */ addText = function (el, str) { var text = document.createTextNode(str); el.appendChild(text); }; /** * finds the objects in the doc data for a fileName * * @param {array} arr - the array of objects to search * @param {string} filename - the filename to look for in the meta object * @return {array} - array of the objects found */ findClassObjects = function (arr, filename) { var i, totalItems = arr.length, newArr = []; for (i = 0; i < totalItems; i++) { if (isDefined(arr[i].meta)) { if (arr[i].meta.filename === filename) { newArr.push(arr[i]); } } } return newArr; }; /** * add the class header content */ addHeaderContent = function () { var topSection = createEl('section', {id: 'top', class: 'section'}), headerData = doc_data.thisClass.headerInfo, header = createEl('h1'), extendsNode = createEl('p'), extendsLink, definedIn = createEl('p'), definedInLink = createEl('a', {href: docsPath + classFilePath + '#L' + headerData.meta.lineno}), description = createEl('div', {style: 'border:none', id: 'classDescription'}), descriptionEl, constructorHeader = createEl('h3'), constructorPre = createEl('pre'), constructorCode = createEl('code'), constructorParamsHeader = createEl('h4'), constructorParams = [], text; // add main content wrapper doc_body.appendChild(mainContent); main = document.getElementById('main'); // add elements topSection.appendChild(header); topSection.appendChild(description); // source file topSection.appendChild(definedIn); addText(definedIn, 'DEFINED IN: '); definedIn.appendChild(definedInLink); addText(definedInLink, headerData.meta.filename + ' line number: ' + headerData.meta.lineno); mainContent.appendChild(topSection); // page header addText(header, headerData.name); // parent info if this class extends another if (isDefined(doc_data.parentClasses)) { topSection.appendChild(extendsNode); addText(extendsNode, 'EXTENDS: '); extendsLink = createEl('a', {href: parentClassFilePath + doc_data.parentClasses[0].headerInfo.meta.filename}); extendsNode.appendChild(extendsLink); addText(extendsLink, doc_data.parentClasses[0].headerInfo.meta.filename); } // constructor info - don't add for video.js if (doc_data.thisClass.headerInfo.name !== 'videojs') { topSection.appendChild(constructorHeader); topSection.appendChild(constructorPre); constructorPre.appendChild(constructorCode); // create the constructor info addText(constructorHeader, 'Constructor'); // get constructor params if any if (isDefined(headerData.params)) { var paramTableHeaders = ['name', 'Type', 'Required', 'Description'], paramTable = createEl('table'), paramThead = createEl('thead'), paramTbody = createEl('tbody'), paramTheadRow = createEl('tr'), paramTbodyRow = createEl('tr'), paramTH, paramTD, k, kMax; addText(constructorParamsHeader, 'Parameters'); paramTable.appendChild(paramThead); paramTable.appendChild(paramTbody); paramThead.appendChild(paramTheadRow); // set the table headers kMax = paramTableHeaders.length; for (k = 0; k < kMax; k++) { paramTH = createEl('th'); paramTheadRow.appendChild(paramTH); addText(paramTH, paramTableHeaders[k]); } // now the table info kMax = headerData.params.length; for (k = 0; k < kMax; k++) { paramTbodyRow = createEl('tr'); paramTbody.appendChild(paramTbodyRow); paramTD = createEl('td'); addText(paramTD, headerData.params[k].name); paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); addText(paramTD, headerData.params[k].type.names.join('|')); paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); if (headerData.params[k].optional) { text = document.createTextNode('no'); constructorParams.push('[' + headerData.params[k].name + ']'); } else { text = document.createTextNode('yes'); constructorParams.push(headerData.params[k].name); } paramTD.appendChild(text); if (isDefined(headerData.params[k].description)) { paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); addText(paramTD, headerData.params[k].description.slice(3, headerData.params[k].description.indexOf('

'))); paramTbodyRow.appendChild(paramTD); } paramTbody.appendChild(paramTbodyRow); } topSection.appendChild(constructorParamsHeader); topSection.appendChild(paramTable); } } // add constructor params to signature if any if (constructorParams.length > 0) { text = document.createTextNode(headerData.name + '( ' + constructorParams.join(',') + ' )'); } else { text = document.createTextNode(headerData.name + '()'); } constructorCode.appendChild(text); descriptionEl = document.getElementById('classDescription'); descriptionEl.innerHTML = headerData.description; }; /** * add the side nav */ addIndex = function () { var section = createEl('section', {id: 'index', class: 'side-nav'}), navHeader = createEl('h2', {class: 'sideNavHeader'}), navHeaderLink = createEl('a', {href: 'index.html'}), memberIndex = createEl('div', {id: 'memberIndex', class: 'member-index'}), thisMember, addedMembers = {}, item, thisParent, parentList, header, listItem, listLink, classHeader, parentHeader, i, iMax, j, jMax, // helper functions classHasMembers = function (member) { if (doc_data.thisClass[member].length > 0) { return true; } return false; }, parentsHaveMembers = function () { if (doc_data.parentClasses.length > 0) { for (i = 0; i < doc_data.parentClasses.length; i++) { if (doc_data.parentClasses[i][thisMember].length > 0) { return true; } } return false; } }, makeList = function (classArr, parentArr, member, list) { thisMember = member.toLowerCase(); if (classArr.length > 0 || (isDefined(doc_data.parentClass) && parentArr.length > 0)) { // add member list header if (classHasMembers(thisMember) || parentsHaveMembers(thisMember)) { header = createEl('h3'); addText(header, doc_data.thisClass.headerInfo.name + ' ' + member); } else { return; } if (classHasMembers(thisMember)) { classHeader = createEl('h4'); addText(classHeader, 'Class ' + member); memberIndex.appendChild(header); memberIndex.appendChild(classHeader); // add the list & items list = createEl('ul', {id: list}); memberIndex.appendChild(list); iMax = classArr.length; for (i = 0; i < iMax; i++) { item = classArr[i].name; if (!isItemInArray(addedMembers[member], item)) { // keep track of added members to remove overridden ones addedMembers[member].push(item); listItem = createEl('li'); listLink = createEl('a', {href: '#' + member + item}); addText(listLink, item); listItem.appendChild(listLink); list.appendChild(listItem); } } } // add inherited items if any if (isDefined(parentArr) && parentArr.length > 0) { jMax = parentArr.length; for (j = 0; j < jMax; j++) { thisParent = parentArr[j]; if (thisParent[thisMember].length > 0) { parentHeader = createEl('h4'); addText(parentHeader, 'Inherited ' + member + ' from ' + thisParent.headerInfo.name); memberIndex.appendChild(parentHeader); parentList = createEl('ul'); memberIndex.appendChild(parentList); iMax = thisParent[thisMember].length; for (i = 0; i < iMax; i++) { item = thisParent[thisMember][i].name; if (!isItemInArray(addedMembers[member], item)) { addedMembers[member].push(item); listItem = createEl('li'); listLink = createEl('a', {href: '#' + member + item}); listItem.appendChild(listLink); addText(listLink, item); parentList.appendChild(listItem); } } } } } } }; // data structure to track members already added addedMembers.Methods = []; addedMembers.Properties = []; addedMembers.Events = []; navHeader.appendChild(navHeaderLink); addText(navHeaderLink, 'API Index'); // add parent class members if any if (isDefined(doc_data.parentClasses)) { makeList(doc_data.thisClass.properties, doc_data.parentClasses, 'Properties', 'propertiesList'); makeList(doc_data.thisClass.methods, doc_data.parentClasses, 'Methods', 'methodsList'); makeList(doc_data.thisClass.events, doc_data.parentClasses, 'Events', 'eventsList'); } else { makeList(doc_data.thisClass.properties, [], 'Properties', 'propertiesList'); makeList(doc_data.thisClass.methods, [], 'Methods', 'methodsList'); makeList(doc_data.thisClass.events, [], 'Events', 'eventsList'); } section.appendChild(navHeader); section.appendChild(memberIndex); doc_body.appendChild(section); }; /** * add the member content */ addMembersContent = function () { var members = [{name: 'Properties', data: 'properties'}, {name: 'Methods', data: 'methods'}, {name: 'Events', data: 'events'}], member, addedMembers = {}, section, header, headerSuffix, item, itemWrapper, itemHeader, itemHeaderStr, itemParams = [], itemParamsHeader, itemDescription, itemDescriptionEl, itemFooter, itemFooterLink, itemFooterContent, paramTable, paramThead, paramTbody, paramTheadRow, paramTbodyRow, paramTH, paramTD, paramTableHeaders = ['name', 'Type', 'Required', 'Description'], text, i, iMax, j, jMax, k, kMax, m, mMax, topLinkP, topLinkA, // helper function createMemberItem = function (classData, member) { bclslog('member', member); // create the class member items jMax = classData[member.data].length; for (j = 0; j < jMax; j++) { item = classData[member.data][j]; if (!isItemInArray(addedMembers[member.name], item.name)) { addedMembers[member.name].push(item.name); itemWrapper = createEl('div', {id: member.name + item.name}); section.appendChild(itemWrapper); itemHeader = createEl('h3', {id: item.name + 'Header'}); itemHeaderStr = item.name; itemWrapper.appendChild(itemHeader); itemDescription = createEl('div', {id: item.name + 'Description', class: 'description'}); itemWrapper.appendChild(itemDescription); itemFooter = createEl('p', {class: 'vjs-only'}); itemFooterLink = createEl('a', {href: docsPath + item.meta.filename + '#L' + item.meta.lineno}); itemFooterContent = createEl('em', {id: item.name + 'Footer'}); itemFooter.appendChild(itemFooterContent); topLinkP = createEl('p'); topLinkA = createEl('a', {href: '#top'}); addText(topLinkA, '[back to top]'); topLinkP.appendChild(topLinkA); // for methods only handle params if any if (member.name === 'Methods' && isDefined(item.params)) { itemParams = []; itemParamsHeader = createEl('h4'); addText(itemParamsHeader, 'Parameters'); paramTable = createEl('table'); paramThead = createEl('thead'); paramTbody = createEl('tbody'); paramTable.appendChild(paramThead); paramTable.appendChild(paramTbody); paramTheadRow = createEl('tr'); paramThead.appendChild(paramTheadRow); // set the table headers kMax = paramTableHeaders.length; for (k = 0; k < kMax; k++) { paramTH = createEl('th'); paramTheadRow.appendChild(paramTH); addText(paramTH, paramTableHeaders[k]); } // now the table info kMax = item.params.length; for (k = 0; k < kMax; k++) { paramTbodyRow = createEl('tr'); paramTbody.appendChild(paramTbodyRow); paramTD = createEl('td'); addText(paramTD, item.params[k].name); paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); addText(paramTD, item.params[k].type.names.join('|')); paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); if (item.params[k].optional) { text = document.createTextNode('no'); itemParams.push('[' + item.params[k].name + ']'); } else { text = document.createTextNode('yes'); itemParams.push(item.params[k].name); } paramTD.appendChild(text); if (isDefined(item.params[k].description)) { paramTbodyRow.appendChild(paramTD); paramTD = createEl('td'); addText(paramTD, item.params[k].description.slice(3, item.params[k].description.indexOf('

'))); paramTbodyRow.appendChild(paramTD); } paramTbody.appendChild(paramTbodyRow); } itemHeaderStr += '( ' + itemParams.join(', ') + ' )'; if (item.scope === 'static') { itemHeaderStr = 'static ' + itemHeaderStr; } itemWrapper.appendChild(itemParamsHeader); itemWrapper.appendChild(paramTable); } else if (member.name === 'Methods') { itemHeaderStr += '()'; } itemWrapper.appendChild(itemFooter); itemWrapper.appendChild(topLinkP); addText(itemHeader, itemHeaderStr); if (isDefined(item.deprecated)) { headerSuffix = createEl('em', {class: 'deprecated'}); text = document.createTextNode(); addText(headerSuffix, ' (deprecated)'); itemHeader.appendChild(headerSuffix); } itemDescriptionEl = document.getElementById(item.name + 'Description'); itemDescriptionEl.innerHTML = item.description; addText(itemFooterContent, 'Defined in '); itemFooterContent.appendChild(itemFooterLink); addText(itemFooterLink, 'src/js/' + item.meta.filename + ' line number: ' + item.meta.lineno); } } }; // data structure to track members already added addedMembers.Methods = []; addedMembers.Properties = []; addedMembers.Events = []; iMax = members.length; for (i = 0; i < iMax; i++) { member = members[i]; if (doc_data.thisClass[member.data].length > 0) { // create the member section section = createEl('section', {id: member.name.toLowerCase(), class: 'section'}); main.appendChild(section); header = createEl('h2'); addText(header, member.name); section.appendChild(header); // create the member items createMemberItem(doc_data.thisClass, member); if (isDefined(doc_data.parentClasses)) { mMax = doc_data.parentClasses.length; for (m = 0; m < mMax; m++) { if (doc_data.parentClasses[m][member.data].length > 0) { createMemberItem(doc_data.parentClasses[m], member); } } } } } }; /** * use hljs to highlight the syntax in code blocks */ highlightCode = function () { var codeBlocks = document.querySelectorAll('pre code'), i, iMax; if (isDefined(codeBlocks)) { iMax = codeBlocks.length; for (i = 0; i < iMax; i++) { hljs.highlightBlock(codeBlocks[i]); } } }; /** * init gets things going */ init = function () { var fileName, srcFileName, parent_class_name, privateItems = [], idx, text, j, parentCounter = 0, // helper function to get the chain of parent classes getAncestorData = function (parent_class) { // get data objects for the class classes.parentClasses[parentCounter] = findClassObjects(docData, parent_class + '.js'); // check to see if there are any parent class items if (classes.parentClasses[parentCounter].length > 0) { doc_data.parentClasses[parentCounter] = {}; // get parent header info idx = findObjectInArray(classes.parentClasses[parentCounter], 'kind', 'class'); doc_data.parentClasses[parentCounter].headerInfo = copyObj(classes.parentClasses[parentCounter][idx]); // get parent class path idx = findObjectInArray(classes.parentClasses[parentCounter], 'kind', 'file'); if (idx > -1) { parentClassFilePath = classes.parentClasses[parentCounter][idx].name; } else { parentClassFilePath = doc_data.parentClasses[parentCounter].headerInfo.meta.filename; } // remove any private items privateItems = findObjectsInArray(classes.parentClasses[parentCounter], 'access', 'private'); j = privateItems.length; while (j > 0) { j--; classes.parentClasses[parentCounter].splice(privateItems[j], 1); } // now get the member arrays doc_data.parentClasses[parentCounter].methods = getSubArray(classes.parentClasses[parentCounter], 'kind', 'function'); doc_data.parentClasses[parentCounter].methods = sortArray(doc_data.parentClasses[parentCounter].methods, 'name'); doc_data.parentClasses[parentCounter].events = getSubArray(classes.parentClasses[parentCounter], 'kind', 'event'); doc_data.parentClasses[parentCounter].events = sortArray(doc_data.parentClasses[parentCounter].events, 'name'); doc_data.parentClasses[parentCounter].properties = getSubArray(classes.parentClasses[parentCounter], 'kind', 'property'); doc_data.parentClasses[parentCounter].properties = sortArray(doc_data.parentClasses[parentCounter].properties, 'name'); } // get parent class, if any, and anything it inherits if (isDefined(doc_data.parentClasses[parentCounter].headerInfo.augments)) { idx = findObjectInArray(docData, 'name', doc_data.parentClasses[parentCounter].headerInfo.augments[0]); parent_class_name = docData[idx].meta.filename.replace('.js', ''); parentCounter++; getAncestorData(parent_class_name); } }; // content wrapper mainContent = createEl('div', {id: 'main', class: 'section'}); // get the class name from the file name fileName = path[path.length - 1]; doc_class = fileName.substring(0, fileName.indexOf('.')); srcFileName = doc_class + '.js'; bclslog('srcFileName', srcFileName); // video.js is a special case - all others will be the same if (srcFileName === 'video.js') { // for doc purposes, treat video like a class, though it's not // get the data objects for this class classes.thisClass = findClassObjects(docData, srcFileName); bclslog('classes', classes); idx = findObjectInArray(classes.thisClass, 'name', 'videojs'); doc_data.thisClass = {}; // get the class overview object doc_data.thisClass.headerInfo = copyObj(classes.thisClass[idx]); doc_data.thisClass.headerInfo.name = 'videojs'; idx = findObjectInArray(classes.thisClass, 'kind', 'file'); if (idx > -1) { classFilePath = classes.thisClass[idx].name; } else { classFilePath = doc_data.thisClass.headerInfo.meta.filename; } // set the doc title text = document.createTextNode(doc_data.thisClass.headerInfo.name); title.appendChild(text); // remove any private items privateItems = findObjectsInArray(classes.thisClass, 'access', 'private'); j = privateItems.length; while (j > 0) { j--; classes.thisClass.splice(privateItems[j], 1); } // now get the member arrays doc_data.thisClass.methods = getSubArray(classes.thisClass, 'kind', 'function'); doc_data.thisClass.methods = sortArray(doc_data.thisClass.methods, 'name'); doc_data.thisClass.events = getSubArray(classes.thisClass, 'kind', 'event'); doc_data.thisClass.events = sortArray(doc_data.thisClass.events, 'name'); doc_data.thisClass.properties = getSubArray(classes.thisClass, 'kind', 'property'); doc_data.thisClass.properties = sortArray(doc_data.thisClass.properties, 'name'); bclslog('thisClass', doc_data.thisClass); } else { // get the data objects for this class classes.thisClass = findClassObjects(docData, srcFileName); bclslog('classes', classes); idx = findObjectInArray(classes.thisClass, 'kind', 'class'); doc_data.thisClass = {}; doc_data.thisClass.headerInfo = copyObj(classes.thisClass[idx]); // get the file path from @file object idx = findObjectInArray(classes.thisClass, 'kind', 'file'); if (idx > -1) { classFilePath = classes.thisClass[idx].name; } else { classFilePath = doc_data.thisClass.headerInfo.meta.filename; } // set the doc title text = document.createTextNode(doc_data.thisClass.headerInfo.name); title.appendChild(text); // remove any private items privateItems = findObjectsInArray(classes.thisClass, 'access', 'private'); j = privateItems.length; while (j > 0) { j--; classes.thisClass.splice(privateItems[j], 1); } // now get the member arrays doc_data.thisClass.methods = getSubArray(classes.thisClass, 'kind', 'function'); doc_data.thisClass.methods = sortArray(doc_data.thisClass.methods, 'name'); doc_data.thisClass.events = getSubArray(classes.thisClass, 'kind', 'event'); doc_data.thisClass.events = sortArray(doc_data.thisClass.events, 'name'); doc_data.thisClass.properties = getSubArray(classes.thisClass, 'kind', 'property'); doc_data.thisClass.properties = sortArray(doc_data.thisClass.properties, 'name'); bclslog('thisClass', doc_data.thisClass); // get parent class, if any, and anything it inherits if (isDefined(doc_data.thisClass.headerInfo.augments)) { doc_data.parentClass = {}; doc_data.parentClasses = []; classes.parentClasses = []; idx = findObjectInArray(docData, 'name', doc_data.thisClass.headerInfo.augments[0]); parent_class_name = docData[idx].meta.filename.replace('.js', ''); getAncestorData(parent_class_name); } bclslog('parentClasses', doc_data.parentClasses); } // now we're ready to roll addIndex(); addHeaderContent(); addMembersContent(); highlightCode(); }; // initialize init(); return { }; })(window, document, docData, hljs);