CINXE.COM
collagen
<!DOCTYPE html> <html lang="en"> <head> <!-- begin src-matrix/nested-content/head/global-design-head-site-state.html --> <script> var window = window || {}; window.sq = (function (exports) { 'use strict'; // # General Utility Functions // // ## Debug // Wrap a function or object to see the output in console. // ### Usage // ``` // const reduce = data => (debug({url: data.url})) // ``` // ### Function var debug = function (obj, trace) { if ( trace === void 0 ) trace = false; console.log(obj); if (trace) { console.trace(); } return obj; }; // Decode data from Matrix ^rawurlencode and convert apostrophe to single-quote // Alternative to using base64 for matrix data var cleanString = function (str) { return decodeURIComponent(str).replace(/'/gi, '’'); }; var cleanStringQuotes = function (str) { return str.replace(/%22/gi, '"'); }; // Base64 encoding/decoding // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding function b64EncodeUnicode(str) { // first we use encodeURIComponent to get percent-encoded UTF-8, // then we convert the percent encodings into raw bytes which // can be fed into btoa. return btoa( encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function toSolidBytes(match, p1) { return String.fromCharCode('0x' + p1); }) ); } function b64DecodeUnicode(str) { // Going backwards: from bytestream, to percent-encoding, to original string. return decodeURIComponent( atob(str) .split('') .map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }) .join('') ); } var maybeBase64Decode = function (text) { if (!text) { return ''; } try { return b64DecodeUnicode(text); } catch (e) { return text; } }; //const DIRTY = /&|<|>|"|script|iframe|=|\(|\)|\[|\]/gi; //javascript:alert var DIRTY = /data:text\/html|script|iframe|javascript:|<|>|\(|\)|\[|\]/gi; var clean = function (str) { str = str.replace(DIRTY, ' '); return str.replace(/'/gi, ''').replace(/"/gi, '"'); }; // ## Immutable Copy // Create a new version of an object var copy = function (obj) { return JSON.parse(JSON.stringify(obj)); }; var jsonEncode = function (obj, empty) { if ( empty === void 0 ) empty = {}; var result; try { result = JSON.stringify(obj); } catch (e) { var script = 'script'; if (typeof isV8 !== 'undefined') { print(("<" + script + ">console.error(" + (JSON.stringify(e)) + ")</" + script + ">")); } else { console.error(e); } result = JSON.stringify(empty); } return result; }; var jsonDecode = function (obj, empty) { if ( empty === void 0 ) empty = {}; var result = empty; try { result = JSON.parse(obj); } catch (e) { var script = 'script'; if (typeof isV8 !== 'undefined') { print(("<" + script + ">console.error(" + (JSON.stringify(e)) + ")</" + script + ">")); } else { console.error(e); } } return result; }; var convertMatrixBase64 = function (content) { return b64DecodeUnicode(content) .replace(/'/gi, ''') .replace(/\\\\\\"/gi, "'") .replace(/\\/gi, ''); }; // ## Immutable // Make a new copy of a value if it is an object and not a function var immutable = function (item) { return typeof item.target !== 'undefined' ? item // If is object and not a function then copy the object : typeof item === 'object' && typeof item !== 'function' ? copy(item) : item; }; // ## immutableAll // Create new copies of arguments and return as an array var immutableAll = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return args.map(immutable); }; // ## pipe // Push result through a series of functions // ### Usage // ```js // const __convert = pipe(function1, function2, function3); // const result = __convert(...args); // // function1(...args) -> function2(resultFunction1) -> function3(resultFunction2) -> resultFunction3 // ``` // // ### Function var pipe = function (fn) { var fns = [], len = arguments.length - 1; while ( len-- > 0 ) fns[ len ] = arguments[ len + 1 ]; return function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return fns.reduce(function (acc, fn) { return fn(acc); }, fn.apply(void 0, immutableAll.apply(void 0, args))); }; }; // ## compose // Classic compose function for functional style programming. Results are piped through each function from right to left. // ### Usage // ```js // const result = compose(function3, function2, function1); // // function1(...args) -> function2(resultFunction1) -> function3(resultFunction2) -> resultFunction3 // ``` // // ### Function var compose = function () { var fns = [], len = arguments.length; while ( len-- ) fns[ len ] = arguments[ len ]; return pipe.apply(void 0, fns.reverse()); }; // ## __flatten // Flattens nested arrays into a flat array. // ### Usage // ```js // const result = __flatten([1, [2, [3, 4, [5, 6, 7]]); // // [1, 2, 3, 4, 5, 6, 7] // ``` // // ### Function var __flatten = function (out) { return function (list) { list.forEach(function (item) { if (Array.isArray(item)) { out = __flatten(out)(item); } else { out = out.concat(item); } }); return out; }; }; // ## flatten // Alias for __flatten. See __flatten for details. var flatten = function (nlist) { return __flatten([])(nlist); }; // ## generateUUID // Generates a uuid. // ### Usage // ```js // const uuid = generateUUID(); // // // ``` // // ### Function // ## r // Route helper for hyper app router event listener. // ### Usage // ```js // // When the routes '/' or '/search' is activated in window.location then call the function funnelbackRequest. // app({ // events: { // route: [ // r('/search', funnelbackRequest), // r('/', funnelbackRequest) // ], // }); // ``` // // ### Function // ## htmlDecode // Decode html entities. // ### Usage // ```js // htmlDecode('& < <'); // // "& < <" // ``` // // ### Function var htmlDecode = function (html) { var txt = document.createElement('textarea'); txt.innerHTML = html; return txt.value; }; // ## __replaceParams // Replace a param in a query string // ### Usage // ```js // // window.location.search === '?facet=blue&query=bingo+jones' // const result = __replaceParams(location.pathname + location.search)('query', 'hello+world'); // // /search?facet=blue&query=hello+world // ``` // // ### Function var __replaceParams = function (str) { return function (param, value) { var qsplit = str.split('?'); var query = qsplit[1] || ''; if (query.match(param)) { var querySplit = query.split('&'); var next = true, i = 0, final = querySplit.length; while (next) { var item = querySplit[i]; if (final === i) { next = false; } else if (item.indexOf(param) !== -1) { str = str.replace(item, (param + "=" + value)); next = false; } i++; } return str; } else { var newQstring = param + "=" + value; return query ? str + "" + (str.substr('-1') == '&' ? '' : '&') + newQstring : str + '?' + newQstring; } }; }; // ## getURLParameter // Get the value of a parameter from a query string. // ### Usage // ```js // // location.search == '?query=hello+world' // const result = getURLParameter('query', location.search); // // 'hello+world' // ``` // // ### Function function getUrlParameter(name, url) { if ( url === void 0 ) url = null; name = name .replace(/[\[]/, '\\[') .replace(/[\]]/, '\\]') .replace(/\./gi, '\\.') .replace(/\+/gi, '\\+'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var results = regex.exec(url ? url : location.search); return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); } // ## qparts // Split query param by space /** * Splits the query into words * @param query */ var qparts = function (query) { return query.split(' '); }; // ## highlight // Highlights a word 'qpart' in a string. // ### Usage // ```js // const result = highlight('juice', 'juicer'); // // <strong>juice</strong>r // ``` // // ### Function /** * Highlights a word 'qpart' in a string * @param qpart * @param str */ var __xhighlight = function (queryParts) { return function (strPart) { var keyword = queryParts.find(function (keyword) { return keyword.length > 2 && strPart.match(new RegExp(("(" + keyword + ")"), 'gi')); }); return keyword ? strPart.replace(new RegExp(("(" + keyword + ")"), 'gi'), '<strong>$1</strong>') : strPart; }; }; // ## highlightWords // Highlights all words in the query against matches in the title // ### Usage // ```js // const result = highlightWords('english', 'happy birthday english'); // // happy birthday <strong>english</strong> // ``` // // ### Function /** * Highlights all words in the query against matches in the title * @param query * @param str */ var highlightWords = function (query, str) { if (str) { var highlight = __xhighlight(qparts(query)); return qparts(str) .map(highlight) .join(' '); } else { return ''; } }; // ## slugify // Converts a string into something that can be used in a URI with no spaces and funny characters. // ### Usage // ```js // const result = slugify('hello world'); // // hello-world // ``` // // ### Function /** * @returns {string} */ var slugify = function (text) { return text .toString() .toLowerCase() .replace(/\s+/g, '-') // Replace spaces with - .replace(/[^\w\-]+/g, '') // Remove all non-word chars .replace(/\-\-+/g, '-') // Replace multiple - with single - .replace(/^-+/, '') // Trim - from start of text .replace(/-+$/, ''); // Trim - from end of text }; // ## KeyValue // Creates a key value object. // ### Usage // ```js // const result = KeyValue('query', 'hello+world'); // // result.key result.value // ``` // // ### Function var KeyValue = function KeyValue(key, value) { this.key = key; this.value = value; }; // ## objToQueryString // Converts an object to a list of KeyValue objects. // ### Usage // ```js // const result = objToQueryString({query: 'hello+world', category: 'blue'}); // // [KeyValue(hello, world), KeyValue(category, blue)] // ``` // // ### Function var objToQueryString = function (obj) { return Object.keys(obj).map(function (key) { return new KeyValue(key, obj[key]); }); }; // ## _parseQuery // Takes a string and converts to Array<KeyValue> // ### Usage // ```js // const result = _parseQuery('query=hello+world&category=blue'); // // [KeyValue(hello, world), KeyValue(category, blue)] // ``` // // ### Function var _parseQuery = function (str) { return str.split('&').map(function (qpart) { return new (Function.prototype.bind.apply( KeyValue, [ null ].concat( qpart.split('=')) )); }); }; // ## mergeQuery // Takes two queries of type Array<KeyValue> and merges them. // ### Usage // ```js // const result = mergeQuery( // objToQueryString({query: '!padrenull', cat: 'blue'}), // _parseQuery('query=hello+world') // ); // // [KeyValue(query, hello+world), KeyValue(cat, blue)] // ``` // // ### Function var mergeQuery = function (defaultQuery, query) { return defaultQuery .filter(function (param) { return !query.find(function (qparam) { return qparam.key == param.key; }); }) .concat(query); }; // ## generateQuery // Generate an Array<KeyValue> from a string and a default Array<KeyValue>. // ### Usage // ```js // const result = generateQuery('query=hello+world', [new KeyValue('query', '!padrenull')]); // // [KeyValue(query, hello+world)] // ``` // // ### Function var generateQuery = function (str, defaultQuery) { return mergeQuery(defaultQuery, _parseQuery(str)); }; // ## parseQuery // parse a query string using a default query. // ### Usage // ```js // const result = parseQuery('query=hello+world', [new KeyValue('query', '!padrenull')]); // // [KeyValue(query, hello+world)] // ``` // // ### Function var parseQuery = function (str, defaultQuery) { if ( defaultQuery === void 0 ) defaultQuery = []; return str && str.substr(0, 1) === '?' ? generateQuery(str.substr(1), defaultQuery) : str ? generateQuery(str, defaultQuery) : defaultQuery; }; var keyValuesToString = function (keyValues) { return keyValues.reduce(function (accum, item) { return (accum + "&" + (item.key) + "=" + (item.value)); }, '').substr(1); }; var keyValuesToQuery = function (keyValues) { return '?' + keyValuesToString(keyValues); }; var keyValuesToObject = function (keyValues) { var final = {}; keyValues.forEach(function (keyValue) { final[keyValue.key] = keyValue.value; }); return final; }; // ## isLocalhost // Check if is local development server var isLocalhost = function () { return location && location.hostname === 'localhost'; }; var createMarkup = function (markup) { return ({ __html: markup }); }; var reactKey = function (namespace, state, index) { return (namespace + "-" + (state.id) + "-" + index); }; var capitalize = function (string) { return string.charAt(0).toUpperCase() + string.slice(1); }; var isItems = function (items) { return Object.keys(items).length; }; var arrayFromSet = function (set) { var final = []; set.forEach(function (item) { return final.push(item); }); return final; }; var filterByKeys = function (keys, obj) { var result = {}; keys.forEach(function (key) { if (obj[key]) { result[key] = obj[key]; } }); return result; }; // # General Utility Functions for PRC // ## ageSuitability // Display age suitability range from provided months. If more than threshold, display as years. // ### Usage // ``` // const preheading = ageSuitability(state.ageMin, state.ageMax, state.ageSuitabilityDisplay); // ``` // ### Function var ageSuitabilityMock = function () { return { ageMin: '', ageMax: '', ageSuitabilityDisplay: '', divider: 12, greaterThan: 18, suffix: { months: '', years: '' } }; }; var strToNum = function (str) { return Number(str); }; var divide = function (number, divider) { return (number % divider ? strToNum((number / divider).toFixed(1)) : number / divider); }; var ageDataMock = function () { return { ageMin: '10', ageMax: '15', ageSuitabilityDisplay: '10-15' }; }; var getAge = function (ageData) { if ( ageData === void 0 ) ageData = ageDataMock(); return ({ ageMin: ageData.ageMin, ageMax: ageData.ageMax, ageSuitabilityDisplay: ageData.ageSuitabilityDisplay, divider: 12, greaterThan: 18, suffix: { months: 'months', years: 'years' } }); }; var ageSuitabilityCalculator = function (age) { if ( age === void 0 ) age = ageSuitabilityMock(); var ageMax = strToNum(age.ageMax); var ageMin = strToNum(age.ageMin); var result = { ageMin: ageMax > age.greaterThan || ageMin > age.greaterThan ? divide(ageMin, age.divider) : ageMin, ageMax: ageMax > age.greaterThan ? divide(ageMax, age.divider) : ageMax, suffix: ageMax > age.greaterThan ? age.suffix.years : age.suffix.months }; // If range, show min-max, otherwise show min+ var resultText = result.ageMax ? ((result.ageMin) + "-" + (result.ageMax) + " " + (result.suffix)) : ((result.ageMin) + "+"); var formattedText = resultText !== 'NaN+' ? resultText : ''; return age.ageSuitabilityDisplay ? age.ageSuitabilityDisplay : formattedText; }; var ageSuitability = function (ageData) { return ageSuitabilityCalculator(getAge(ageData)); }; var METHODS = ['Day', 'Date', 'FullYear', 'Hours', 'Minutes', 'Month', 'Seconds']; var DAY = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; var MONTH = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; var convert = function (f, k) { return (f[k] > 8 ? f[k] + 1 : ("0" + (f[k] + 1))); }; var convertTime = function (f, k) { return (f[k] > 9 ? ("" + (f[k])) : ("0" + (f[k]))); }; /** * * Creates a date object of type FriendlyDate from a date object * export type FriendlyDate = { * dayLong: string, * dayShort: string, * day: string, * monthLong: string, * monthShort: string, * month: string, * shortYear: string, * json: string, * date: number, * fullyear: number, * hours: number, * minutes: number, * month: number, * seconds: number * }; * * @example sq.friendlyDate(new Date()) * @param date */ var friendlyDate = function (date) { var final = { json: date.toJSON() }; METHODS.forEach(function (item) { final[item.toLowerCase()] = date['get' + item](); }); return Object.assign(final, { dayLong: DAY[final['day']], dayShort: DAY[final['day']].substr(0, 3), day: ("" + (final.date)), monthLong: MONTH[final['month']], monthShort: MONTH[final['month']].substr(0, 3), month: convert(final, 'month'), yearShort: ("" + (final.fullyear)).substr(2, 2), fullYear: ("" + (final.fullyear)), friendlyHours: convertTime(final, 'hours'), friendlyMinutes: convertTime(final, 'minutes') }); }; /** * Creates a date object of type FriendlyDate from a date object in string format * export type FriendlyDate = { * dayLong: string, * dayShort: string, * day: string, * monthLong: string, * monthShort: string, * month: string, * shortYear: string, * json: string, * date: number, * fullyear: number, * hours: number, * minutes: number, * month: number, * seconds: number * }; * @example * var dateVar = sq.friendlyDateFromString((new Date()).toString()) * @param date * @returns {FriendlyDate} */ var friendlyDateFromString = function (date) { return friendlyDate(new Date(Date.parse(date))); }; // this is a closure dummy var ReactRender = function (getElement) { return function (Component, props) { // how does this even work? var domContainerNode = getElement(); ///console.log(domContainerNode); var reactElement = React.createElement(Component, props); ReactDOM.render(reactElement, domContainerNode); //ReactDOM.unmountComponentAtNode(domContainerNode) }; }; var mount = function (element, Component, props) { var reactElement = React.createElement(Component, props); ReactDOM.render(reactElement, element); }; var mountNewRoot = function (element, Component, props, elType, classList) { if ( elType === void 0 ) elType = 'span'; if ( classList === void 0 ) classList = ['react-root']; var wrapper = document.createElement(elType); wrapper.id = props.state.id; try { wrapper.classList = classList; } catch(e) { wrapper.className = classList.join(' '); } // insert wrapper before el in the DOM tree element.parentNode.insertBefore(wrapper, element); element.parentNode.removeChild(element); mount(wrapper, Component, props); }; /** * * AppInstance * * Can be used to review data. Call render, and update state via actions. * @example * let appInstance = app({...}); * // call update action * appInstance = appInstance.emit('update'); * // call updateByValue action * appInstance = appInstance.emit('updateByValue', 3); * // call render * const renderResult = appInstance.render(Component, {state: appInstance.state, actions}) * @param {function} emit returns AppInstance * @param {object} state the current state * @param {function} render the passed in render function. This available for testing purposes. * @param {undefined|object} lastAction the result of the last action * @constructor */ var cleanForReact = function (str) { return str.replace(/&/gi, '&'); }; // TODO: add idAlias to all // TODO: add action.emit to all var app = function (obj) { var state = JSON.parse(cleanForReact(JSON.stringify(obj.state))); var views = obj.views; var tmp = obj._tmp || {}; obj.actions.beforeFirstRun = obj.actions.beforeFirstRun ? obj.actions.beforeFirstRun : function (state, actions) { return ({}); }; var actions = {}; var actionFn = function (action) { var params = [], len = arguments.length - 1; while ( len-- > 0 ) params[ len ] = arguments[ len + 1 ]; if (!actions[action]) { console.error(("action '" + action + "' does not exist in your actions for app with id: '" + (obj.state.id) + "'")); } return out(actions[action].apply(actions, params)); }; function out(lastAction) { if ( lastAction === void 0 ) lastAction = null; return { emit: actionFn, state: copy(state), render: obj.render, lastAction: lastAction, views: obj.views }; } Object.keys(obj.actions).forEach(function (action) { var actionWrapper = function () { var ref; var params = [], len = arguments.length; while ( len-- ) params[ len ] = arguments[ len ]; var nstate = copy(state); nstate._tmp = tmp; var result = (ref = obj.actions)[action].apply(ref, [ nstate, actions ].concat( params )); if (result) { state = copy(Object.assign(state, result)); state._tmp = result._tmp ? Object.assign({}, tmp, result._tmp) : tmp; obj.render(views[state.view], { state: Object.assign({}, views, state), actions: actions }); } return result; }; actionWrapper.refName = action; actionWrapper.ref = obj.actions[action]; actions[action] = actionWrapper; }); actionFn('beforeFirstRun'); delete actions['beforeFirstRun']; return out(); }; function StateResource(stype, resource, mockResponse, reuse) { if ( reuse === void 0 ) reuse = true; this.type = stype; this.resource = resource; this.mockResponse = mockResponse; this.reuse = reuse; } var stateJson = function (resource, mockResponse) { return new StateResource('json', resource, mockResponse); }; var pass = function (data) { return data; }; /** * When there is a value of item function pass the value to fn * @param item * @param fn */ var ready = function (item, fn, wait) { if ( wait === void 0 ) wait = 4; return (item() ? fn(item()) : setTimeout(function () { return ready(item, fn); }, wait)); }; function appRequest(sq, name, stateResource, thenHandler, debug$$1) { fetch(stateResource.resource, { credentials: 'include' }) .then(function (response) { if (stateResource.mockResponse) { response = { status: stateResource.mockResponse.status, json: function () { return Promise.resolve(JSON.parse(JSON.stringify(stateResource.mockResponse.body))); } }; console.log(response); } if (response.status === 200) { if (!!location && location.search.toString().match(/dump/)) { console.log(("Response for " + name + ":")); console.log(response); } var jsonResult; try { jsonResult = response.json(); } catch (e) { return Promise.reject(e); } return jsonResult.then(function (res) { if (typeof res.info === 'object') { return Promise.reject(res); } return res; }); } else if (response.status === 304) { return Promise.reject({ aliasId: 'authStatus', action: 'authFail' }); } else { return Promise.reject({}); } }) .then(thenHandler(stateResource.resource)) .catch(function (err) { if ( err === void 0 ) err = {}; console.log('appRequest error: ', err); //tryRemoteAction(sq, err.aliasId || 'globalModalAlias', err.action || 'globalModalError'); }); } var appInstance = function ( name, domElement, viewsActionsState, stateResources, runRequest, sq, debug$$1 ) { if ( stateResources === void 0 ) stateResources = null; if ( runRequest === void 0 ) runRequest = appRequest; if ( sq === void 0 ) sq = window.sq; if ( debug$$1 === void 0 ) debug$$1 = debug$$1; //TODO: Refactor all this stuff away to lib/sq.js if (!sq) { sq = window.sq; } if (viewsActionsState.state.idAlias) { sq.aliases[viewsActionsState.state.idAlias] = name; } sq.componentViews = Object.assign({}, sq.componentViews, viewsActionsState.views); if (!sq.aliases) { sq.aliases = {}; } if (viewsActionsState.state.idAlias) { sq.aliases[viewsActionsState.state.idAlias] = name; } var newApp = function () { sq[name] = app(Object.assign({}, viewsActionsState, {render: ReactRender(function () { return domElement; })})); }; var mainThenHandler = function (response) { viewsActionsState.actions.responseHandler = viewsActionsState.actions.responseHandler || pass; if (!sq[name]) { newApp(); } sq[name].emit('responseHandler', response); }; var thenHandler = function (key) { return function (response) { sq[key] = response; mainThenHandler(response); }; }; if (domElement && !sq[name]) { // Use this stateResource Type so if multiple apps need the same resource we only call that once if (stateResources) { if (viewsActionsState.state.view === 'Loading') { sq[name] = app(Object.assign({}, viewsActionsState, {render: ReactRender(function () { return domElement; })})); } stateResources = [].concat(stateResources); stateResources.forEach(function (stateResource) { if (stateResource.type === 'json') { if ( !stateResource.reuse || (stateResource.reuse && typeof sq[stateResource.resource] === 'undefined') ) { sq[stateResource.resource] = false; runRequest(sq, name, stateResource, thenHandler, debug$$1); } else { ready(function () { return sq[stateResource.resource]; }, mainThenHandler); } } }); } else { newApp(); } } else { sq[name] = null; } }; /** * * @param state * @param actions * @param subscriber */ var subscribeHandler = function (state, actions, subscriber) { var final = { _subscribers: state._subscribers || {} }; if (typeof final._subscribers[subscriber.event] === 'undefined') { final._subscribers[subscriber.event] = []; } if ( !final._subscribers[subscriber.event].find( function (item) { return item.action === subscriber.action && item.id === subscriber.id; } ) ) { final._subscribers[subscriber.event] = final._subscribers[subscriber.event].concat(subscriber); } return final; }; var getSubscribers = function (state, event) { return state._subscribers && state._subscribers[event] ? state._subscribers[event] : []; }; var tryId = function (id) { if (typeof window.sq[id] === 'undefined') { throw ("'" + id + "' does not exist in 'window.sq[id]'. Its likely you have a typo in your id or this app instance was not successfully instantiated after 10 seconds of the page load."); } return window.sq[id]; }; var __publish = function (eventsObject) { return function (state, actions, data) { if (!state) { return eventsObject; } if (!data.event) { console.error( ("You have not specified an event for the publish action using data\n" + (JSON.stringify(data, null, 2))) ); console.trace(); } if (data.after) { var result = eventsObject[data.event](state, actions, data); getSubscribers(state, data.event).forEach(function (subscriber) { tryId(subscriber.id).emit(subscriber.action, { data: data, result: result }); }); return result; } else if (data.before) { getSubscribers(state, data.event).forEach(function (subscriber) { tryId(subscriber.id).emit(subscriber.action, { data: data }); }); return eventsObject[data.event](state, actions, data); } else { return eventsObject[data.event](state, actions, data); } }; }; var allSubscribers = function (state, event, data) { return getSubscribers(state, event).forEach(function (subscriber) { tryId(subscriber.id).emit(subscriber.action, data); }); }; var subscribe = function (id, subscriber) { setTimeout(function () { tryId(id); }, 10000); window.sq.ready(function () { return window.sq[id]; }, function (app) { return app.emit('subscribe', subscriber); }, 50); }; // Builds the event object to be merged into the actions object var events = function (eventsObject) { return ({ publish: __publish(eventsObject), subscribe: subscribeHandler }); }; var MINIMUM_TWO_PARAMETERS = "actions.emit expects a minimum of two parameters. \n1. the id or alias of the app dom element. \n2. the action of the dom element"; var missingElement = function (first) { return (first + " does not exist as an element ID in the dom or an alias.\nIts preferable to use the app event system to avoid these issues.\n"); }; var emit = function (state, actions) { var params = [], len = arguments.length - 2; while ( len-- > 0 ) params[ len ] = arguments[ len + 2 ]; if (!params.length > 1) { console.error(MINIMUM_TWO_PARAMETERS); } var first = params.shift(); var app = actions[first] || window.sq[first] || window.sq[window.sq.aliases[first]]; if (!app) { console.error(missingElement(first)); } console.log(("Calling action '" + (params[0]) + "' on app '" + first + "'")); app.emit.apply(app, params); }; var addFunctionId = function (fn, id) { fn.functionId = id; return fn; }; var addWindowAction = function (state, actions, event, actionName, fn) { if (actions[actionName] && actions[actionName].functionId !== fn.functionId) { throw ("'" + actionName + "' clashes with another name in actions"); } var win = actions.window || window; if (!actions[actionName]) { actions[actionName] = fn; } win.addEventListener(event, actions[actionName]); }; var removeWindowAction = function (state, actions, event, actionName) { var win = actions.window || window; win.removeEventListener(event, actions[actionName]); }; var addDomAction = function (state, actions, event, actionName, fn) { if (actions[actionName] && actions[actionName].functionId && actions[actionName].functionId !== fn.functionId) { throw ("'" + actionName + "' clashes with another name in actions"); } // console.log(actions); var dom = actions.document || document; if (!actions[actionName]) { actions[actionName] = fn; // console.log(actions[actionName]); // console.log(`Adding dom action '${actionName}'.`) } else { // console.log(`Dom action '${actionName}' already added.`) } dom.addEventListener(event, actions[actionName]); }; var removeDomAction = function (state, actions, event, actionName) { var dom = actions.document || document; dom.removeEventListener(event, actions[actionName]); }; var mergeEvents = function (actions) { var initEventsObject = {}; if (actions.publish) { initEventsObject = actions.publish(); } return events(Object.assign({}, initEventsObject)); }; var baseActions = function (actions) { return (Object.assign({}, {emit: emit, addDomAction: addDomAction, removeDomAction: removeDomAction, addWindowAction: addWindowAction, removeWindowAction: removeWindowAction}, actions, mergeEvents(actions))); }; exports = { state: {}, components: {}, componentViews: {}, aliases: {}, __replaceParams: __replaceParams, addFunctionId: addFunctionId, ageSuitability: ageSuitability, allSubscribers: allSubscribers, app: app, appInstance: appInstance, arrayFromSet: arrayFromSet, baseActions: baseActions, capitalize: capitalize, clean: clean, cleanString: cleanString, cleanStringQuotes: cleanStringQuotes, compose: compose, convertMatrixBase64: convertMatrixBase64, copy: copy, createMarkup: createMarkup, debug: debug, events: events, filterByKeys: filterByKeys, flatten: flatten, friendlyDate: friendlyDate, friendlyDateFromString: friendlyDateFromString, getUrlParameter: getUrlParameter, highlightWords: highlightWords, htmlDecode: htmlDecode, immutable: immutable, isItems: isItems, isLocalhost: isLocalhost, jsonDecode: jsonDecode, jsonEncode: jsonEncode, keyValuesToObject: keyValuesToObject, keyValuesToQuery: keyValuesToQuery, maybeBase64Decode: maybeBase64Decode, b64EncodeUnicode: b64EncodeUnicode, b64DecodeUnicode: b64DecodeUnicode, mount: mount, mountNewRoot: mountNewRoot, objToQueryString: objToQueryString, parseQuery: parseQuery, pipe: pipe, reactKey: reactKey, ready: ready, slugify: slugify, stateJson: stateJson, subscribe: subscribe }; return exports; }({})); </script> <script> (function(sq) { sq.state.site = {"gitFilesPath":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/m%403x.png","logoURL":"","legalName":"null","siteName":"Raising Children Network Media & Reusable Content","homeURL":"https://raisingchildren.net.au/_media","menu":[{"asset_assetid":"44274","asset_name":"Images - varieties","asset_short_name":"Images - varieties","asset_url_path":"/_media/images-varieties"},{"asset_assetid":"23385","asset_name":"Glossaries","asset_short_name":"Glossaries","asset_url_path":"/_media/glossary"},{"asset_assetid":"52647","asset_name":"Listings","asset_short_name":"Listings","asset_url_path":"/_media/listings"},{"asset_assetid":"53752","asset_name":"Global Content","asset_short_name":"Global Content","asset_url_path":"/_media/global-content"},{"asset_assetid":"73064","asset_name":"Custom sidebars","asset_short_name":"Custom sidebars","asset_url_path":"/_media/custom-sidebars"}],"footerFlags":[],"siteAcknowledgement":"null","siteLegalName":"null","subscribe":{"formUrl":"https://raisingchildren.net.au/_media/glossary/collagen","formContentId":"1","subscribePage":"","fields":"eyJhc3NldGlkIjoiMSIsInR5cGVfY29kZSI6InJvb3RfZm9sZGVyIiwidmVyc2lvbiI6IjAuMC4xIiwibmFtZSI6IlJvb3QgRm9sZGVyIiwic2hvcnRfbmFtZSI6IlwvIiwiZXh0ZXJuYWxfaWQiOmZhbHNlLCJzdGF0dXMiOiIyIiwibGFuZ3VhZ2VzIjoiZW4iLCJjaGFyc2V0IjoidXRmLTgiLCJjcmVhdGVkIjoiMjAxOC0wNS0wNCAxNDowMDoxNCIsImNyZWF0ZWRfdXNlcmlkIjoiMCIsInVwZGF0ZWQiOiIyMDE4LTA1LTA0IDE0OjAwOjE0IiwidXBkYXRlZF91c2VyaWQiOiIwIiwicHVibGlzaGVkIjoiTmV2ZXIiLCJwdWJsaXNoZWRfdXNlcmlkIjoiIiwic3RhdHVzX2NoYW5nZWQiOiIyMDE4LTA1LTA0IDE0OjAwOjE0Iiwic3RhdHVzX2NoYW5nZWRfdXNlcmlkIjoiMCIsInRodW1ibmFpbCI6IiIsImF0dHJpYnV0ZXMiOnsibmFtZSI6eyJhdHRyaWQiOiI4ODgiLCJ0eXBlIjoidGV4dCIsInZhbHVlIjoiUm9vdCBGb2xkZXIiLCJpc19jb250ZXh0YWJsZSI6dHJ1ZSwidXNlX2RlZmF1bHQiOnRydWV9fSwibWV0YWRhdGEiOltdfQ=="},"instagramUrl":"null","linkedinUrl":"null","twitterUrl":"null","facebookUrl":"null","googlePlusUrl":"null","youtubeUrl":"null","matrixSearchPage":"https://raisingchildren.net.au/search","movieReviewSearchPage":"https://raisingchildren.net.au/guides/movie-reviews","footerMenuBlocks":[],"_webserviceSuggestUrl":"https://prc-search.squiz.cloud/s/suggest.json","_webserviceSearchUrl":"https://prc-search.squiz.cloud/s/search.html","_webserviceSearchHost":"https://prc-search.squiz.cloud","queryObject":{"query":"!padrenull","collection":"raising-children-web","uatCollection":"raising-children-web-uat","form":"matrix_json","metaAND_pageContentLang":"en"}} })(sq); </script> <!--<script async src="https://raisingchildren.net.au/_media?SQ_DESIGN_NAME=menu"></script>--> <!-- menu.optimised.js PROD:#98836 STAGE: #92832 DEV: #92816 --> <script async src="https://raisingchildren.net.au/menu.optimised.js"></script> <!-- /end src-matrix/nested-content/head/global-design-head-site-state.html --> <!-- begin src-matrix/nested-content/head/global-design-head-page-state.html --> <meta name="lineage" content="92;23385;45537" /> <meta name="top_level_item" content="Glossaries" /> <meta name="stage_group" content="" /> <meta name="asset_name" content="collagen" /> <meta name="asset_short_name" content="collagen" /> <meta name="page_thumbnail_url" content="" /> <meta name="header_banner_url" content="" /> <meta name="header_banner_square_url" content="" /> <meta name="language" content="en" /> <script> sq.state.page = {"articleType":"","lineage":["92","23385","45537"],"lineageDetail":[{"asset_assetid":"92","asset_name":"Raising Children Network Media & Reusable Content","asset_short_name":"Raising Children Network Media & Reusable Content","asset_linking_info_current":{"linkid":"95","link_type":"1","link_value":"","lineage":["83"]},"asset_url":"https://raisingchildren.net.au/_media","asset_metadata_stage_group":null},{"asset_assetid":"23385","asset_name":"Glossaries","asset_short_name":"Glossaries","asset_linking_info_current":{"linkid":"91165","link_type":"1","link_value":"","lineage":["83","92"]},"asset_url":"https://raisingchildren.net.au/_media/glossary","asset_metadata_stage_group":null},{"asset_assetid":"45537","asset_name":"collagen","asset_short_name":"collagen","asset_linking_info_current":{"linkid":"181263","link_type":"1","link_value":"","lineage":["83","92","23385"]},"asset_url":"https://raisingchildren.net.au/_media/glossary/collagen","asset_metadata_stage_group":null}],"frontend_asset_name":"collagen","frontend_asset_short_name":"collagen","assetType":"page_standard","assetid":"45537","asset_url":"https://raisingchildren.net.au/_media/glossary/collagen","thumbnail_url":"","defaultThumbnailURL":"https://raisingchildren.net.au/__data/assets/image/0006/40110/placeholder-wide.jpg","defaultThumbnailSquareURL":"https://raisingchildren.net.au/__data/assets/image/0014/40109/placeholder-narrow.jpg","video":false,"counter":0,"description":"null","videoUrl":"","videoDescription":"","l1Header":"Glossaries","heroSection":{"otherLanguage":false,"background":{"mobile":"","tablet":"","desktop":"","show":false},"preheading":"null","ageMin":"null","ageMax":"null","ageSuitabilityDisplay":"","heading":"collagen","intro":"null","showIntro":false,"landing":false,"button":{"toParent":{"href":"https://raisingchildren.net.au/_media/glossary","text":"Glossaries"},"share":{"href":"https://raisingchildren.net.au/_media/glossary/collagen","addThisLink":""}},"rtl":""},"topLevelItem":{"asset_assetid":"23385","asset_name":"Glossaries","asset_short_name":"Glossaries","asset_linking_info_current":{"linkid":"91165","link_type":"1","link_value":"","lineage":["83","92"]},"asset_url":"https://raisingchildren.net.au/_media/glossary","asset_metadata_stage_group":null},"stageGroup":{"asset_assetid":"23385","asset_name":"Glossaries","asset_short_name":"Glossaries","asset_linking_info_current":{"linkid":"91165","link_type":"1","link_value":"","lineage":["83","92"]},"asset_url":"https://raisingchildren.net.au/_media/glossary","asset_metadata_stage_group":null},"pageContentDir":"","otherLanguage":"en"} </script> <!-- /end src-matrix/nested-content/head/global-design-head-page-state.html --> <!-- begin src-matrix/nested-content/head/global-design-head-user-state.html --> <script> sq.state.user = {"isUserLoggedIn":false,"loggedInOverride":false,"first_name":"","last_name":""} </script> <!-- /end src-matrix/nested-content/head/global-design-head-user-state.html --> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> <title>collagen</title> <meta name="google-site-verification" content="EnaXP8S0SL4XL7MB_al5NC98jTn5rosmqIa6o2ICQ6E" /> <meta name="asset_id" content="45537"/> <meta name="site_internal_domains" content=""/> <!-- Running Squiz Matrix Developed by Squiz - http://www.squiz.net Squiz, Squiz Matrix, MySource, MySource Matrix and Squiz.net are registered Trademarks of Squiz Pty Ltd Page generated: 28 November 2024 17:42:01 --> </head> <body> <input type="hidden" name="token" value="31cd16b80d787d9fd0020132901a867ab62d95f0" class="sq-form-field" id="token" /><!-- begin src-matrix/nested-content/header/global-design-skip-to-content.html --> <div id="skip-to-links-wrapper"> <script> (function(sq) { var isFirefox = typeof InstallTrigger !== 'undefined'; if(isFirefox) { document.getElementById('skip-to-links-wrapper').style.visibility = 'hidden'; sq.ready(() => document.getElementById('footer'), () => document.getElementById('skip-to-links-wrapper').style.visibility = 'visible'); } })(window.sq) </script> <div id="skip-links" class="skip-links" aria-hidden="true"> <ul class="skip-links__list"> <li class="skip-links__item"><a class="skip-links__link" href="#main">Skip to content</a></li> <li class="skip-links__item"><a class="skip-links__link" href="#navigation">Skip to navigation</a></li> </ul> </div> </div> <!-- /end src-matrix/nested-content/header/global-design-skip-to-content.html --> <div id="page-wrapper" class="page-wrapper"> <!-- begin src-matrix/nested-content/header/global-design-header.html --> <div id="header-mobile"></div> <div id="header-tablet"></div> <div id="header-desktop"></div> <!-- /end src-matrix/nested-content/header/global-design-header.html --> <div class="main-wrapper"> <script>console['info']("Begin 'transducer' for container #hero-section-52511 heroSection")</script><script>console['info']("Complete 'transducer' for container #hero-section-52511 heroSection")</script><script>console['info']("Begin 'heroSection' for container #hero-section-52511")</script><!-- Begin container id #hero-section-52511 'heroSection' --> <div><div><script src="https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/hero-section.js?v=2023-04-24T035717.998Z" id="heroSection"></script></div><section id="hero-section-52511" class="hero container-template"></section><script>try {sq.heroSection('hero-section-52511', Object.assign({}, sq.state, sq.aliases, sq.componentViews, JSON.parse('{"cls":"hero","namespace":"hero-section","assetid":"52511","id":"hero-section-52511","otherLanguage":"","background":{"mobile":"","tablet":"","desktop":"","show":false},"preheading":"null","ageMin":"null","ageMax":"null","ageSuitabilityDisplay":"","heading":"collagen","intro":"null","showIntro":false,"landing":false,"showBreadcrumbs":false,"button":{"toParent":{"href":"https://raisingchildren.net.au/_media/glossary","text":"Glossaries"},"share":{"href":"https://raisingchildren.net.au/_media/glossary/collagen","addThisLink":"null","icons":{"fbIcon":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/social-share-fb.svg","mailIcon":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/social-share-mail.svg","pinIcon":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/social-share-pin.svg","plusIcon":"","printIcon":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/social-share-print.svg","linkedinIcon":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/files/social-share-linkedin.svg"}}},"rtl":"","src":"https://raisingchildren.net.au/__data/assets/git_bridge/0013/94/static/hero-section.js","camel":"heroSection","containerType":"section"}'))); }catch(e) {console.log(e); console.trace(); console.error("Could not render component `heroSection` with id `hero-section-52511`") }</script></div> <!-- End container id #hero-section-52511 'heroSection' --> <script>console['info']("Complete 'heroSection' for container #hero-section-52511")</script> <!-- begin src-matrix/nested-content/main/global-design-body-main.html --> <div class="container"> <div class="row justify-content-center "> <div class="col-sm-12 col-lg-12 section-main"> <main class="main" id="main"> <div class="content-viewport"> <div > <div id="main-content" > <div id="content_container_45539"> <p>A type of protein that connects tissues in the body. It’s found in many parts of the body including skin, tendons, ligaments, bones, blood vessels, cartilage and the gut.</p> </div> </div> </div> </div> </main> </div> </div> </div> <!-- /end src-matrix/nested-content/main/global-design-body-main.html --> <!-- begin src-matrix/nested-content/footer/global-design-footer.html --> <!-- /end src-matrix/nested-content/footer/global-design-footer.html --> <!-- <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5a2a25a975ec241c" async="async"></script> --> </div> </div> </body> </html>