function Cobalt(x) { try { self.cobalt._ instanceof Cobalt } catch(exception) { self.cobalt = { _: this } self.cobalt.blueprint = { blueprints: [], draw: function _(name, code) { for (let i = 0; i < self.cobalt.blueprint.blueprints.length; i++) { if (self.cobalt.blueprint.blueprints[i].name == name) { return false } } code = code.toString() if (code.indexOf('_ => {') == 0) { code = code.replace('_ => {', '') code = code.split('').reverse().join('').replace('}', '').split('').reverse().join('') } blueprint = { name: name, code: code } self.cobalt.blueprint.blueprints.push(blueprint) return true }, sketch: function _(contexts, parent, code) { code = code.toString() if (code.indexOf('_ => {') == 0) { code = code.replace('_ => {', '') code = code.split('').reverse().join('').replace('}', '').split('').reverse().join('') } for (let i = 0; i < self.cobalt.blueprint.blueprints.length; i++) { if (self.cobalt.blueprint.blueprints[i].code == code) { self.cobalt.object.build(self.cobalt.blueprint.blueprints[i].name, contexts, parent) return } } random = self.cobalt.tools.random(0, 1000000) self.cobalt.blueprint.draw(random, code) self.cobalt.object.build(random, contexts, parent) }, require: function _(blueprints, updateAfter) { for (let i = 0; i < blueprints.length; i++) { let customContext = blueprints[i][0] if (updateAfter === true) { customContext = customContext + ',' + blueprints.length } self.cobalt.request.get(blueprints[i][1], [], true, function(response) { self.cobalt.blueprint.draw(response.customContext.split(',')[0], response.response) if (response.customContext.split(',').length > 0) { if (self.cobalt.blueprint.blueprints.length == parseInt(response.customContext.split(',')[1])) { self.cobalt.update() } } }, customContext) } }, update: function _(name, updatedCode) { for (let i = 0; i < self.cobalt.blueprint.blueprints.length; i++) { if (self.cobalt.blueprint.blueprints[i].name == name) { self.cobalt.blueprint.blueprints = self.cobalt.blueprint.blueprints[i].splice(i, 1) self.cobalt.blueprint.draw(name, updatedCode) } } } } self.cobalt.cobalt = function _() { return true } self.cobalt.component = { components: [], create: function _(name, code, labels) { for (let i = 0; i < self.cobalt.component.components.length; i++) { if (self.cobalt.component.components[i].name == name) { return false } } code = code.toString() if (code.indexOf('function() ') == 0) { code = code.replace('function() {', '') code = code.split('').reverse().join('').replace('}', '').split('').reverse().join('') } if (code.indexOf('function()') == 0) { code = code.replace('function(){', '') code = code.split('').reverse().join('').replace('}', '').split('').reverse().join('') } component = { name: name, code: code, labels: labels } self.cobalt.component.components.push(component) return true }, replace: function _(name, newCode, newLabels) { for (let i = 0; i < self.cobalt.component.components.length; i++) { if (self.cobalt.component.components[i].name == name) { self.cobalt.component.components = self.cobalt.component.components[i].splice(i, 1) self.cobalt.component.create(name, newCode, newLabels) } } } } self.cobalt.data = { extract: function _(data) { return JSON.parse(data) }, package: function _(data) { return JSON.stringify(data) }, parser: function _(data, query) { parser = new DOMParser() document = parser.parseFromString(data, 'text/html') return document.querySelectorAll(query) } } self.cobalt.document = { root: document.querySelector('body'), scroll: (to) => { window.scroll(0, to) }, size: _ => { return { width: window.innerWidth, height: window.innerHeight } }, icon: (location) => { let link = document.createElement('link') link.setAttribute('cobalt', 'icon') link.setAttribute('href', location) document.head.appendChild(link) self.cobalt.import.badges.push('icon') }, path: function _(newPath) { if (!(newPath == '')) { history.pushState({},'', window.location.href.replace('//', '%%').split('/')[0].replace('%%', '//') + newPath) } else { return window.location.href.replace('//', '').replace('/', '%').split('%')[1] } }, moveRoot: function _(newRoot) { if (typeof newRoot === 'string') { newRoot = document.querySelector(newRoot) } self.cobalt.document.root = newRoot }, title: function _(newTitle) { if (!(newTitle == '')) { if (document.querySelectorAll('head > title').length == 0) { title = document.createElement('title') title.innerHTML = newTitle document.head.appendChild(title) } else { document.querySelectorAll('head > title')[0].innerHTML = newTitle } } else { return document.querySelectorAll('head > title')[0].innerHTML } }, clear: _ => { self.cobalt.object.objects = [] } } self.cobalt.get = { label: function _(label) { list = [] for (let i = 0; i < self.cobalt.object.objects.length; i++) { let currentLabels = self.cobalt.object.objects[i].labels for (let ii = 0; ii < currentLabels.length; ii++) { if (currentLabels[ii] == label) { list.push(self.cobalt.object.objects[i].id) } } } return list }, node: function _(id) { result = { exists: false, node: undefined } nodes = document.querySelectorAll('*[cobalt~="' + id + '"]') if (nodes.length == 1) { result.node = nodes[0] result.exists = true } return result }, object: function _(id) { if (Array.isArray(id)) { objects = [] for (let i = 0; i < id.length; i++) { currentID = id[i] for (let ii = 0; ii < self.cobalt.object.objects.length; ii++) { if (self.cobalt.object.objects[ii].id == id) { objects.push(self.cobalt.object.objects[ii]) } } } return objects } result = { exists: false, object: undefined } for (let i = 0; i < self.cobalt.object.objects.length; i++) { if (self.cobalt.object.objects[i].id == id) { result.object = self.cobalt.object.objects[i] result.exists = true } } return result } } self.cobalt.identify = { authentication: { token: '', fingerprint: '', }, initialize: function _(execute) { if (self.cobalt.memory.storage === undefined) { console.log('[Cobalt] WARN | Tried to set up identification without first setting up the database.') return false } transaction = self.cobalt.memory.storage.transaction(['authentication'], 'readwrite') store = transaction.objectStore('authentication') request = store.add({ 'property': 'fingerprint', 'value': '' }) request.onsuccess = function() { secondRequest = store.add({ 'property': 'token', 'value': '' }) secondRequest.onsucces = function() { tokenTransaction = self.cobalt.memory.storage.transaction(['authentication']) tokenStore = tokenTransaction.objectStore('authentication') tokenRequest = tokenStore.get('token') tokenRequest.onsuccess = function(tokenEvent) { self.cobalt.identify.authentication.token = tokenEvent.target.result.value fingerprintTransaction = self.cobalt.memory.storage.transaction(['authentication']) fingerprintStore = fingerprintTransaction.objectStore('authentication') fingerprintRequest = fingerprintStore.get('fingerprint') fingerprintRequest.onsuccess = function(fingerprintEvent) { self.cobalt.identify.authentication.fingerprint = fingerprintEvent.target.result.value if (!(execute === undefined)) { execute() } } } } } }, integrity: function _(execute, customContext) { self.cobalt.request.get('/_/integrity', [], true, execute, customContext) }, setToken: function _(token, execute) { transaction = self.cobalt.memory.storage.transaction(['authentication'], 'readwrite') store = transaction.objectStore('authentication') request = store.put({ property: 'token', value: token }) request.onsuccess = function() { if (!(execute === undefined)) { execute() } } }, setFingerprint: function _(execute) { transaction = self.cobalt.memory.storage.transaction(['authentication'], 'readwrite') store = transaction.objectStore('authentication') request = store.put({ property: 'fingerprint', value: Math.floor(Math.random() * Math.floor(99999)).toString() }) request.onsuccess = function() { if (!(execute === undefined)) { execute() } } } } self.cobalt.import = { badges: [], export: function _(badge) { for (let i = 0; i < self.cobalt.import.badges.length; i++) { if (self.cobalt.import.badges[i] == badge) { self.cobalt.import.badges.splice(i, 1) document.querySelectorAll('head *[cobalt="' + badge + '"]')[0].remove() } } }, font: function _(badge, source) { current = document.querySelectorAll('head > style') for (let i = 0; i < current.length; i++) { if (current[i].getAttribute('font') == badge) { current.innerHTML = '@font-face{font-family:' + badge + ';src:url(\'' + source + '\');}' return } } element = document.createElement('style') element.setAttribute('cobalt', 'font:' + badge) element.innerHTML = '@font-face{font-family:' + badge + ';src:url(\'' + source + '\');}' document.head.appendChild(element) self.cobalt.import.badges.push('font:' + badge) }, script: function _(badge, script, external, wait) { newScript = document.createElement('script') newScript.setAttribute('cobalt', 'script:' + badge) if (wait) { newScript.setAttribute('defer', 'defer') } if (external) { newScript.setAttribute('src', script) } else { newScript.innerHTML = script } document.head.appendChild(newScript) self.cobalt.import.badges.push('script:' + badge) }, style: function _(badge, style, external) { for (let i = 0; i < self.cobalt.import.badges.length; i++) { if (self.cobalt.import.badges[i] == 'style:' + badge) { return } } if (external) { newStyle = document.createElement('link') newStyle.setAttribute('href', style) newStyle.setAttribute('rel', 'stylesheet') } else { newStyle = document.createElement('style') newStyle.innerHTML = style } newStyle.setAttribute('cobalt', 'style:' + badge) document.head.appendChild(newStyle) self.cobalt.import.badges.push('style:' + badge) } } self.cobalt.include = { blueprint: function _(name) { self.cobalt.request.get('/_/include/blueprints', [['name', name]], true, function(response) { if (response.success) { if (response.code == 200) { self.cobalt.blueprint.draw('cobalt.' + name, response.response) } } }) }, component: function _(name, labels) { self.cobalt.request.get('/_/include/components', [['name', name]], true, function(response) { if (response.success) { if (response.code == 200) { self.cobalt.component.create('cobalt.' + name, response.response, labels) } } }) }, manifest: function _(parameters) { element = document.createElement('link') element.setAttribute('rel', 'manifest') query = '?' for (let i = 0; i < parameters.length; i++) { query = query + '&' + parameters[i][0] + '=' + parameters[i][1] } query = query.replace('?&', '?') element.setAttribute('href', '/_/manifest' + query) element.setAttribute('cobalt', 'manifest') document.head.appendChild(element) self.cobalt.import.badges.push('manifest') }, styleKit: function _() { foundFont = 0 for (let i = 0; i < self.cobalt.import.badges.length; i++) { if (self.cobalt.import.badges[i] == 'font:cobalt-display') { foundFont++ } if (self.cobalt.import.badges[i] == 'font:cobalt-text') { foundFont++ } } if (foundFont < 2) { self.cobalt.import.font('cobalt-display', '/_/library/asset?location=fonts/display&type=font/ttf') self.cobalt.import.font('cobalt-text', '/_/library/asset?location=fonts/text&type=font/ttf') } styleKit = document.createElement('link') styleKit.setAttribute('href', '/_/styleKit') styleKit.setAttribute('rel', 'stylesheet') styleKit.setAttribute('cobalt', 'styleKit') document.head.appendChild(styleKit) self.cobalt.import.badges.push('styleKit') }, worker: function _() { try { navigator.serviceWorker.register('/?worker=*') } catch (exception) {} } } self.cobalt.memory = { storage: undefined, global: {}, add: function _(key, value, execute) { transaction = self.cobalt.memory.storage.transaction(['memory'], 'readwrite') store = transaction.objectStore('memory') request = store.add({ 'memoryKey': key, 'memoryValue': value }) request.onsuccess = function() { if (!(execute === undefined)) { execute() } } }, clear: function _(execute) { transaction = self.cobalt.memory.storage.transaction(['memory'], 'readwrite') store = transaction.objectStore('memory') request = store.clear() request.onsuccess = function() { if (!(execute === undefined)) { execute() } } }, delete: function _(key, execute) { transaction = self.cobalt.memory.storage.transaction(['memory'], 'readwrite') store = transaction.objectStore('memory') request = store.delete(key) request.onsuccess = function() { if (!(execute === undefined)) { execute() } } }, get: function _(key, execute) { transaction = self.cobalt.memory.storage.transaction(['memory']) store = transaction.objectStore('memory') request = store.get(key) request.onsuccess = function(event) { if (!(execute === undefined)) { try { execute(event.target.result.memoryValue) } catch(exception) { execute() } } } }, setup: function _(execute) { if (execute === undefined) { execute = function() {} } try { databaseRequest = window.indexedDB.open('cobalt', 1) databaseRequest.onupgradeneeded = function(event) { database = event.target.result database.createObjectStore('memory', {keyPath: "memoryKey"}) database.createObjectStore('authentication', {keyPath: "property"}) self.cobalt.memory.storage = database } databaseRequest.onsuccess = function(event) { self.cobalt.memory.storage = event.target.result execute() } } catch(exception) {} }, update: function _(key, newValue, execute) { transaction = self.cobalt.memory.storage.transaction(['memory'], 'readwrite') store = transaction.objectStore('memory') request = store.put({ memoryKey: key, memoryValue: newValue }) request.onsuccess = function() { if (!(execute === undefined)) { execute() } } }, } self.cobalt.navigation = { redirect: function _(location) { window.location.href = location }, scroll: function _(position) { destination = { top: position, left: 0, behaviour: 'smooth' } window.scroll(destination) }, switch: function _(page) { window.location.href = page } } self.cobalt.object = { objects: [], build: function _(blueprint, contexts, parent) { if (parent === undefined) { parent = 0 } if (!(Array.isArray(contexts))) { if (contexts === undefined) { contexts = [''] } else { contexts = [contexts] } } for (let i = 0; i < contexts.length; i++) { valid = true invalidReason = 0 for (let ii = 0; ii < self.cobalt.object.objects.length; ii++) { if (self.cobalt.object.objects[ii].blueprint == blueprint) { objectContext = self.cobalt.object.objects[ii].context if (typeof objectContext === 'object') { objectContext = self.cobalt.data.package(objectContext) } compareContext = contexts[i] if (typeof compareContext === 'object') { compareContext = self.cobalt.data.package(contexts[i]) } if (objectContext == compareContext) { if (self.cobalt.object.objects[ii].data.parent == parent) { valid = false invalidReason = self.cobalt.object.objects[ii].id } } } } if (!(valid)) { if (contexts.length == 1) { return invalidReason } continue } newObject = { id: 0, labels: [], blueprint: blueprint, context: contexts[i], data: { value: '', style: [], properties: [], parent: parent, type: 'cobalt' } } while (true) { randomID = Math.floor(Math.random() * 1000000) if (document.querySelectorAll('*[cobalt~="' + randomID + '"]').length == 0) { newObject.id = randomID break } } self.cobalt.object.objects.push(newObject) if (contexts.length == 1) { return newObject.id } } }, destroy: function _(id) { killList = [] addToKillList(id) function addToKillList(id) { for (let i = 0; i < self.cobalt.object.objects.length; i++) { if (self.cobalt.object.objects[i].id == id) { killList.push(i) } if (self.cobalt.object.objects[i].data.parent == id) { addToKillList(self.cobalt.object.objects[i].id) } } } for (let i = 0; i < killList.length; i++) { self.cobalt.object.objects.splice(killList[i], 1) } }, } self.cobalt.request = { get: function _(to, query, secure, execute, customContext) { if (secure) { fingerprint = self.cobalt.identify.authentication.fingerprint token = self.cobalt.identify.authentication.token query.push(['cobalt', fingerprint + '::' + token]) } compiledQuery = '?' for (let i = 0; i < query.length; i++) { compiledQuery = compiledQuery + query[i][0] + '=' + query[i][1] if (!(i + 2 > query.length)) { compiledQuery = compiledQuery + '&' } } try { var request = new XMLHttpRequest() request.onreadystatechange = function() { if (request.readyState == 4) { execute({response: request.response, code: request.status, success: true, customContext: customContext}) } } request.open('GET', to + compiledQuery) request.send() } catch(exception) { return {response: exception, code: 0, success: false, customContext: customContext} } }, post: function _(to, query, body, secure, execute, customContext) { if (secure) { fingerprint = self.cobalt.identify.authentication.fingerprint token = self.cobalt.identify.authentication.token query.push(['cobalt', fingerprint + '::' + token]) } compiledQuery = '?' for (let i = 0; i < query.length; i++) { compiledQuery = compiledQuery + query[i][0] + '=' + query[i][1] if (!(i + 2 > query.length)) { compiledQuery = compiledQuery + '&' } } try { var request = new XMLHttpRequest() request.onreadystatechange = function() { if (request.readyState == 4) { execute({response: request.response, code: request.status, success: true, customContext: customContext}) } } request.open('POST', to + compiledQuery) request.send(body) } catch(exception) { return {response: exception, code: 0, success: false, customContext: customContext} } } } self.cobalt.socket = { call: function _(body, execute, customContext) { body = self.cobalt.data.package(body) self.cobalt.request.post('/_/socket', [], body, true, execute, customContext) }, authorize: function _(userID, key, execute, customContext) { body = { _: "cobalt-authentication", action: "authorize", credentials: { userID: userID, key: key } } self.cobalt.request.post('/_/socket', [], self.cobalt.data.parse(body), execute, customContext) } } self.cobalt.tools = { print: function _(message) { console.log('[Cobalt] => ' + message) }, random: function _(minimum, maximum) { return Math.floor((Math.random() * maximum) + minimum) } } self.cobalt.update = function _() { valueToProperty() importProperties() updateObjects() applyComponents() updateNodes() propertyToValue() exportProperties() function valueToProperty() { nodes = self.cobalt.document.root.querySelectorAll('*') for (let i = 0; i < nodes.length; i++) { if (!(nodes[i].value === null)) { if (!(nodes[i].getAttribute('cobalt') == '_')) { nodes[i].setAttribute('value', nodes[i].value) } } } } function importProperties() { nodes = self.cobalt.document.root.querySelectorAll('*') for (let i = 0; i < nodes.length; i++) { id = nodes[i].getAttribute('cobalt') if (!(id == '_')) { for (let ii = 0; ii < self.cobalt.object.objects.length; ii++) { if (self.cobalt.object.objects[ii].id == id) { self.cobalt.object.objects[ii].data.properties = [] for (let iii = 0; iii < nodes[i].attributes.length; iii++) { validProperty = true if (nodes[i].attributes[iii].name == 'cobalt') { validProperty = false } if (nodes[i].attributes[iii].name == 'style') { validProperty = false } if (validProperty) { newProperty = [] newProperty.push(nodes[i].attributes[iii].name) newProperty.push(nodes[i].attributes[iii].value) self.cobalt.object.objects[ii].data.properties.push(newProperty) } } } } } } } function updateObjects() { for (let i = 0; i < self.cobalt.object.objects.length; i++) { for (let ii = 0; ii < self.cobalt.blueprint.blueprints.length; ii++) { if (self.cobalt.blueprint.blueprints[ii].name == self.cobalt.object.objects[i].blueprint) { objectFunction = new Function('$', 'x', self.cobalt.blueprint.blueprints[ii].code + '\nreturn x') self.cobalt.object.objects[i] = objectFunction(self.cobalt, self.cobalt.object.objects[i]) } } } } function applyComponents() { for (let i = 0; i < self.cobalt.object.objects.length; i++) { for (let ii = 0; ii < self.cobalt.component.components.length; ii++) { for (let iii = 0; iii < self.cobalt.object.objects[i].labels.length; iii++) { if ('~' + self.cobalt.component.components[ii].labels.join('~') + '~'.indexOf(self.cobalt.object.objects[i].labels[iii]) > -1) { componentFunction = new Function('$', 'x', self.cobalt.component.components[ii].code + '\nreturn x') self.cobalt.object.objects[i] = componentFunction(self.cobalt, self.cobalt.object.objects[i]) } } } } } function updateNodes() { root = self.cobalt.document.root nodes = root.querySelectorAll('*') objects = self.cobalt.object.objects for (let i = 0; i < nodes.length; i++) { id = nodes[i].getAttribute('cobalt') if (!(id == "_")) { found = false for (let ii = 0; ii < objects.length; ii++) { if (id == objects[ii].id) { found = true if (!(objects[ii].data.type.toUpperCase() == nodes[i].nodeName)) { console.log('[Cobalt] WARN | Node type change detected. This is unsupported.') } compiledStyle = '' for (let iii = 0; iii < objects[ii].data.style.length; iii++) { sep = ' ' if (objects[ii].data.style[iii][0] == 'cobalt') { sep = '+' } compiledStyle = compiledStyle + objects[ii].data.style[iii][0] + ':' + objects[ii].data.style[iii].slice(1).join(sep) + ';' } if (!(compiledStyle == nodes[i].getAttribute('style'))) { nodes[i].setAttribute('style', compiledStyle) } if (objects[ii].data.parent > 0) { if (!(parseInt(nodes[i].parentNode.getAttribute('cobalt')) == objects[ii].data.parent)) { console.log('[Cobalt] WARN | Parental change detected. This is unsupported.') } } if (nodes[i].childNodes.length < 1) { if (!(nodes[i].innerHTML == objects[ii].data.value)) { nodes[i].innerHTML = objects[ii].data.value } } else { if (nodes[i].childNodes[0].nodeName == '#text') { if (!(nodes[i].innerHTML == objects[ii].data.value)) { nodes[i].innerHTML = objects[ii].data.value } } } } } if (!(found)) { nodes[i].remove() } } } for (let i = 0; i < self.cobalt.object.objects.length; i++) { if (!(document.querySelectorAll('*[cobalt~="' + objects[i].id + '"]').length == 1)) { newNode = document.createElement(objects[i].data.type) newNode.setAttribute('cobalt', objects[i].id) compiledStyle = '' for (let ii = 0; ii < objects[i].data.style.length; ii++) { sep = ' ' if (objects[i].data.style[ii][0] == 'cobalt') { sep = '+' } compiledStyle = compiledStyle + objects[i].data.style[ii][0] + ':' + objects[i].data.style[ii].slice(1).join(sep) + ';' } newNode.setAttribute('style', compiledStyle) newNode.innerHTML = objects[i].data.value newNode = processEvents(newNode, objects[i]) for (let ii = 0; ii < objects[i].data.properties.length; ii++) { newNode.setAttribute(objects[i].data.properties[ii][0], objects[i].data.properties[ii][1]) } if (objects[i].data.parent == 0) { self.cobalt.document.root.appendChild(newNode) } else { try { document.querySelectorAll('*[cobalt~="' + objects[i].data.parent + '"]')[0].appendChild(newNode) } catch (exception) { console.log('[Cobalt] ERROR | Object has an invalid or non-existent parent!') } } } } } function processEvents(newNode, currentObject) { if (currentObject.data.events == undefined) { return newNode } for (let i = 0; i < currentObject.data.events.length; i++) { currentEvent = currentObject.data.events[i].event action = currentObject.data.events[i].action if (currentEvent == 'click') { newNode.addEventListener('click', { do: action, handleEvent: function() { this.do() } }) } if (currentEvent == 'resize') { window.addEventListener('resize', { do: action, handleEvent: function() { this.do() } }) } else if (currentEvent == 'key') { newNode.addEventListener('keydown', { do: action, handleEvent: function(event) { this.do(true, event.key) } }) newNode.addEventListener('keyup', { do: action, handleEvent: function(event) { this.do(false, event.key) } }) } else if (currentEvent == 'mouse') { target.addEventListener('mouseover', { do: action, handleEvent: function() { this.do(true) } }) target.addEventListener('mouseenter', { do: action, handleEvent: function() { this.do(true) } }) target.addEventListener('mouseout', { do: action, handleEvent: function() { this.do(false) } }) target.addEventListener('mouseleave', { do: action, handleEvent: function() { this.do(false) } }) } } return newNode } function propertyToValue() { nodes = self.cobalt.document.root.querySelectorAll('*') for (let i = 0; i < nodes.length; i++) { nodes[i].value = nodes[i].getAttribute('value') } } function exportProperties() { for (let i = 0; i < self.cobalt.object.objects.length; i++) { id = self.cobalt.object.objects[i].id nodes = self.cobalt.document.root.querySelectorAll('*') for (let ii = 0; ii < nodes.length; ii++) { if (nodes[ii].getAttribute('cobalt') == id) { for (let iii = 0; iii < self.cobalt.object.objects[i].data.properties.length; iii++) { nodes[ii].setAttribute(self.cobalt.object.objects[i].data.properties[iii][0], self.cobalt.object.objects[i].data.properties[iii][1]) } } } } } } } if (!(x === undefined)) { try { x(self.cobalt) } catch(exception) { console.log('[Cobalt] ERROR | An error occured in the executed script.\n=> ', exception) } } }