// Simulate the bare minimum of the view that exists on the main site var Scratch = Scratch || {}; Scratch.FlashApp = Scratch.FlashApp || {}; var editorId = "scratch"; var initialPage = "home"; var ShortURL = { key : "AIzaSyBlaftRUIOLFVs8nfrWvp4IBrqq9-az46A", api : "https://www.googleapis.com/urlshortener/v1/url", domain : "http://goo.gl" } function handleEmbedStatus(e) { $('#scratch-loader').hide(); var scratch = $(document.getElementById(editorId)); if (!e.success) { scratch.css('marginTop', '10'); scratch.find('IMG.proj_thumb').css('width', '179px'); scratch.find('DIV.scratch_unsupported').show(); scratch.find('DIV.scratch_loading').hide(); } else { Scratch.FlashApp.ASobj = scratch[0]; Scratch.FlashApp.$ASobj = $(Scratch.FlashApp.ASobj); } } // enables the SWF to log errors function JSthrowError(e) { if (window.onerror) window.onerror(e, 'swf', 0); else console.error(e); } function JSeditorReady() { try { handleParameters(); Scratch.FlashApp.$ASobj.trigger("editor:ready"); return true; } catch (error) { console.error(error.message, "\n", error.stack); throw error; } } function JSprojectLoaded() { loadExtensionQueue(); } function JSshowExtensionDialog() { showModal(["template-extension-file", "template-extension-url"]); } var extensionQueue = []; function handleParameters() { var project; var queryString = window.location.search.substring(1); var queryVars = queryString.split(/[&;]/); for (var i = 0; i < queryVars.length; i++) { var nameVal = queryVars[i].split('='); switch(nameVal[0]){ case 'ext': extensionQueue.push(nameVal[1]); break; case 'proj': project = nameVal[1]; break; } } if (project) { Scratch.FlashApp.ASobj.ASloadSBXFromURL(project); } else { loadExtensionQueue(); } } function loadExtensionQueue() { for (var i = 0; i < extensionQueue.length; ++i) { var extensionURL = extensionQueue[i]; ScratchExtensions.loadExternalJS(extensionURL); } extensionQueue = []; } var flashVars = { autostart: 'false', extensionDevMode: 'true', server: encodeURIComponent(location.host), cloudToken: '4af4863d-a921-4004-b2cb-e0ad00ee1927', cdnToken: '34f16bc63e8ada7dfd7ec12c715d0c94', urlOverrides: { sitePrefix: "http://scratch.mit.edu/", siteCdnPrefix: "http://cdn.scratch.mit.edu/", assetPrefix: "http://assets.scratch.mit.edu/", assetCdnPrefix: "http://cdn.assets.scratch.mit.edu/", projectPrefix: "http://projects.scratch.mit.edu/", projectCdnPrefix: "http://cdn.projects.scratch.mit.edu/", internalAPI: "internalapi/", siteAPI: "site-api/", staticFiles: "scratchr2/static/" }, inIE: (navigator.userAgent.indexOf('MSIE') > -1) }; var params = { allowscriptaccess: 'always', allowfullscreen: 'true', wmode: 'direct', menu: 'false' }; $.each(flashVars, function (prop, val) { if ($.isPlainObject(val)) flashVars[prop] = encodeURIComponent(JSON.stringify(val)); }); swfobject.switchOffAutoHideShow(); swfobject.embedSWF('Scratch.swf', 'scratch', '100%', '100%', '11.7.0', 'libs/expressInstall.swf', flashVars, params, null, handleEmbedStatus); /* File uploads */ function sendFileToFlash(file) { /* * Use the HTML5 FileReader API to send base-64 encoded file * contents to Flash via ASloadBase64SBX (or do it when the SWF * is ready). */ var fileReader = new FileReader(); fileReader.onload = function (e) { var fileAsB64 = ab_to_b64(fileReader.result); if (Scratch.FlashApp.ASobj.ASloadBase64SBX !== undefined) { $(document).trigger("editor:extensionLoaded", {method: "file"}); showPage(editorId); Scratch.FlashApp.ASobj.ASloadBase64SBX(fileAsB64); } else { $(document).on("editor:ready", function(e) { $(document).trigger("editor:extensionLoaded", {method: "file"}); showPage(editorId); Scratch.FlashApp.ASobj.ASloadBase64SBX(fileAsB64); $(this).off(e); }); } } fileReader.readAsArrayBuffer(file); } function sendURLtoFlash() { /* * Send a URL to Flash with ASloadGithubURL, or do it when the * editor is ready. */ var urls = []; for (var i = 0; i < arguments.length; i++) { urls.push(arguments[i]); } if (urls.length <= 0) return; if (Scratch.FlashApp.ASobj.ASloadGithubURL !== undefined) { $(document).trigger("editor:extensionLoaded", {method: "url", urls: urls}); showPage(editorId); Scratch.FlashApp.ASobj.ASloadGithubURL(urls); } else { $(document).on("editor:ready", function(e) { $(document).trigger("editor:extensionLoaded", {method: "url", urls: urls}); showPage(editorId); Scratch.FlashApp.ASobj.ASloadGithubURL(urls); $(this).off(e); }); } } /* Load from URL */ function loadFromURLParameter(queryString) { /* * Get all url=urlToLoad from the querystring and send to Flash * Use like... * http://scratchx.org/?url=urlToLoad1&url=urlToLoad2 */ var paramString = queryString.replace(/^\?|\/$/g, ''); var vars = paramString.split("&"); var showedEditor = false; var urls = []; for (var i=0; i 1 && pair[0]=="url") { urls.push(pair[1]); } } if (urls.length > 0) sendURLtoFlash.apply(window, urls); } /* Modals */ function getOrCreateFromTemplate(elementId, templateId, elementType, appendTo, wrapper, data) { elementType = elementType || "div"; appendTo = appendTo || "body"; data = data || {}; var $element = $(document.getElementById(elementId)); if (!$element.length) { var templateContent = ""; if (typeof(templateId) != "string") { for (var id in templateId) { templateContent += $(document.getElementById(templateId[id])).html(); } } else { templateContent += $(document.getElementById(templateId)).html() } $template = _.template(templateContent); $element = $("<"+elementType+">") .attr("id", elementId) .html($template(data)); if (wrapper) $element.wrapInner(wrapper); $element.appendTo(appendTo) } return $element; }; function showModal(templateId, data) { /* * Copies the HTML referenced by data-template into a new element, * with id="modal-[template value]" and creates an overlay on the * page, which when clicked will close the popup. */ var zIndex = 100; var modalId = ("modal-" + templateId).replace(",", "-"); $modalwrapper = $(""); var $modal = getOrCreateFromTemplate(modalId, templateId, "dialog", "body", $modalwrapper, data); $modal.addClass("modal"); $(".modal-fade-screen", $modal) .addClass("visible") .click(function(e){if ($(e.target).is($(this))) $(this).trigger("modal:exit")}); $(".modal-close", $modal).click(function(e){ e.preventDefault(); $(document).trigger("modal:exit") }); $("body").addClass("modal-open"); $(document).one("modal:exit page:show editor:extensionLoaded", function(e){ $("body").removeClass("modal-open"); Scratch.FlashApp.ASobj.ASsetModalOverlay(false); $modal.remove(); }); return $modal; } $(document).keyup(function(e) { // Exit modals with esc key if (e.keyCode == 27) $(document).trigger("modal:exit"); }); $(document).on("modal:exit", function(e){Scratch.FlashApp.ASobj.ASsetModalOverlay(false);}); $(document).on('click', "[data-action='modal']", function(e){ /* * Usage: * Popup */ e.preventDefault(); showModal($(this).data("template")); }); function JSshowWarning(extensionData) { $modal = showModal("template-warning", extensionData); $("button", $modal).click(function(e){ e.preventDefault(); $(document).trigger("modal:exit") }); return $modal; } /* Page switching */ function showPage(path, force) { /* Show a part of the page. The site is set up like body main article#home article#privacy-policy ... editor Each
is a "page" of the site, plus one special view, which is the editor. The editor is not actually hidden, but located -9999px above the viewport. This is because if it's hidden, it doesn't load when the page is loaded. So first we have to hide everything that we're not going to show or move the editor up, then display everything we're going to show if it's hidden. If we are linking to an anchor within a page, then show its parent. */ var toHide = "body > main, body > main > article"; var toShow = "#" + path; var $toShow = $(toShow); var showEditor = $toShow.is(Scratch.FlashApp.$ASobj); var editorShown = parseInt(Scratch.FlashApp.$ASobj.css("top")) == 0; if (!$toShow.length || (!showEditor && $toShow.filter(":visible").length > 0) || (showEditor && editorShown)) return; if (editorShown && !force) { Scratch.FlashApp.ASobj.AScreateNewProject(["showPage", path, true]); return; } $(toHide).filter(":visible").hide(); if (!showEditor && editorShown) $(document.getElementById(editorId)).css({top: "-9999px"}); $("body > main, body > main > article").has($toShow).show(); setBodyClass(path); $toShow.show(); if (showEditor) $toShow.css({top: 0}); if (document.location.hash.substr(1) != path) document.location.hash = path; $toShow[0].scrollIntoView(true); $(document).trigger("page:show", path); } function setBodyClass(path) { var pageClassPrefix = "page-"; var currentPageClasses = ($("body").attr("class") || "").split(" "); for (c in currentPageClasses) { if (currentPageClasses[c].indexOf(pageClassPrefix) != -1) { $("body").removeClass(currentPageClasses[c]); } } $("body").addClass(pageClassPrefix + path); } /* URL Shortening */ function shorten(url, done) { var data = {longUrl: url}; $.ajax({ url : ShortURL.api + '?' + $.param({key : ShortURL.key}), type : "post", data : JSON.stringify(data), dataType : "json", contentType : "application/json" }).done(done); } function getUrlFor(extensions) { return document.location.origin + '/?' + $.param( extensions.map(function(url){ return {name: 'url', value: url} }) ); } function UrlParser(url) { parser = document.createElement('a'); parser.href = url; return parser } function showShortUrl(url) { shorten(url, function(data) { var parser = UrlParser(data.id); var id = parser.pathname.replace('/', ''); parser.href = window.location.origin; parser.hash = "#!" + id; var shortUrl = parser.href; var context = { longUrl : data.longUrl, shortUrl : shortUrl } $modal = showModal("template-short-url", context); var client = new ZeroClipboard($('button', $modal)); }); } function JSshowShortUrlFor() { showShortUrl(getUrlFor(Array.prototype.slice.call(arguments))); } function decompress(id, done) { var data = {shortUrl: ShortURL.domain + id} $.ajax({ url : ShortURL.api + '?' + $.param({ key : ShortURL.key, shortUrl : ShortURL.domain + '/' + id}), dataType : "json", contentType : "application/json" }).done(done); } /* Setup */ $(document).on('click', "[data-action='load-file']", function(e) { /* Buttons with data-action="load-file" trigger a file input prompt, passed to a handler that passes the file to Flash. */ $('').on('change', function(){ sendFileToFlash(this.files[0]) }).click(); }); $(document).on('click', "[data-action='load-url']", function(e) { /* Links with data-action="load-url" send their href to Flash So use like... Load this */ e.preventDefault(); showPage(editorId); loadFromURLParameter($(this).attr("href")); }); $(document).on('submit', ".url-load-form", function(e) { // Load text input value on submit e.preventDefault() showPage(editorId); sendURLtoFlash($('input[type="text"]', this).val()); }); $(document).on('click', "[data-action='show']", function(e) { /* Links with data-action="static-link" should switch the view to that page. Works like tabs sort of. Use like... Privacy Policy */ var path = $(this).data('target') || $(this).attr("href").substring(1); showPage(path); }); $(window).on('hashchange', function(e) { var path = document.location.hash.split('#')[1] || document.location.hash || 'home'; if (path.charAt(0) != '!') showPage(path); }); $(document).on("page:show", function(e, page){ ga("send", "pageview", '#' + page); ga("set", "referrer", document.location.origin + document.location.pathname + document.location.hash) }); $(document).on("editor:extensionLoaded", function(e, data){ if (data.method == "url") { for (var i = 0; url = data['urls'][i]; i++) { ga("send", "event", "extensionLoaded", data.method, url); } } else { ga("send", "event", "extensionLoaded", data.method); } }); function initPage() { /* On load, show the page identified by the URL fragment. Default to #home. */ if (window.location.hash) { if (window.location.hash.charAt(1) == "!") { decompress(window.location.hash.substr(2), function(data) { var parser = UrlParser(data.longUrl); if (parser.hostname == window.location.hostname) window.location = data.longUrl; return; }); } else { initialPage = window.location.hash.substr(1); } } setBodyClass(initialPage); showPage(initialPage, true); loadFromURLParameter(window.location.search, true); } $(initPage);