closeheat-editor
Version:
Edit deployed websites.
1,684 lines (1,500 loc) • 6.06 MB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var $, ChangeDistDirToast, Filesystem, Header, Navigation, NewApp, Promise, React, RouteHandler, Router, _, cookies, flatten, request;
React = require('react');
flatten = require('flat');
_ = require('lodash');
$ = window.jQuery = window.$ = require('jquery');
request = require('request');
Promise = require('bluebird');
cookies = require('browser-cookies');
require('./materialize');
Router = require('react-router');
RouteHandler = Router.RouteHandler;
Navigation = Router.Navigation;
Header = require('./header');
Filesystem = require('./filesystem');
NewApp = require('./new_app');
ChangeDistDirToast = require('./change_dist_dir_toast');
module.exports = React.createClass({
getInitialState: function() {
this.bindKeys();
track('loaded', {
ch_initial_referrer: cookies.get('ch_initial_referrer')
});
return {
clean_files: _.cloneDeep(Filesystem.ls()),
action_in_progress: false,
first_build_done: false,
show_free_hosting: false,
show_change_dist_dir: !this.props.is_demo_app && this.props.first_build,
dist_dir: this.props.dist_dir
};
},
componentDidMount: function() {
if (this.props.is_demo_app) {
return this.showCodeGuide();
}
},
showCodeGuide: function() {
Materialize.toast("We created a simple demo website for you. Here's the code.", 10000);
return setTimeout((function() {
return Materialize.toast("Click <span class='guide-button'>Preview</span> to see how it looks.", 10000);
}), 4000);
},
showFreeHosting: function() {
return this.setState({
show_free_hosting: true
});
},
hideFreeHosting: function() {
return this.setState({
show_free_hosting: false,
free_hosting_shown: true
});
},
bindKeys: function() {
return $(window).bind('keydown', (function(_this) {
return function(event) {
if (!(event.ctrlKey || event.metaKey)) {
return;
}
switch (String.fromCharCode(event.which).toLowerCase()) {
case 's':
event.preventDefault();
return _this.previewClick();
case 'e':
event.preventDefault();
return _this.codeClick();
}
};
})(this));
},
mixins: [Navigation],
editorChange: function(path, new_content) {
return Filesystem.write(path, new_content);
},
codeClick: function() {
track('code_clicked');
return this.transitionWithCodeModeHistory('code', '/code/*?');
},
previewClick: function() {
track('preview_clicked');
if (this.state.action_in_progress) {
return;
}
if (this.context.router.getCurrentPath().match(/^\/preview/)) {
return this.buildOrRefresh();
} else {
return this.transitionWithCodeModeHistory('preview', 'preview-with-history');
}
},
transitionWithCodeModeHistory: function(route, with_history_route) {
track('transitioned_to', {
route: route
});
if (_.isEmpty(this.context.router.getCurrentParams())) {
return this.transitionTo(route);
} else {
return this.transitionTo(with_history_route, this.context.router.getCurrentParams());
}
},
publishClick: function() {
track('publish_clicked');
if (this.state.action_in_progress) {
return;
}
return this.transitionWithCodeModeHistory('publish', '/publish/*?');
},
settingsClick: function() {
if (this.state.action_in_progress) {
return;
}
return this.openSettings();
},
handleError: function(msg) {
track('error_happened', {
message: msg
});
this.setState({
error: msg
});
return this.transitionWithCodeModeHistory('error', '/error/*?');
},
changedFiles: function() {
return _.reject(Filesystem.ls(), (function(_this) {
return function(new_file) {
var clean_file;
clean_file = _.find(_this.state.clean_files, function(file) {
return file.path === new_file.path;
});
return clean_file.content === new_file.content;
};
})(this));
},
build: function() {
return this.buildOrRefresh();
},
buildOrRefresh: function() {
if (this.filesChanged() || !this.state.first_build_done) {
return this.execBuild();
} else {
return this.refreshBrowser();
}
},
refreshBrowser: function() {
return new Promise((function(_this) {
return function(resolve, reject) {
var browser_ref, ref;
browser_ref = (ref = _this.refs.appRouteHandler.refs.__routeHandler__) != null ? ref.refs.browser : void 0;
if (!browser_ref) {
return resolve();
}
browser_ref.refresh();
return resolve();
};
})(this));
},
execBuild: function() {
track('build_started');
this.actionStarted();
return new Promise((function(_this) {
return function(resolve, reject) {
return request.post({
json: true,
body: {
files: _this.changedFiles()
},
url: window.location.origin + "/apps/" + APP_SLUG + "/live_edit/preview"
}, function(err, status, resp) {
if (err) {
return reject(err);
}
if (status.statusCode === 500) {
return reject("Something bad happened in the server. Not your fault. We're fixing it.");
}
if (!resp.success) {
return reject(resp.error);
}
_this.setState({
clean_files: _.cloneDeep(Filesystem.ls()),
first_build_done: true
});
_this.actionStopped();
track('build_finished');
return resolve();
});
};
})(this));
},
filesChanged: function() {
return !_.isEmpty(this.changedFiles());
},
publishToGithub: function() {
track('publish_started');
if (this.filesChanged()) {
return this.build().then(this.publishToGithub)["catch"]((function(_this) {
return function(err) {
return _this.handleError(err);
};
})(this));
} else {
this.actionStarted();
return this.execPublish().then((function(_this) {
return function(resp) {
if (!resp.success) {
return _this.handleError(resp.error);
}
return track('publish_to_github_finished');
};
})(this))["catch"]((function(_this) {
return function(err) {
return _this.handleError(err);
};
})(this));
}
},
waitForPublishToServer: function() {
return new Promise((function(_this) {
return function(resolve, reject) {
return pusher_user_channel.bind('app.build', function() {
track('publish_to_server_finished');
_this.actionStopped();
return resolve();
});
};
})(this));
},
execPublish: function() {
return new Promise((function(_this) {
return function(resolve, reject) {
return request.post({
json: true,
url: window.location.origin + "/apps/" + APP_SLUG + "/live_edit/publish"
}, function(err, status, resp) {
if (err) {
return reject(err);
}
return resolve(resp);
});
};
})(this));
},
activeMode: function() {
var routes;
routes = this.context.router.getCurrentRoutes();
return _.first(routes[1].name.split('-'));
},
actionStarted: function() {
return this.setState({
action_in_progress: true
});
},
actionStopped: function() {
return this.setState({
action_in_progress: false
});
},
openSettings: function() {
track('settings_clicked');
return this.transitionWithCodeModeHistory('settings', '/settings/*?');
},
hideChangeDistDirToast: function() {
return this.setState({
show_change_dist_dir: false
});
},
saveDistDir: function(dist_dir) {
return new Promise((function(_this) {
return function(resolve, reject) {
return request.post({
json: true,
url: window.location.origin + "/apps/" + APP_SLUG + "/live_edit/change_dist_dir",
body: {
dist_dir: dist_dir
}
}, function(err, status, resp) {
if (err) {
return reject(err);
}
_this.setState({
dist_dir: resp.dist_dir
});
return resolve(resp);
});
};
})(this));
},
saveSlug: function(slug) {
return new Promise((function(_this) {
return function(resolve, reject) {
return request.post({
json: true,
url: window.location.origin + "/apps/" + APP_SLUG + "/live_edit/change_slug",
body: {
slug: slug
}
}, function(err, status, resp) {
if (err) {
return reject(err);
}
if (!resp.success) {
return reject('invalid_slug');
}
return window.location.origin = _this.newEditorUrl(resp.slug);
});
};
})(this));
},
newEditorUrl: function(slug) {
return window.location.href = window.location.origin + "/apps/" + slug + "/live_edit" + window.location.hash;
},
render: function() {
return React.createElement("main", {
"className": 'editor-wrapper'
}, React.createElement(Header, {
"action_in_progress": this.state.action_in_progress,
"website_url": this.props.website_url,
"active_mode": this.activeMode(),
"onCodeClick": this.codeClick,
"onPreviewClick": this.previewClick,
"onPublishClick": this.publishClick,
"onSettingsClick": this.settingsClick,
"onNewWebsiteClick": this.showFreeHosting,
"avatar": this.props.avatar
}), React.createElement(RouteHandler, {
"browser_url": this.props.browser_url,
"website_url": this.props.website_url,
"slug": this.props.slug,
"dist_dir": this.state.dist_dir,
"editorChange": this.editorChange,
"build": this.build,
"handleError": this.handleError,
"error": this.state.error,
"transitionWithCodeModeHistory": this.transitionWithCodeModeHistory,
"files_changed": this.filesChanged(),
"publishToGithub": this.publishToGithub,
"waitForPublishToServer": this.waitForPublishToServer,
"actionStopped": this.actionStopped,
"saveDistDir": this.saveDistDir,
"saveSlug": this.saveSlug,
"hideChangeDistDirToast": this.hideChangeDistDirToast,
"ref": 'appRouteHandler'
}), React.createElement(NewApp, {
"show": this.state.show_free_hosting,
"close": this.hideFreeHosting
}), React.createElement(ChangeDistDirToast, {
"show": this.state.show_change_dist_dir,
"dist_dir": this.state.dist_dir,
"onClose": this.hideChangeDistDirToast,
"onClick": this.openSettings
}));
}
});
},{"./change_dist_dir_toast":3,"./filesystem":11,"./header":12,"./materialize":15,"./new_app":16,"bluebird":57,"browser-cookies":79,"flat":185,"jquery":244,"lodash":250,"react":489,"react-router":351,"request":500}],2:[function(require,module,exports){
var Browser, React;
React = require('react');
module.exports = Browser = React.createClass({
refresh: function() {
return document.getElementById('browser').src = this.props.browser_url;
},
render: function() {
return React.createElement("div", {
"className": 'browser'
}, React.createElement("iframe", {
"id": 'browser',
"name": 'browser-frame',
"src": this.props.browser_url
}));
}
});
},{"react":489}],3:[function(require,module,exports){
var React, _;
React = require('react');
_ = require('lodash');
module.exports = React.createClass({
distDirName: function() {
if (this.props.dist_dir === '/' || _.isEmpty(this.props.dist_dir)) {
return 'Root (/)';
}
return this.props.dist_dir;
},
render: function() {
if (!this.props.show) {
return React.createElement("div", null);
}
return React.createElement("div", {
"className": 'toast-container'
}, React.createElement("div", {
"className": 'toast custom-toast'
}, React.createElement("span", null, "Current public directory for this website is ", React.createElement("b", null, this.distDirName())), React.createElement("span", {
"className": 'custom-toast-buttons'
}, React.createElement("span", {
"className": 'btn-flat yellow-text',
"onClick": this.props.onClick
}, "Change public directory"), React.createElement("span", {
"className": 'btn-flat blue-text text-lighten-4',
"onClick": this.props.onClose
}, "Leave as is"))));
}
});
},{"lodash":250,"react":489}],4:[function(require,module,exports){
var Link, Navigation, React, RouteHandler, Router, Tabs, _;
React = require('react');
_ = require('lodash');
Router = require('react-router');
RouteHandler = Router.RouteHandler;
Link = Router.Link;
Navigation = Router.Navigation;
Tabs = require('./tabs');
module.exports = React.createClass({
mixins: [Navigation],
fullPath: function() {
return this.props.params.splat;
},
tabs: function() {
var tabs;
tabs = _.map(this.tabPaths(), (function(_this) {
return function(tab_path) {
var name, path, tab_data;
path = tab_path.replace(/\*$/, '');
name = _.last(path.split('/'));
return tab_data = {
path: path,
name: name,
active: path === _this.activeTabPath()
};
};
})(this));
return _.map(tabs, (function(_this) {
return function(tab) {
tab.href = _this.href(tabs, tab);
tab.close_href = _this.closeHref(tabs, tab);
return tab;
};
})(this));
},
tabPaths: function() {
if (!this.fullPath()) {
return [];
}
return this.fullPath().split('&');
},
activeTabPath: function() {
var active_with_asterix;
active_with_asterix = _.find(this.tabPaths(), function(tab_path) {
return _.last(tab_path) === '*';
});
if (active_with_asterix) {
return active_with_asterix.slice(0, -1);
} else {
return this.fullPath();
}
},
href: function(tabs, new_active_tab) {
var new_tab_list;
new_tab_list = _.map(_.cloneDeep(tabs), function(tab) {
var updated_tab;
updated_tab = tab;
updated_tab.active = updated_tab.path === new_active_tab.path;
return updated_tab;
});
return this.joinTabPaths(new_tab_list);
},
closeHref: function(tabs, close_tab) {
var last_tab, new_tab_list;
new_tab_list = _.reject(_.cloneDeep(tabs), function(tab) {
return tab.path === close_tab.path;
});
_.each(new_tab_list, function(tab) {
return tab.active = false;
});
last_tab = _.last(new_tab_list);
if (last_tab) {
last_tab.active = true;
}
return this.joinTabPaths(new_tab_list);
},
joinTabPaths: function(tabs) {
var tab_paths;
tab_paths = _.map(tabs, function(tab) {
if (tab.active) {
return tab.path + '*';
} else {
return tab.path;
}
});
return tab_paths.join('&');
},
newTabHref: function(path) {
var new_active_tab, unique_tabs;
new_active_tab = {
path: path,
active: true
};
unique_tabs = _.uniqBy(_.flatten([this.tabs(), new_active_tab]), 'path');
return this.href(unique_tabs, new_active_tab);
},
reuseTabHref: function(path) {
var new_tabs, unique_tabs, with_active_tab;
new_tabs = _.map(this.tabs(), function(tab) {
if (tab.active) {
tab.path = path;
}
return tab;
});
unique_tabs = _.uniqBy(new_tabs, 'path');
with_active_tab = _.map(unique_tabs, function(tab) {
if (tab.path === path) {
tab.active = true;
}
return tab;
});
return this.joinTabPaths(with_active_tab);
},
checkValidPath: function() {
if (!this.fullPath()) {
return this.transitionTo('file', {
splat: '*'
});
}
},
render: function() {
this.checkValidPath();
return React.createElement("div", null, React.createElement("div", {
"className": 'row full'
}, React.createElement("div", {
"className": 'col m12 full code-mode-cols'
}, React.createElement(Tabs, {
"tabs": this.tabs(),
"new_tab_href": this.newTabHref('')
}), React.createElement(RouteHandler, {
"active_tab_path": this.activeTabPath(),
"reuseTabHref": this.reuseTabHref,
"newTabHref": this.newTabHref,
"editorChange": this.props.editorChange
}))));
}
});
},{"./tabs":24,"lodash":250,"react":489,"react-router":351}],5:[function(require,module,exports){
var $, App, CodeMode, Core, ErrorHandler, InitialLoader, PreviewMode, Publish, React, ReactDOM, Redirect, Route, Router, Settings, TabManager, md;
md = require('marked');
$ = require('jquery');
React = require('react');
ReactDOM = require('react-dom');
Router = require('react-router');
Route = Router.Route;
Redirect = Router.Redirect;
InitialLoader = require('./initial_loader');
App = require('./app');
CodeMode = require('./code_mode');
PreviewMode = require('./preview_mode');
TabManager = require('./tab_manager');
Publish = require('./publish');
ErrorHandler = require('./error_handler');
Settings = require('./settings');
module.exports = Core = (function() {
function Core(base, server) {
this.base = base;
this.server = server;
this.initial_loader = new InitialLoader();
}
Core.prototype.load = function() {
return this.initial_loader.loadFilesAndData().then((function(_this) {
return function(data) {
_this.data = data;
return Router.run(_this.routes(), function(Handler) {
return ReactDOM.render(React.createElement(Handler, {
"website_url": _this.data.app_domain,
"slug": _this.data.slug,
"avatar": _this.data.avatar,
"browser_url": _this.data.browser_url,
"dist_dir": _this.data.dist_dir,
"is_demo_app": _this.data.is_demo_app,
"first_build": _this.data.first_build
}), document.getElementById('editor-container'));
});
};
})(this));
};
Core.prototype.routes = function() {
return React.createElement(Route, {
"handler": App,
"path": '/'
}, React.createElement(Route, {
"name": 'code',
"path": '/code',
"handler": CodeMode
}, React.createElement(Route, {
"name": 'file',
"path": '/code/*?',
"handler": TabManager
})), React.createElement(Route, {
"name": 'preview',
"path": '/preview',
"handler": PreviewMode
}), React.createElement(Route, {
"name": 'preview-with-history',
"path": '/preview/*?',
"handler": PreviewMode
}), React.createElement(Route, {
"name": 'publish',
"path": '/publish',
"handler": Publish
}), React.createElement(Route, {
"name": 'publish-with-history',
"path": '/publish/*?',
"handler": Publish
}), React.createElement(Route, {
"name": 'error',
"path": '/error',
"handler": ErrorHandler
}), React.createElement(Route, {
"name": 'error-with-history',
"path": '/error/*?',
"handler": ErrorHandler
}), React.createElement(Route, {
"name": 'settings',
"path": '/settings',
"handler": Settings
}), React.createElement(Route, {
"name": 'settings-with-history',
"path": '/settings/*?',
"handler": Settings
}), React.createElement(Redirect, {
"from": '',
"to": '/code/'
}), React.createElement(Redirect, {
"from": "/code",
"to": "/code/"
}));
};
return Core;
})();
$(function() {
return new Core(APP_DOMAIN).load();
});
},{"./app":1,"./code_mode":4,"./error_handler":7,"./initial_loader":13,"./preview_mode":17,"./publish":18,"./settings":21,"./tab_manager":23,"jquery":244,"marked":252,"react":489,"react-dom":326,"react-router":351}],6:[function(require,module,exports){
var AceEditor, React, _, brace;
React = require('react');
brace = require('brace');
AceEditor = require('react-ace');
_ = require('lodash');
require('brace/mode/html');
require('brace/mode/jade');
require('brace/mode/markdown');
require('brace/mode/text');
require('brace/mode/javascript');
require('brace/mode/coffee');
require('brace/mode/jsx');
require('brace/mode/json');
require('brace/mode/css');
require('brace/mode/sass');
require('brace/theme/xcode');
require('brace/ext/searchbox');
module.exports = React.createClass({
emptySelection: function() {
return {
start: {
row: 0,
column: 0
},
end: {
row: 0,
column: 0
}
};
},
onChange: function(new_content) {
return this.props.onChange(this.props.path, new_content);
},
mode: function() {
var ext;
ext = this.props.path.match(/\.(.*)$/)[1] || 'html';
return this.props.supported_modes[ext] || 'html';
},
restoreSettings: function(editor) {
var settings;
settings = window.CloseheatFileSettings[this.props.path];
if (!settings) {
return editor.clearSelection();
}
editor.session.selection.setSelectionRange(settings.selection);
editor.session.setScrollTop(settings.scroll_top);
editor.session.setScrollLeft(settings.scroll_left);
settings.undo_manager.$doc = editor.session;
return editor.session.setUndoManager(settings.undo_manager);
},
onLoad: function(editor) {
var editor_session;
editor_session = editor.getSession();
editor_session.setTabSize(2);
editor_session.setUseSoftTabs(true);
editor.setHighlightActiveLine(false);
editor_session.setUndoManager(new brace.UndoManager);
return this.restoreSettings(editor);
},
saveSettings: function() {
var editor;
editor = this.refs.editor_container.editor;
return window.CloseheatFileSettings[this.props.path] = {
selection: editor.getSelectionRange() || this.emptySelection(),
scroll_top: editor.session.getScrollTop() || 0,
scroll_left: editor.session.getScrollLeft() || 0,
undo_manager: editor.session.getUndoManager()
};
},
render: function() {
return React.createElement(AceEditor, {
"mode": this.mode(),
"theme": 'xcode',
"name": 'blah1',
"height": 'calc(100vh - 54px - 36px)',
"width": '100%',
"onChange": this.onChange,
"onLoad": this.onLoad,
"value": this.props.value,
"ref": 'editor_container',
"editorProps": {
$blockScrolling: true
}
});
}
});
},{"brace":60,"brace/ext/searchbox":59,"brace/mode/coffee":61,"brace/mode/css":62,"brace/mode/html":63,"brace/mode/jade":64,"brace/mode/javascript":65,"brace/mode/json":66,"brace/mode/jsx":67,"brace/mode/markdown":68,"brace/mode/sass":69,"brace/mode/text":70,"brace/theme/xcode":71,"lodash":250,"react":489,"react-ace":325}],7:[function(require,module,exports){
var Promise, React, request;
React = require('react');
Promise = require('bluebird');
request = require('request');
module.exports = React.createClass({
componentWillMount: function() {
if (!this.props.error) {
this.props.transitionWithCodeModeHistory('code', '/code/*?');
}
return this.props.actionStopped();
},
getInitialState: function() {
return {};
},
message: function() {
var msg, with_n_as_enter;
if (!this.props.error) {
return;
}
msg = this.props.error.toString();
with_n_as_enter = JSON.stringify(msg).slice(1, -1);
return with_n_as_enter.replace(/\\n/g, '<br>');
},
render: function() {
return React.createElement("div", {
"className": 'error'
}, React.createElement("div", {
"className": 'row'
}, React.createElement("div", {
"className": 'error-container col offset-s2 s8 offset-l3 l6'
}, React.createElement("div", {
"className": 'error-title'
}, "Oops. An error occured."), React.createElement("div", {
"className": 'error-content',
"dangerouslySetInnerHTML": {
__html: this.message()
}
}))));
}
});
},{"bluebird":57,"react":489,"request":500}],8:[function(require,module,exports){
var Navigation, React, Router;
React = require('react');
Router = require('react-router');
Navigation = Router.Navigation;
module.exports = React.createClass({
mixins: [Navigation],
activeClass: function() {
var result;
result = 'tab col m2';
if (this.props.active) {
result += ' tab-active';
}
return result;
},
onClick: function() {
if (this.uneditableFile()) {
return;
}
return this.transitionTo('file', {
splat: this.props.file.href
});
},
kind: function() {
var ext;
if (this.props.file.type === 'dir') {
return 'Folder';
}
ext = this.props.file.path.match(/\.([0-9a-z]+)$/i)[1];
return this.props.supported_modes[ext] || ext;
},
icon: function() {
if (this.props.file.type === 'dir') {
return React.createElement("i", {
"className": 'material-icons'
}, "folder_open");
} else {
return React.createElement("i", {
"className": 'material-icons'
}, "class");
}
},
uneditableFile: function() {
return this.props.file.type === 'file' && !this.props.file.editable;
},
editableClass: function() {
if (this.uneditableFile()) {
return 'file-list-uneditable';
}
},
render: function() {
return React.createElement("tr", {
"onClick": this.onClick,
"className": this.editableClass()
}, React.createElement("td", {
"className": 'file-list-icon'
}, this.icon()), React.createElement("td", {
"className": 'file-list-name'
}, this.props.file.name), React.createElement("td", {
"className": 'file-list-kind'
}, this.kind()));
}
});
},{"react":489,"react-router":351}],9:[function(require,module,exports){
var File, FileUp, Filesystem, Link, React, Router, _;
React = require('react');
_ = require('lodash');
Router = require('react-router');
Link = Router.Link;
Filesystem = require('./filesystem');
File = require('./file');
FileUp = require('./file_up');
module.exports = React.createClass({
folderFiles: function() {
var dirs, files, ref, result;
result = _.map(this.props.dir.files, (function(_this) {
return function(file) {
file.href = _this.props.reuseTabHref(file.path);
return file;
};
})(this));
ref = _.partition(result, function(f) {
return f.type === 'dir';
}), dirs = ref[0], files = ref[1];
return dirs.concat(files);
},
upHref: function() {
var up_path;
up_path = _.dropRight(this.pathParts());
return this.props.reuseTabHref(up_path);
},
pathParts: function() {
return (this.props.path || '').split('/');
},
render: function() {
return React.createElement("div", null, React.createElement("div", {
"className": 'row'
}, React.createElement("div", {
"className": 'col m12'
}, React.createElement("ul", {
"className": 'file-list-path'
}, React.createElement("li", {
"className": 'file-list-start'
}, "Files"), _.map(this.pathParts(), function(part) {
return React.createElement("li", {
"key": part
}, React.createElement("span", {
"className": 'file-list-sep'
}, "\x2F"), React.createElement("span", {
"className": 'file-list-name'
}, part));
})), React.createElement("table", {
"className": 'file-list'
}, React.createElement("tbody", null, React.createElement("tr", null, React.createElement("th", {
"colSpan": 2
}, "Name"), React.createElement("th", null, "Kind")), React.createElement(FileUp, {
"show": !!this.props.path,
"href": this.upHref()
}), _.map(this.folderFiles(), (function(_this) {
return function(file) {
return React.createElement(File, {
"key": file.path,
"file": file,
"active": _this.props.active,
"supported_modes": _this.props.supported_modes
});
};
})(this)))))));
}
});
},{"./file":8,"./file_up":10,"./filesystem":11,"lodash":250,"react":489,"react-router":351}],10:[function(require,module,exports){
var Navigation, React, Router;
React = require('react');
Router = require('react-router');
Navigation = Router.Navigation;
module.exports = React.createClass({
mixins: [Navigation],
onClick: function() {
return this.transitionTo('file', {
splat: this.props.href
});
},
render: function() {
if (!this.props.show) {
return React.createElement("tr", null);
}
return React.createElement("tr", {
"onClick": this.onClick
}, React.createElement("td", null), React.createElement("td", {
"colSpan": 2
}, "..."));
}
});
},{"react":489,"react-router":351}],11:[function(require,module,exports){
var Filesystem, _;
_ = require('lodash');
module.exports = Filesystem = (function() {
function Filesystem() {}
Filesystem.create = function(files) {
return window.fs = files;
};
Filesystem.ls = function(path) {
if (!path) {
return window.fs;
}
return _.filter(window.fs, function(file) {
return file.path.match(RegExp("^" + path));
});
};
Filesystem.read = function(path) {
var file_on_path;
file_on_path = _.find(this.ls(), function(file) {
return file.path === path;
});
if (file_on_path) {
return file_on_path;
}
return {
type: 'dir',
path: path,
files: this.dirFiles(path)
};
};
Filesystem.dirFiles = function(path) {
var result;
result = [];
_.each(this.ls(path), function(file) {
var dir_path, name, relative_to_dir;
relative_to_dir = file.path.replace(RegExp("^" + path + "\\/"), '');
name = _.first(relative_to_dir.split('/'));
if (relative_to_dir.match('/')) {
dir_path = _.isEmpty(path) ? name : [path, name].join('/');
return result.push({
type: 'dir',
path: dir_path,
name: name
});
} else {
return result.push(_.merge(file, {
type: 'file',
name: name
}));
}
});
return _.uniqBy(result, 'name');
};
Filesystem.write = function(path, new_content) {
var file;
file = this.read(path);
return file.content = new_content;
};
Filesystem.isFile = function(path) {
return _.find(this.ls(), function(file) {
return file.path === path;
});
};
return Filesystem;
})();
},{"lodash":250}],12:[function(require,module,exports){
var $, Header, PublishStatus, React, ReactDOM, Tour, _, classNames;
React = require('react');
ReactDOM = require('react-dom');
classNames = require('classnames');
_ = require('lodash');
PublishStatus = require('./publish_status');
Tour = require('./tour');
$ = window.jQuery = window.$ = require('jquery');
module.exports = Header = React.createClass({
getInitialState: function() {
return {};
},
goToStep: function(tour_step) {},
activeModeClass: function(type, cols) {
var obj;
return classNames((
obj = {
col: true,
'header-mode': true,
'center-align': true
},
obj["" + cols] = true,
obj['header-mode-active'] = this.props.active_mode === type,
obj['header-in-progress'] = this.props.action_in_progress && type !== 'code',
obj
));
},
componentDidMount: function() {
this.addTooltips();
return this.addDropdowns();
},
componentDidUpdate: function() {
this.addTooltips();
return this.addDropdowns();
},
addDropdowns: function() {
return $(this.refs.dropdown_button).dropdown({
hover: true,
belowOrigin: true,
gutter: 20,
constrain_width: false
});
},
addTooltips: function() {
var elements;
elements = _.map(['code', 'preview', 'publish', 'website_url'], (function(_this) {
return function(name) {
return ReactDOM.findDOMNode(_this.refs[name]);
};
})(this));
return $(elements).tooltip({
delay: 100
});
},
prettyWebsiteUrl: function() {
return this.props.website_url.replace('http://', '');
},
render: function() {
var dashboard_url;
dashboard_url = "http://app.closeheat.com/apps/" + APP_SLUG + "/";
return React.createElement("div", null, React.createElement("div", {
"className": 'row header-row'
}, React.createElement("div", {
"className": this.activeModeClass('code', 'label-with-icon s2'),
"onClick": this.props.onCodeClick,
"data-tooltip": 'Ctrl+E',
"ref": 'code'
}, React.createElement("i", {
"className": 'material-icons'
}, "code"), "Code"), React.createElement("div", {
"className": this.activeModeClass('preview', 'label-with-icon s2'),
"onClick": this.props.onPreviewClick,
"data-tooltip": 'Ctrl+S',
"ref": 'preview'
}, React.createElement("i", {
"className": 'material-icons'
}, "navigation"), "Preview"), React.createElement("div", {
"className": 'header-website-url col s4 center-align label-with-icon',
"ref": 'website_url',
"data-tooltip": 'This is your public page URL'
}, React.createElement("a", {
"href": this.props.website_url,
"target": '_blank',
"className": 'truncate'
}, this.prettyWebsiteUrl(), React.createElement("i", {
"className": 'material-icons header-icon-right'
}, "open_in_new"))), React.createElement("div", {
"className": this.activeModeClass('publish', 's2 label-with-icon'),
"onClick": this.props.onPublishClick,
"data-tooltip": "Publishes changes to " + (this.prettyWebsiteUrl()),
"ref": 'publish'
}, React.createElement("i", {
"className": 'material-icons'
}, "publish"), "Publish"), React.createElement("div", {
"className": 'header-support col s1 center-align'
}, React.createElement("a", {
"href": "mailto:support@closeheat.com?subject=I'm having a problem with the editor"
}, "Support")), React.createElement("div", {
"ref": 'dropdown_button',
"className": 'col s1 center-align dropdown-button',
"data-activates": 'avatar-dropdown'
}, React.createElement("div", {
"className": 'header-avatar'
}, React.createElement("img", {
"src": this.props.avatar
})))), React.createElement("ul", {
"id": 'avatar-dropdown',
"className": 'dropdown-content'
}, React.createElement("li", null, React.createElement("a", {
"href": 'javascript:void(0);',
"onClick": this.props.onSettingsClick
}, "Settings")), React.createElement("li", null, React.createElement("a", {
"href": 'javascript:void(0);',
"onClick": this.props.onNewWebsiteClick
}, "Create a New Website")), React.createElement("li", null, React.createElement("a", {
"href": dashboard_url,
"target": '_blank'
}, "Website Dashboard"))), React.createElement(Tour, {
"step": this.state.tour_step,
"done": this.state.tour_done
}));
}
});
},{"./publish_status":19,"./tour":25,"classnames":114,"jquery":244,"lodash":250,"react":489,"react-dom":326}],13:[function(require,module,exports){
var Filesystem, InitialLoader, Promise, _, request;
_ = require('lodash');
request = require('request');
Promise = require('bluebird');
Filesystem = require('./filesystem');
module.exports = InitialLoader = (function() {
function InitialLoader() {}
InitialLoader.prototype.loadFilesAndData = function() {
return this.addFiles();
};
InitialLoader.prototype.addFiles = function() {
return this.getInitialData().then((function(_this) {
return function(data) {
window.CloseheatFileSettings = {};
Filesystem.create(data.files);
return data;
};
})(this))["catch"]((function(_this) {
return function(err) {
return alert(err);
};
})(this));
};
InitialLoader.prototype.getInitialData = function() {
return new Promise((function(_this) {
return function(resolve, reject) {
return request.get({
json: true,
url: window.location.origin + "/apps/" + APP_SLUG + "/live_edit/init"
}, function(err, status, resp) {
if (err) {
return reject(err);
}
return resolve(resp);
});
};
})(this));
};
return InitialLoader;
})();
},{"./filesystem":11,"bluebird":57,"lodash":250,"request":500}],14:[function(require,module,exports){
var React;
React = require('react');
module.exports = React.createClass({
render: function() {
return React.createElement("div", {
"className": 'loader valign-wrapper'
}, React.createElement("div", {
"className": 'valign loader-container'
}, React.createElement("div", {
"className": 'row'
}, React.createElement("div", {
"className": "preloader-wrapper big active loader-spinner valign"
}, React.createElement("div", {
"className": "spinner-layer spinner-red-only"
}, React.createElement("div", {
"className": "circle-clipper left"
}, React.createElement("div", {
"className": "circle"
})), React.createElement("div", {
"className": "gap-patch"
}, React.createElement("div", {
"className": "circle"
})), React.createElement("div", {
"className": "circle-clipper right"
}, React.createElement("div", {
"className": "circle"
}))))), React.createElement("div", {
"className": 'row'
}, React.createElement("div", {
"className": 'action-title'
}, this.props.title), React.createElement("div", {
"className": 'action-title'
}, this.props.subtitle))));
}
});
},{"react":489}],15:[function(require,module,exports){
require('materialize-css/js/jquery.easing.1.3');
require('materialize-css/js/animation');
require('materialize-css/js/velocity.min');
require('materialize-css/js/hammer.min');
require('materialize-css/js/jquery.hammer');
require('materialize-css/js/global');
require('materialize-css/js/collapsible');
require('materialize-css/js/dropdown');
require('materialize-css/js/leanModal');
require('materialize-css/js/materialbox');
require('materialize-css/js/parallax');
require('materialize-css/js/tabs');
require('materialize-css/js/tooltip');
require('materialize-css/js/waves');
require('materialize-css/js/toasts');
require('materialize-css/js/sideNav');
require('materialize-css/js/scrollspy');
require('materialize-css/js/forms');
require('materialize-css/js/slider');
require('materialize-css/js/cards');
require('materialize-css/js/pushpin');
require('materialize-css/js/buttons');
require('materialize-css/js/transitions');
require('materialize-css/js/scrollFire');
require('materialize-css/js/date_picker/picker');
require('materialize-css/js/date_picker/picker.date');
require('materialize-css/js/character_counter');
},{"materialize-css/js/animation":253,"materialize-css/js/buttons":254,"materialize-css/js/cards":255,"materialize-css/js/character_counter":256,"materialize-css/js/collapsible":257,"materialize-css/js/date_picker/picker":259,"materialize-css/js/date_picker/picker.date":258,"materialize-css/js/dropdown":260,"materialize-css/js/forms":261,"materialize-css/js/global":262,"materialize-css/js/hammer.min":263,"materialize-css/js/jquery.easing.1.3":264,"materialize-css/js/jquery.hammer":265,"materialize-css/js/leanModal":266,"materialize-css/js/materialbox":267,"materialize-css/js/parallax":268,"materialize-css/js/pushpin":269,"materialize-css/js/scrollFire":270,"materialize-css/js/scrollspy":271,"materialize-css/js/sideNav":272,"materialize-css/js/slider":273,"materialize-css/js/tabs":274,"materialize-css/js/toasts":275,"materialize-css/js/tooltip":276,"materialize-css/js/transitions":277,"materialize-css/js/velocity.min":278,"materialize-css/js/waves":279}],16:[function(require,module,exports){
var React;
React = require('react');
module.exports = React.createClass({
getInitialState: function() {
return {
selected: 'upload'
};
},
itemClass: function(type) {
var result;
result = 'free-hosting-type';
if (this.state.selected === type) {
result += ' free-hosting-type-selected';
}
return result;
},
handleSelect: function(type) {
return (function(_this) {
return function() {
return _this.setState({
selected: type
});
};
})(this);
},
getHref: function() {
if (this.state.selected === 'upload') {
return '/apps/new/upload';
} else {
return '/apps/new/templates';
}
},
buttonText: function() {
if (this.state.selected === 'upload') {
return 'Upload my website';
} else {
return 'Get my website';
}
},
maybeClose: function(e) {
if (e.target.className !== 'free-hosting-container') {
return;
}
return this.props.close();
},
render: function() {
if (!this.props.show) {
return React.createElement("div", null);
}
return React.createElement("div", {
"className": 'free-hosting-container',
"onClick": this.maybeClose
}, React.createElement("div", {
"className": 'free-hosting center-align'
}, React.createElement("div", {
"className": 'row free-hosting-title'
}, "Create a different website"), React.createElement("div", {
"className": 'row'
}, React.createElement("div", {
"className": 'col s6'
}, React.createElement("div", {
"className": this.itemClass('upload'),
"onClick": this.handleSelect('upload')
}, React.createElement("div", {
"className": 'free-hosting-type-icon'
}, React.createElement("i", {
"className": 'medium material-icons'
}, "invert_colors")), React.createElement("div", {
"className": 'free-hosting-type-title'
}, "I have a website to upload"))), React.createElement("div", {
"className": 'col s6'
}, React.createElement("div", {
"className": this.itemClass('template'),
"onClick": this.handleSelect('template')
}, React.createElement("div", {
"className": 'free-hosting-type-icon'
}, React.createElement("i", {
"className": 'medium material-icons'
}, "album")), React.createElement("div", {
"className": 'free-hosting-type-title'
}, "Use a new template"))), React.createElement("div", {
"className": 'row'
}, React.createElement("a", {
"href": this.getHref(),
"target": '_blank',
"className": "btn btn-large waves-effect waves-light free-hosting-button"
}, this.buttonText())))));
}
});
},{"react":489}],17:[function(require,module,exports){
var Browser, Loader, React;
React = require('react');
Browser = require('./browser');
Loader = require('./loader');
module.exports = React.createClass({
getInitialState: function() {
return {
build_finished: false
};
},
componentDidMount: function() {
return this.props.build().then((function(_this) {
return function(resp) {
return _this.setState({
build_finished: true
});
};
})(this))["catch"]((function(_this) {
return function(err) {
return _this.props.handleError(err);
};
})(this));
},
browser: function() {
return React.createElement("div", null, React.createElement("div", {
"className": 'row full'
}, React.createElement("div", {
"className": 'col browser-col full m12'
}, React.createElement(Browser, {
"ref": 'browser',
"browser_url": this.props.browser_url
}))));
},
render: function() {
if (this.state.build_finished) {
return this.browser();
} else {
return React.createElement(Loader, {
"title": 'Hang in tight.',
"subtitle": 'Building your page preview...'
});
}
}
});
},{"./browser":2,"./loader":14,"react":489}],18:[function(require,module,exports){
var Loader, Promise, Published, React, request;
React = require('react');
Promise = require('bluebird');
request = require('request');
Loader = require('./loader');
Published = require('./published');
module.exports = React.createClass({
getInitialState: function() {
return {
published_to_server: false,
published_to_github: false
};
},
componentDidMount: function() {
return this.props.publishToGithub().then((function(_this) {
return function(resp) {
_this.setState({
published_to_github: true
});
return _this.props.waitForPublishToServer().timeout(60000, _this.timeoutMsg()).then(function() {
return _this.setState({
published_to_server: true
});
});
};
})(this))["catch"]((function(_this) {
return function(err) {
return _this.props.handleError(err);
};
})(this));
},
timeoutMsg: function() {
return "Oops. Looks like we're having problems with publishing apps. <br>Click Support in the top bar!";
},
render: function() {
if (this.props.files_changed) {
return React.createElement(Loader, {
"title": 'Building your website...'
});
} else if (this.state.published_to_server) {
return React.createElement(Published, {
"website_url": this.props.website_url
});
} else if (this.state.published_to_github) {
return React.createElement(Loader, {
"title": 'Your files are now in Github.',
"subtitle": 'Publishing to server (~30 sec)...'
});
} else {
return React.createElement(Loader, {
"title": 'I am publishing your landing page...'
});
}
}
});
},{"./loader":14,"./published":20,"bluebird":57,"react":489,"request":500}],19:[function(require,module,exports){
var PublishStatus, React, classNames;
React = require('react');
classNames = require('classnames');
module.exports = PublishStatus = React.createClass({
currentStage: function() {
return this.props.current || 0;
},
error: function(i) {
if (!(this.props.error && this.currentStage() === i + 1)) {
return React.createElement("span", null);
}
return React.createElement("div", {
"className": 'stage-error'
}, "App name ", this.props.error);
},
render: function() {
if (this.currentStage() === 0) {
return React.createElement("span", {
"className": 'deploy-steps'
});
}
return React.createElement("ul", {
"className": "deploy-steps collection"
}, _.map(this.props.stages, (function(_this) {
return function(stage, i) {
var icon_classes, li_classes;
li_classes = function(_this) {
return classNames({
'collection-item': true,
success: !_this.props.error && _this.currentStage() > i + 1,
failure: _this.props.error && _this.currentStage() === i + 1
});
};
icon_classes = function(_this) {
return classNames({
fa: true,
icon: true,
'secondary-content': true,
'fa-check-circle': !_this.props.error && _this.currentStage() > i + 1,
'fa-circle-o-notch fa-spin': !_this.props.error && _this.currentStage() === i + 1,
'fa-exclamation-circle': _this.props.error && _this.currentStage() === i + 1
});
};
return React.createElement("li", {
"key": stage,
"className": li_classes(_this)
}, React.createElement("span", {
"className": 'stage-name'
}, stage), React.createElement("i", {
"className": icon_classes(_this)
}), _this.error(i));
};
})(this)));
}
});
},{"classnames":114,"react":489}],20:[function(require,module,exports){
var React;
React = require('react');
module.exports = React.createClass({
render: function() {
return React.createElement("div", {
"className": 'published valign-wrapper'
}, React.createElement("div", {
"className": 'valign published-container'
}, React.createElement("div", {
"className": 'published-icon row center-align'
}, React.createElement("i", {
"className": 'material-icons'
}, "favorite_border")), React.createElement("div", {
"className": 'row center-align'
}, React.createElement("div", {
"className": 'published-title'
}, React.createElement("div", null, "Phew, everything is great."), React.createElement("div", null, "Your landing page has been published.")), React.createElement("a", {
"href": this.props.website_url,
"target": '_blank',
"className": "btn btn-large waves-effect waves-light published-button"
}, React.createElement("div", null, "Open my landing page", React.createElement("span", {
"className": 'published-button-icon'
}, React.createElement("i", {
"className": 'material-icons'
}, "open_in_new"))), React.createElement("div", {
"className": 'published-button-subtitle'
}, this.props.website_url.replace('http://', ''))))));
}
});
},{"react":489}],21:[function(require,module,exports){
var Promise, React, request;
React = require('react');
Promise = require('bluebird');
request = require('request');
module.exports = React.createClass({
getInitialState: function() {
return {
dist_dir: this.props.dist_dir,
slug: this.props.slug
};
},
componentDidMount: function()