'use strict'; window.onerror = function(error, url) { if (!url) { document.onreadystatechange = function() { if (document.readyState == 'complete') { var logo = new Image(); logo.onload = function() { var warning = document.createElement('div'); warning.innerHTML = 'Please open this file over HTTP.'; warning.style.margin = '16px'; document.body.appendChild(warning); } logo.src = 'source/Ox.UI/themes/classic/png/logo128.png'; document.body.style.backgroundColor = 'rgb(224, 224, 224)'; document.body.style.color = 'rgb(64, 64, 64)'; document.body.style.fontFamily = [ 'Lucida Grande', 'Segoe UI', 'DejaVu Sans', 'Lucida Sans Unicode', 'Helvetica', 'Arial', 'sans-serif' ].join(', '); document.body.style.fontSize = '13px'; document.body.style.margin = Math.floor( window.innerHeight / 2 ) - 128 + 'px'; document.body.style.textAlign = 'center'; document.body.appendChild(logo); } }; } }; Ox.load(/^https?:\/\/(www\.)?oxjs\.org\//.test( window.location.href ), function() { var app = window.oxjs = { $ui: {}, animate: function() { var home = app.url.parse().page == ''; app.state.animating = true; if (home) { app.$ui.logo.attr({src: app.getSRC('logo')}); app.$ui.screen.show(); app.$ui.label.show(); app.$ui.menu.options({value: ''}).show(); } else { app.$ui.menu.options({value: app.user.page}); } app.$ui.panel.find('.OxButtonGroup').css({opacity: 0}); [ 'screen', 'logo', 'label', 'menu', 'switch' ].forEach(function(element) { app.$ui[element].stop().animate( app.getCSS(element), 500, element == 'screen' ? function() { if (!home) { app.$ui.logo.attr({src: app.getSRC('logo')}); app.$ui.panel.find('.OxButtonGroup').css({ opacity: 1 }); app.$ui.screen.hide(); app.$ui.label.hide(); app.$ui.menu.hide().options({value: ''}); } app.state.animating = false; } : void 0 ); }); }, data: { downloads: {}, html: {}, pages: [ {id: 'about', title: 'About'}, {id: 'readme', title: 'Readme'}, {id: 'examples', title: 'Examples'}, {id: 'doc', title: 'Documentation'}, {id: 'download', title: 'Download'}, {id: 'development', title: 'Development'} ], user: { item: {doc: '', examples: '', readme: ''}, page: '', previousPage: 'about', theme: 'classic' }, warning: 'Aw, snap! This website requires an up-to-date, ' + 'HTML5-compliant web browser. ' + 'It should work fine in current versions of ' + 'Chrome, ' + 'Firefox and ' + 'Safari, or ' + 'Internet Explorer with ' + '' + 'Chrome Frame installed. ' + 'To proceed at your own risk, click on the logo above.' }, db: Ox.localStorage('OxJS'), getCSS: function(element) { var css = {}, home = app.url.parse().page == '', center = Math.floor(window.innerWidth / 2), middle = Math.floor(window.innerHeight / 2); if (element == 'label') { css = home ? { top: middle + 16 + 'px', left: center - 128 + 'px', width: '242px', height: '16px', fontSize: '12px', opacity: 1, overflow: 'visible' } : { top: '35px', left: '4px', width: '40px', height: '4px', fontSize: '1px', opacity: 0 } } else if (element == 'loading') { css.top = middle + 52 + 'px' } else if (element == 'logo') { css = home || !app.state.loaded ? { left: center - 128 + 'px', top: middle - 128 + 'px', width: '256px', height: '128px', borderRadius: '32px' } : { top: '6px', left: '6px', width: '48px', height: '24px', borderRadius: '6px' }; } else if (element == 'menu') { css = home ? { top: middle + 56 + 'px', left: Math.ceil(center - app.$ui.menu.width() / 2) + 'px' } : { top: '6px', left: Math.ceil(center - app.$ui.menu.width() / 2) + 'px' }; } else if (element == 'screen') { css.opacity = home ? 1 : 0; } else if (element == 'switch') { css = home ? { top: middle + 96 + 'px', right: Math.floor(center - app.$ui.switch.width() / 2) + 'px' } : { top: '6px', right: '6px' }; } else if (element == 'warning') { css = { left: center - 128 + 'px', top: middle + 16 + 'px', }; } return css; }, getSRC: function(element) { return 'source/Ox.UI/themes/' + app.user.theme + '/' + { icon: 'png/icon16.png', loading: 'svg/symbolLoading.svg', logo: 'png/logo128.png' }[element]; }, init: function() { app.user = Ox.extend(app.data.user, app.db()); app.loadScreen(function() { app.loadData(function() { Ox.load('UI', {theme: app.user.theme}, app.load); }); }); }, load: function(browserSupported) { var data = app.url.parse(); app.user.page = data.page; if (data.item && data.page in app.user.item) { app.user.item[data.page] = data.item; } app.db(app.user); app.$ui.panel = app.ui.panel() .select(app.user.page) .appendTo(Ox.$body); // jquerify so that we can animate ['screen', 'logo', 'loading'].forEach(function(element) { app.$ui[element] = $('.' + element); }); app.$ui.loading.animate({opacity: 0}, 500, function() { app.$ui.loading.remove(); }); if (!browserSupported) { app.$ui.warning = app.ui.warning() .css(app.getCSS('warning')) .appendTo(Ox.$body); app.$ui.logo .css({cursor: 'pointer'}) .one({ click: function() { app.$ui.warning.remove(); app.load(true); } }); } else if (!data.page) { app.$ui.logo .css({cursor: 'pointer'}) .on({click: app.toggle}); ['label', 'menu', 'switch'].forEach(function(element) { app.$ui[element] = app.ui[element]() .css({opacity: 0}) .appendTo(Ox.$body); app.$ui[element] .css(app.getCSS(element)) .animate({opacity: 1}, 500); }); } else { ['label', 'menu', 'switch'].forEach(function(element) { app.$ui[element] = app.ui[element]().appendTo(Ox.$body); app.$ui[element].css(app.getCSS(element)).hide(); }); app.$ui.screen.animate({opacity: 0}, 500, function() { app.$ui.screen.hide(); }); app.$ui.logo.animate({opacity: 0}, 500, function() { app.$ui.logo .attr({src: app.getSRC('logo')}) .css(app.getCSS('logo')) .animate({opacity: 1}, 500, function() { app.$ui.logo .css({cursor: 'pointer'}) .on({click: app.toggle}); }); app.$ui.switch.css({opacity: 0}).show() .animate({opacity: 1}, 500); }); } Ox.$window.on({hashchange: app.url.change}); app.state.loaded = true; }, loadData: function(callback) { var q = '?' + Ox.random(1000000), url = '//oxjs.org/downloads/downloads.json' + q; Ox.getJSON('index.json' + q, function(data) { app.data = Ox.extend(app.data, data); app.data.pages.forEach(function(page) { var id = page.id == 'doc' ? 'documentation' : page.id; Ox.get('readme/index/' + id + '.html' + q, function(html) { app.data.html[id] = html; if (Ox.len(app.data.html) == app.data.pages.length) { navigator.onLine ? Ox.getJSON(url, function(data) { app.data.downloads = data; callback(); }) : callback(); } }); }); }); }, loadScreen: function(callback) { app.setTheme(app.user.theme); app.$ui.screen = app.ui.screen(); app.$ui.loading = app.ui.loading(); app.$ui.logo = app.ui.logo().one({ load: function() { Ox.$('body') .append(app.$ui.screen) .append(app.$ui.logo) .append(app.$ui.loading); app.rotate(); callback(); } }); Ox.$(window).on({resize: app.resize}); }, patchButtonGroup: function($buttonGroup) { $buttonGroup.find('.OxButton').css({ height: '22px', paddingLeft: '8px', paddingRight: '8px', fontSize: '13px' }).find('.OxButton:first-child').css({ borderTopLeftRadius: '6px', borderBottomLeftRadius: '6px' }).find('.OxButton:last-child').css({ borderTopRightRadius: '6px', borderBottomRightRadius: '6px' }); return $buttonGroup; }, re: { code: [ new RegExp( 'Ox' + '(\\.' + 'UI)?' + '\\.' + '([\\w\\$]+)<\\/span>', 'g' ), function(match) { var string = Ox.stripTags(match); return string == 'Ox.My' ? string : '' + match + ''; } ], comment: [ /\b(Ox\.[\w\$]+)/g, function(match) { return match == 'Ox.My' ? match : '' + match + '' } ], size: [ /\{size\.(\w+)\}/g, function(match, key) { return app.data.downloads.size ? ' (' + Ox.formatValue( app.data.downloads.size[key], 'B' ) + ')' : ''; } ], version: [ '{version}', function() { var version = app.data.downloads.version, current = 'You\'re currently running version ' + Ox.VERSION + '.', latest = version ? 'The latest version is ' + version + ' (' + app.data.downloads.date.slice(0, 10) + ').' : ''; return version ? latest + ( /^https?:\/\/(www\.)?oxjs\.org\//.test( window.location.href ) ? '' : version == Ox.VERSION ? ' You\'re up to date.' : ' ' + current ) : current; } ] }, resize: function() { [ 'logo', 'loading', 'label', 'menu', 'switch' ].forEach(function(element) { app.$ui[element] && app.$ui[element].css(app.getCSS(element)); }); }, rotate: function() { var css, deg = 0, previousTime = +new Date(), interval = setInterval(function() { var currentTime = +new Date(), delta = (currentTime - previousTime) / 1000, loadingIcon = document.getElementById('loadingIcon'); if (loadingIcon) { previousTime = currentTime; deg = Math.round((deg + delta * 360) % 360 / 30) * 30; css = 'rotate(' + deg + 'deg)'; loadingIcon.style.MozTransform = css; loadingIcon.style.MSTransform = css; loadingIcon.style.OTransform = css; loadingIcon.style.WebkitTransform = css; } else { clearInterval(interval); } }, 83); }, setTheme: function(theme) { app.user.theme = theme; app.db(app.user); (Ox.$('#icon') || Ox.$('').attr({ id: 'icon', rel: 'shortcut icon', type: 'image/png' }).appendTo(Ox.$('head'))).attr({ href: app.getSRC('icon') }); app.$ui.logo && app.$ui.logo .attr({src: app.getSRC('logo')}) .css(app.getCSS('logo')); Ox.Theme ? Ox.Theme(theme) : Ox.$('body').addClass('OxTheme' + Ox.toTitleCase(theme) ); }, state: { animating: false, loaded: false }, toggle: function() { !app.state.animating && app.url.push( app.url.parse().page ? { page: '', item: '' } : { page: app.user.previousPage, item: app.user.previousPage in app.user.item ? app.user.item[app.user.previousPage] : '' } ); }, ui: { doc: function() { return Ox.DocPanel({ element: $('
') .addClass('page') .css({ margin: '32px', width: window.innerWidth - 640 + 'px' }) .html(app.data.html.documentation), examples: app.data.docItems ? null : app.data.examples, examplesPath: app.data.docItems ? null : 'examples/', files: app.data.docItems ? null : app.data.documentation, getModule: function(item) { return item.file.replace(/^dev\//, '') .split('/')[0]; }, getSection: function(item) { return item.section || item.file.replace(/^dev\//, '') .split('/')[2].split('.')[0]; }, items: app.data.docItems || null, path: 'dev/', references: /\b(Ox\.[\w\$]+(?=\W))/g, replace: [app.re.code], results: app.data.testResults || null, selected: app.user.item.doc, showLoading: true, showTests: true }) .bindEvent({ example: function(data) { app.url.push({page: 'examples', item: data.id}); }, select: function(data) { app.url.push({item: data.id}); } }) .bindEventOnce({ load: function(data) { app.data.docItems = data.items; }, tests: function(data) { app.data.testResults = data.results; } }); }, examples: function() { return Ox.ExamplePanel({ element: $('
') .addClass('page') .css({ margin: '32px', width: window.innerWidth - 640 + 'px' }) .html(app.data.html.examples), examples: app.data.examples, mode: app.url.parse().mode || 'source', path: 'examples/', references: /\b(Ox\.[\w\$]+(?=\W))/g, replaceCode: [app.re.code], replaceComment: [app.re.comment], selected: app.user.item.examples }) .bindEvent({ change: function(data) { app.url.push({ mode: data.value == 'live' ? 'live' : '' }); }, select: function(data) { app.url.push({item: data.id}); } }); }, label: function() { return Ox.Label({ textAlign: 'center', title: 'A JavaScript Library for Web Applications', width: 256 }) .addClass('label animate') .css({ paddingTop: '4px', paddingBottom: '4px', borderRadius: '6px' }); }, loading: function() { return Ox.$('') .addClass('loading') .attr({id: 'loadingIcon', src: app.getSRC('loading')}) .css(app.getCSS('loading')); }, logo: function() { return Ox.$('') .addClass('logo animate') .attr({src: app.getSRC('logo')}) .css(app.getCSS('logo')); }, menu: function() { return app.patchButtonGroup( Ox.ButtonGroup({ buttons: app.data.pages, min: 0, selectable: true, }) .addClass('menu animate') .bindEvent({ change: function(data) { data.value && app.url.push({page: data.value}); } }) ); }, page: function(page, replace) { return Ox.Container().append( $('
').addClass('OxSelectable page').html( app.data.html[page] .replace(app.re.size[0], app.re.size[1]) .replace(app.re.version[0], app.re.version[1]) ) ); }, panel: function() { var $panel = Ox.TabPanel({ content: function(id) { return app.$ui[id] = app.ui[id] ? app.ui[id]() : app.ui.page(id); }, size: 36, tabs: app.data.pages }) .bindEvent({ change: function(data) { if (app.state.loaded) { app.url.push({page: data.selected}); } } }); app.patchButtonGroup( $panel.find('.OxButtonGroup').css({top: '6px'}) ); return $panel; }, readme: function() { var $list = Ox.Container() .css({overflowY: 'scroll'}) .on({ click: function(e) { var $target = $(e.target), $parent = $target.parent(); if ($parent.is('.item')) { $target = $parent; } selectItem( $target.is('.item') && ( $target.is(':not(.selected)') || !e.metaKey ) ? $target.attr('id') : '' ); } }), $text = Ox.Container() .addClass('OxSerif OxSelectable text'), $panel = Ox.SplitPanel({ elements: [ {element: $list, size: 256}, {element: $text} ], orientation: 'horizontal' }) .update(function(key, value) { key == 'selected' && selectItem(value); }) .addClass('readme'); Ox.sortBy(app.data.readme, '-date').forEach(function(item, i) { var $item = $('
') .addClass('item') .attr({id: item.id}) .css({width: 224 - Ox.UI.SCROLLBAR_SIZE + 'px'}) .appendTo($list); $('
') .addClass('OxSerif title') .html(item.title) .appendTo($item); $('
') .addClass('OxSerif OxLight date') .html(Ox.formatDate(item.date, '%B %e, %Y', true)) .appendTo($item); }); selectItem(app.user.item.readme); function selectItem(id) { if (id && !Ox.getObjectById(app.data.readme, id)) { id = ''; } $panel.find('.item.selected').removeClass('selected'); id && $panel.find('.item#' + id).addClass('selected'); Ox.get('readme/' + ( id || 'index/readme' ) + '.html?' + Math.random(1000000), function(html) { $text.empty() .append( id ? html : $('
') .addClass('page') .css({ margin: '16px', width: window.innerWidth - 640 + 'px' }) .html(html) ) .find('.code').each(function() { var $this = $(this); $this.replaceWith( Ox.SyntaxHighlighter({ source: $this.text() }) .attr({id: $this.attr('id')}) ); }); }); app.url.push({item: id}); } return $panel; }, screen: function() { return Ox.$('
').addClass('screen animate'); }, switch: function() { return app.patchButtonGroup( Ox.ButtonGroup({ buttons: [ {id: 'classic', title: 'Light'}, {id: 'modern', title: 'Dark'} ], selectable: true, value: app.user.theme }) .addClass('switch animate') .bindEvent({ change: function(data) { app.setTheme(data.value); } }) ); }, warning: function() { return $('
').addClass('warning').html(app.data.warning); } }, url: { change: function() { var data = app.url.parse(); app.user.previousPage = app.user.page; app.user.page = data.page; if (data.page in app.user.item) { app.user.item[data.page] = data.item; } app.db(app.user); if (app.user.page != app.user.previousPage) { app.$ui.panel.select(app.user.page); } if (app.user.page) { app.$ui[app.user.page].options(Ox.extend({ selected: data.item }, app.user.page == 'examples' ? { mode: data.mode || 'source' } : {})); } if (!app.user.page || !app.user.previousPage) { app.animate(); } }, format: function(data) { var hash = ''; if (data.page) { hash = '#' + data.page; if (data.item && data.page in app.user.item) { hash += '/' + data.item; if (data.page == 'examples' && data.mode == 'live') { hash += '/live'; } } } return hash; }, parse: function(hash) { hash = hash || window.location.hash; var data = {}, formattedHash, split = hash.slice(1).split('/'); data.page = Ox.getObjectById(app.data.pages, split[0]) ? split[0] : ''; data.item = data.page in app.user.item && split[1] ? split[1] : ''; data.mode = data.page == 'examples' && split[2] == 'live' ? 'live' : ''; formattedHash = app.url.format(data); hash != formattedHash && app.url.replace(formattedHash); return data; }, push: function(data) { data = data || {}; data.page = 'page' in data ? data.page : app.user.page; data.item = 'item' in data ? data.item : app.user.item[data.page] || ''; window.location.hash = app.url.format(data); return app; }, replace: function(hash) { var location = window.location; if (history.replaceState) { history.replaceState( {}, '', location.origin + location.pathname + hash ); } return app; } }, user: {} }; app.init(); });