// 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("editorReady"); return true; } catch (error) { console.error(error.message, "\n", error.stack); throw error; } } function JSprojectLoaded() { loadExtensionQueue(); } function JSshowExtensionDialog() { showModal("dialogs"); } 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); showPage(editorId); if (Scratch.FlashApp.ASobj.ASloadBase64SBX !== undefined) { Scratch.FlashApp.ASobj.ASloadBase64SBX(fileAsB64); } else { $(document).on("editorReady", function(e) { Scratch.FlashApp.ASobj.ASloadBase64SBX(fileAsB64); $(this).off(e); }); } } fileReader.readAsArrayBuffer(file); } var loadFileListener = 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(); } 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) { Scratch.FlashApp.ASobj.ASloadGithubURL(urls); } else { $(document).on("editorReady", function(e) { Scratch.FlashApp.ASobj.ASloadGithubURL(urls); $(this).off(e); }); } } /* Load from URL */ var loadURLlistener = 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")); } var loadURLformListener = function(e) { // Load text input value on submit e.preventDefault(); showPage(editorId); sendURLtoFlash($('input[type="text"]', this).val()); } 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) { $template = _.template($(document.getElementById(templateId)).html()); $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; $modalwrapper = $(""); var $modal = getOrCreateFromTemplate(modalId, templateId, "dialog", "body", $modalwrapper, data); $modal.addClass("modal"); $(".modal-fade-screen", $modal) .addClass("visible") .click(function(e){$(this).trigger("modal:exit")}); $("body").addClass("modal-open"); attachListeners(); var triggerExit = function (e) {$(this).trigger("modal:exit");} $(".modal-inner", $modal).click(function(e){e.stopPropagation();}) $(document).on("click", "[data-action='load-file'], [data-action='load-url'], [data-action='show']", triggerExit); $(document).on("submit", ".url-load-form", triggerExit) $(document).on("modal:exit", function(){ $("body").removeClass("modal-open"); Scratch.FlashApp.ASobj.ASsetModalOverlay(false); $modal.remove(); $(this).off(); }); 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"); $("button, .modal-close", $modal).click(function(e){ e.preventDefault(); $(document).trigger("modal:exit") }); } /* Page switching */ var showClickListener = 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).attr("href").substring(1); showPage(path); }; $(window).bind('hashchange', function(e) { if (document.location.hash == '') showPage('home'); }); 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(); $toShow.show(); if (showEditor) $toShow.css({top: 0}); if (document.location.hash.substr(1) != path) document.location.hash = 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 */ function attachListeners(){ $("[data-action='load-file']").on('click', loadFileListener); $("[data-action='load-url']").on('click', loadURLlistener); $(".url-load-form").on('submit', loadURLformListener); $("[data-action='show']").on('click', showClickListener); } function initPage() { /* * On load, show the page identified by the URL fragment. Default to #home. */ attachListeners(); 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); } } showPage(initialPage, true); loadFromURLParameter(window.location.search, true); } $(initPage);