Skip to content
This repository was archived by the owner on Jan 19, 2022. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 1 addition & 57 deletions examples/alternate-publisher.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,63 +12,7 @@

<script src="../js/require-config.js"></script>
<script src="../js/require.min.js"></script>
<script>
// Alternate publisher implementation that publishes to a hackpub
// endpoint. For more information, see:
//
// https://github.com/hackasaurus/hackpub
//
// Note also that the Amazon S3 bucket hackpub publishes to must
// be configured with a CORS configuration that allows for cross-origin
// GET requests, e.g.:
//
// <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
// <CORSRule>
// <AllowedOrigin>*</AllowedOrigin>
// <AllowedMethod>GET</AllowedMethod>
// </CORSRule>
// </CORSConfiguration>

define("hackpub", ["jquery"], function($) {
return function Hackpub(options) {
return {
loadCode: function(path, cb) {
var url = options.publishURL + path;
$.ajax({
type: "GET",
url: url,
dataType: 'text',
error: function(req) {
cb(req);
},
success: function(html) {
cb(null, html, url);
}
});
},
saveCode: function(data, originalURL, cb) {
$.ajax({
type: "POST",
url: options.hackpubURL + "/publish",
data: {
'html': data,
'original-url': originalURL
},
dataType: 'json',
error: function(req) {
cb(req);
},
success: function(result) {
var url = result['published-url'];
var path = '/' + url.match(/\/([A-Za-z0-9]+)$/)[1];
cb(null, {path: path, url: options.publishURL + path});
}
});
}
};
};
});
</script>
<script src="hackpub.js"></script>
<script>
require([
"jquery",
Expand Down
55 changes: 55 additions & 0 deletions examples/hackpub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Alternate publisher implementation that publishes to a hackpub
// endpoint. For more information, see:
//
// https://github.com/hackasaurus/hackpub
//
// Note also that the Amazon S3 bucket hackpub publishes to must
// be configured with a CORS configuration that allows for cross-origin
// GET requests, e.g.:
//
// <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
// <CORSRule>
// <AllowedOrigin>*</AllowedOrigin>
// <AllowedMethod>GET</AllowedMethod>
// </CORSRule>
// </CORSConfiguration>

define("hackpub", ["jquery"], function($) {
return function Hackpub(options) {
return {
loadCode: function(path, cb) {
var url = options.publishURL + path;
$.ajax({
type: "GET",
url: url,
dataType: 'text',
error: function(req) {
cb(req);
},
success: function(html) {
cb(null, html, url);
}
});
},
saveCode: function(data, originalURL, cb) {
$.ajax({
type: "POST",
url: options.hackpubURL + "/publish",
data: {
'html': data,
'original-url': originalURL
},
dataType: 'json',
error: function(req) {
cb(req);
},
success: function(result) {
var url = result['published-url'];
var path = '/' + url.match(/\/([A-Za-z0-9]+)$/)[1];
cb(null, {path: path, url: options.publishURL + path});
}
});
}
};
};
});
38 changes: 38 additions & 0 deletions examples/sandboxed-alternate-publisher.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html class="deployment-type-development">
<head>
<meta charset="utf-8">
<base target="_blank">

<title>Sandboxed Alternate Publisher Friendlycode Editor</title>
<link rel="stylesheet" href="../css/friendlycode.css">
</head>
<body style="margin: 0">
<div id="bare-fc-holder" class="friendlycode-loading"></div>

<script src="../js/require-config.js"></script>
<script src="../js/require.min.js"></script>
<script src="hackpub.js"></script>
<script>
require([
"jquery",
"friendlycode",
"hackpub",
"fc/ui/live-preview-sandbox"
], function($, FriendlycodeEditor, Hackpub, LivePreview) {
return FriendlycodeEditor({
allowJS: true,
publisher: Hackpub({
hackpubURL: "http://hackpub.hackasaurus.org",
publishURL: "http://poof.hksr.us"
}),
container: $("#bare-fc-holder"),
makeLivePreview: function(options) {
options.sandboxURL = "http://friendlycode-live-preview-sandbox.toolness.org/templates/live-preview-sandbox.html";
return LivePreview(options);
}
});
});
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion js/fc/ui/editor-panes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ define(function(require) {
div = options.container,
initialValue = options.value || "",
allowJS = options.allowJS || false,
makeLivePreview = options.makeLivePreview || LivePreview,
sourceCode = $('<div class="source-code"></div>').appendTo(div),
previewArea = $('<div class="preview-holder"></div>').appendTo(div),
helpArea = $('<div class="help hidden"></div>').appendTo(div),
Expand Down Expand Up @@ -51,7 +52,7 @@ define(function(require) {
errorArea: errorArea,
relocator: relocator
});
var preview = self.preview = LivePreview({
var preview = self.preview = makeLivePreview({
codeMirror: codeMirror,
ignoreErrors: true,
previewArea: previewArea
Expand Down
3 changes: 2 additions & 1 deletion js/fc/ui/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ define([
var panes = EditorPanes({
container: panesDiv,
value: value,
allowJS: options.allowJS
allowJS: options.allowJS,
makeLivePreview: options.makeLivePreview
});
var toolbar = EditorToolbar({
container: toolbarDiv,
Expand Down
86 changes: 86 additions & 0 deletions js/fc/ui/live-preview-sandbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use strict";

// Displays the HTML source of a CodeMirror editor as a rendered preview
// in an iframe.
define(function(require) {
var $ = require("jquery"),
BackboneEvents = require("backbone-events"),
Channel = require("jschannel");

function LivePreviewSandbox(options) {
var self = {
codeMirror: options.codeMirror,
title: "",
inEditor: true,
channel: null
},
codeMirror = options.codeMirror,
sandboxURL = options.sandboxURL,
readyToSendLatestReparse = false,
iframeSandbox,
channel,
latestReparse;

if (!sandboxURL)
sandboxURL = require.toUrl("templates/live-preview-sandbox.html");

function sendLatestReparse() {
channel.call({
method: "setHTML",
params: {
error: latestReparse.error,
sourceCode: latestReparse.sourceCode
},
error: function(e) {
if (window.console)
window.console.log("setHTML() error", e);
readyToSendLatestReparse = true;
},
success: function(v) {
readyToSendLatestReparse = true;
}
});
}

function setupIframeSandbox() {
iframeSandbox = document.createElement("iframe");
iframeSandbox.setAttribute("src", sandboxURL);
options.previewArea.append(iframeSandbox);
channel = Channel.build({
window: iframeSandbox.contentWindow,
origin: "*",
scope: "friendlycode",
onReady: function() {
sendLatestReparse();
self.trigger("channel:ready", self);
}
});
channel.bind("change:title", function(trans, title) {
self.trigger("change:title", title);
});
self.channel = channel;
self.trigger("channel:created", self);
}

codeMirror.on("reparse", function(event) {
var isPreviewInDocument = $.contains(document.documentElement,
options.previewArea[0]);
if (!isPreviewInDocument) {
if (window.console)
window.console.log("reparse triggered, but preview area is not " +
"attached to the document.");
return;
}
if (!iframeSandbox)
setupIframeSandbox();
latestReparse = event;
if (readyToSendLatestReparse)
sendLatestReparse();
});

BackboneEvents.mixin(self);
return self;
};

return LivePreviewSandbox;
});
85 changes: 41 additions & 44 deletions js/fc/ui/preview-to-editor-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ define(["jquery", "./mark-tracker"], function($, MarkTracker) {
return ' > ' + parts.join(' > ');
}

function nodeToCode(node, docFrag) {
var parallelNode = getParallelNode(node, docFrag);
function nodeToCode(parallelNode) {
var result = null;
if (parallelNode) {
var pi = parallelNode.parseInfo;
Expand All @@ -35,62 +34,60 @@ define(["jquery", "./mark-tracker"], function($, MarkTracker) {
return result;
}

function getParallelNode(node, docFrag) {
var root, i;
var htmlNode = docFrag.querySelector("html");
var origDocFrag = docFrag;
var parallelNode = null;
if (htmlNode && docFrag.querySelector("body")) {
root = node.ownerDocument.documentElement;
} else {
if (!htmlNode) {
docFrag = document.createDocumentFragment();
htmlNode = document.createElement("html");
docFrag.appendChild(htmlNode);
for (i = 0; i < origDocFrag.childNodes.length; i++)
htmlNode.appendChild(origDocFrag.childNodes[i]);
}
root = node.ownerDocument.body;
}
var path = "html " + pathTo(root, node);
parallelNode = docFrag.querySelector(path);
if (origDocFrag != docFrag) {
for (i = 0; i < htmlNode.childNodes.length; i++)
origDocFrag.appendChild(htmlNode.childNodes[i]);
}
return parallelNode;
}

function PreviewToEditorMapping(livePreview) {
function initParent(livePreview) {
var codeMirror = livePreview.codeMirror;
var docFrag = null;
var marks = MarkTracker(codeMirror);
$(".CodeMirror-lines", codeMirror.getWrapperElement())
.on("mouseup", marks.clear);
livePreview.on("channel:created", function() {
livePreview.channel.bind("ptem:highlight", function(trans, params) {
marks.clear();
if (!docFrag) return;
var element = docFrag.querySelector(params);
if (!element) return;
var interval = nodeToCode(element);
if (!interval) return;
var start = codeMirror.posFromIndex(interval.start);
var end = codeMirror.posFromIndex(interval.end);
var contentStart = codeMirror.posFromIndex(interval.contentStart);
var startCoords = codeMirror.charCoords(start, "local");
codeMirror.scrollTo(startCoords.x, startCoords.y);
marks.mark(interval.start, interval.end,
"preview-to-editor-highlight");
codeMirror.focus();
});
});
codeMirror.on("reparse", function(event) {
docFrag = event.document;
marks.clear();
});
}

function initChild(livePreview) {
livePreview.on("refresh", function(event) {
var docFrag = event.documentFragment;
marks.clear();
$(event.window).on("mousedown", function(event) {
marks.clear();
var tagName = event.target.tagName.toLowerCase();
var interval = null;
if (tagName !== "html" && tagName !== "body")
interval = nodeToCode(event.target, docFrag);
if (interval) {
var start = codeMirror.posFromIndex(interval.start);
var end = codeMirror.posFromIndex(interval.end);
var contentStart = codeMirror.posFromIndex(interval.contentStart);
var startCoords = codeMirror.charCoords(start, "local");
codeMirror.scrollTo(startCoords.x, startCoords.y);
marks.mark(interval.start, interval.end,
"preview-to-editor-highlight");
codeMirror.focus();
event.preventDefault();
event.stopPropagation();
if (tagName !== "html" && tagName !== "body") {
var htmlElement = event.target.ownerDocument.documentElement;
livePreview.channel.notify({
method: "ptem:highlight",
params: "html " + pathTo(htmlElement, event.target)
});
}
});
});
}

function PreviewToEditorMapping(livePreview) {
if (livePreview.inEditor)
initParent(livePreview);
else
initChild(livePreview);
}

PreviewToEditorMapping._pathTo = pathTo;
PreviewToEditorMapping._nodeToCode = nodeToCode;

Expand Down
3 changes: 2 additions & 1 deletion js/friendlycode.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ define(function(require) {
location.pathname + "#{{VIEW_URL}}",
editor = Editor({
container: options.container,
allowJS: options.allowJS
allowJS: options.allowJS,
makeLivePreview: options.makeLivePreview
}),
ready = $.Deferred();

Expand Down
Loading