brutaljs
Version:
BrutalJS ========
1,674 lines (1,403 loc) • 635 kB
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 AuthService, DefaultRoute, NotFoundRoute, RedirectRoute, Route, _, glob, path, riot, router, securityFilter;
_ = require('lodash');
path = require('path');
riot = require('riot');
glob = require("glob");
router = require("riot-router");
AuthService = require('./services/auth.coffee');
require('./components/app.tag');require('./components/auth/login.tag');require('./components/edit.tag');require('./components/landing.tag');require('./components/list.tag');require('./components/navbar.tag');require('./components/pen.tag');
riot.mount('*');
securityFilter = function(req, res, next) {
return AuthService.ping(next, function() {
return riot.route('/login');
});
};
Route = router.Route;
DefaultRoute = router.DefaultRoute;
NotFoundRoute = router.NotFoundRoute;
RedirectRoute = router.RedirectRoute;
router.use(securityFilter);
router.routes([
new DefaultRoute({
tag: 'app'
}), new Route({
tag: 'app'
}).routes([
new DefaultRoute({
tag: 'landing'
}), new Route({
path: '/list/:modelName',
tag: 'list'
}), new Route({
path: '/edit/:modelName/:itemId',
tag: 'edit'
}), new Route({
path: '/new/:modelName',
tag: 'edit'
})
]), new Route({
tag: 'login'
})
]);
router.start();
},{"./components/app.tag":2,"./components/auth/login.tag":3,"./components/edit.tag":4,"./components/landing.tag":5,"./components/list.tag":6,"./components/navbar.tag":7,"./components/pen.tag":8,"./services/auth.coffee":10,"glob":14,"lodash":34,"path":30,"riot":36,"riot-router":35}],2:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('app', '<div class="container"> <div class="row"> <div class="col-xs-12"> <route></route> </div> </div> </div>', function(opts) {
});
},{"riot":36}],3:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('login', '<div class="row"> <div class="col-xs-6"> <h1>Log In</h1> <form onsubmit="{submit}" class="form"> <div class="form-group"> <label>Email</label> <input type="email" placeholder="E-mail" name="email" class="form-control"> </div> <div class="form-group"> <label>Password</label> <input type="password" placeholder="Password" name="password" class="form-control"> </div> <div class="form-group"> <input type="submit" value="Log In" class="btn btn-primary"> </div> </form> </div> </div>', function(opts) {var AuthService, riot;
riot = require('riot');
AuthService = require('../../services/auth.coffee');
this.submit = function(event) {
event.preventDefault();
return AuthService.login({
email: this.email.value,
password: this.password.value
}, function(err, resp) {
riot.route('/app');
return console.log(arguments);
});
};
});
},{"../../services/auth.coffee":10,"riot":36}],4:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('edit', '<h2> <a href="/admin#/app">Edit</a> > <a href="/admin#/app/list/{modelName}">{modelName} </a><span if="{itemId !== undefined}">> {itemId}</span></h2> <div class="row"> <div class="col-xs-6"> <form onsubmit="{submit}"> <div each="{key, val in model.schema}" class="form-group"> <label>{key}</label> <input data-key="{key}" if="{val.instance === \'String\' && (val.options._meta !== undefined && val.options._meta.plain)}" value="{model.data[key]}" class="form-control"> <pen data-key="{key}" if="{val.instance === \'String\' && (val.options._meta === undefined || val.options._meta.plain !== true)}" content="{model.data[key]}" class="form-control"> </pen> </div> <input type="submit" value="Save" class="btn btn-primary"> </form> </div> </div>', function(opts) {var ApiService, ModelService, _, router;
_ = require('lodash');
router = require('riot-router');
ModelService = require('../services/model.coffee');
ApiService = require('../services/api.coffee');
this.modelName = router.current.params.modelName;
this.itemId = router.current.params.itemId;
this.model = {
schema: {},
data: {}
};
this.getData = function() {
var data;
data = {};
_.forIn(document.querySelectorAll('.form-control'), (function(_this) {
return function(el) {
var k;
if (el.dataset != null) {
k = el.dataset.key;
if (el.tagName === 'PEN') {
return data[k] = el.innerHTML;
} else {
return data[k] = el.value;
}
}
};
})(this));
return data;
};
this.submit = function(event) {
var data;
event.preventDefault();
data = this.getData();
if (this.itemId != null) {
return ApiService.put(this.modelName, this.itemId, data, function(err, resp) {
return console.log(arguments);
});
} else {
return ApiService.post(this.modelName, data, function(err, resp) {
return console.log(arguments);
});
}
};
ModelService.get(this.modelName, (function(_this) {
return function(err, resp) {
if (err) {
console.log(err);
} else {
_this.model.schema = resp.body.schema;
}
return _this.update();
};
})(this));
if (this.itemId != null) {
ApiService.get(this.modelName, this.itemId, (function(_this) {
return function(err, resp) {
if (err) {
console.log(err);
} else {
_this.model.data = resp.body;
}
return _this.update();
};
})(this));
}
});
},{"../services/api.coffee":9,"../services/model.coffee":11,"lodash":34,"riot":36,"riot-router":35}],5:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('landing', '<h1>Edit Data</h1> <p>Pick a type of data to edit</p> <div class="row"> <div class="col-xs-6"> <ul class="list-group"> <li each="{models}" class="list-group-item"><a href="/admin#/app/list/{id}">{id}</a></li> </ul> </div> </div>', function(opts) {var ModelService, _;
_ = require('lodash');
ModelService = require('../services/model.coffee');
this.models = [];
ModelService.getAll((function(_this) {
return function(err, resp) {
_this.models = resp.body;
return _this.update();
};
})(this));
});
},{"../services/model.coffee":11,"lodash":34,"riot":36}],6:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('list', '<h2><a href="/admin#/app">Edit</a> > {modelName} <a href="/admin#/app/new/{modelName}" class="btn btn-primary btn-sm">Add New</a></h2> <table if="items.length > 0" class="table table-striped"> <thead> <tr> <th each="{key, val in items[0]}">{key}</th> <th></th> </tr> </thead> <tbody> <tr each="{item in items}"> <td each="{key, val in item}">{val}</td> <td><a class="btn btn-default pull-right">Delete</a><a href="/admin#/app/edit/{modelName}/{item._id}" class="btn btn-default pull-right">Edit</a></td> </tr> </tbody> </table>', function(opts) {var ApiService, router;
router = require('riot-router');
ApiService = require('../services/api.coffee');
this.modelName = router.current.params.modelName;
this.items = [];
ApiService.getAll(this.modelName, (function(_this) {
return function(err, resp) {
if (err) {
alert(err);
} else {
_this.items = resp.body;
console.log(_this.items);
}
return _this.update();
};
})(this));
});
},{"../services/api.coffee":9,"riot":36,"riot-router":35}],7:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('navbar', '<nav class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"><a href="/admin#/app" class="navbar-brand">Admin</a></div><a href="/" target="_blank" class="btn btn-default navbar-btn pull-right">View Site</a><a onclick="{logout}" class="btn btn-default navbar-btn pull-right">Log Out</a> </div> </nav>', function(opts) {var AuthService, riot;
riot = require('riot');
AuthService = require('../services/auth.coffee');
this.logout = function() {
return AuthService.logout(function() {
return riot.route('/login');
});
};
});
},{"../services/auth.coffee":10,"riot":36}],8:[function(require,module,exports){
var riot = require('riot');
module.exports =
riot.tag('pen', '', function(opts) {var Pen, _;
_ = require('lodash');
Pen = require('Pen');
this.on('mount update', function() {
if (this.opts.content != null) {
return this.root.innerHTML = this.opts.content;
}
});
this.on('mount', function() {
return new Pen({
stay: false,
editor: this.root
});
});
});
},{"Pen":12,"lodash":34,"riot":36}],9:[function(require,module,exports){
var _, request;
_ = require('lodash');
request = require('superagent');
module.exports = {
getAll: function(modelName, next) {
return request.get("http://" + "127.0.0.1:5000" + "/api/" + modelName).end(next);
},
post: function(modelName, data, next) {
return request.post("http://" + "127.0.0.1:5000" + "/api/" + modelName).send(data).end(next);
},
get: function(modelName, id, next) {
return request.get("http://" + "127.0.0.1:5000" + "/api/" + modelName + "/" + id).end(next);
},
put: function(modelName, id, data, next) {
return request.put("http://" + "127.0.0.1:5000" + "/api/" + modelName + "/" + id).send(data).end(next);
},
"delete": function() {}
};
},{"lodash":34,"superagent":37}],10:[function(require,module,exports){
var _, request;
_ = require('lodash');
request = require('superagent');
module.exports = {
login: function(payload, next) {
var email, password;
email = payload.email.trim();
password = payload.password.trim();
if (email !== '' && password !== '') {
return request.post("http://127.0.0.1:5000/auth/login").send({
email: email,
password: password
}).end(function(err, resp) {
if (resp.status === 200) {
localStorage.setItem('fabric_auth_token', resp.body.token);
}
return next(err, resp);
});
}
},
logout: function(next) {
localStorage.removeItem('fabric_auth_token');
return next(null);
},
ping: function(success, fail) {
var token;
token = localStorage.getItem('fabric_auth_token');
if (token == null) {
return request.get("http://127.0.0.1:5000/auth/ping").set('X-Auth', token).end(function(err, resp) {
if (err) {
return fail();
} else if ((resp != null) && (resp.body != null)) {
resp.body = {
user: resp.body,
token: token
};
return success(err, resp);
}
});
} else {
return success();
}
}
};
},{"lodash":34,"superagent":37}],11:[function(require,module,exports){
var _, request;
_ = require('lodash');
request = require('superagent');
module.exports = {
getAll: function(next) {
return request.get("http://" + "127.0.0.1:5000" + "/admin/model").end(next);
},
post: function() {},
get: function(id, next) {
return request.get("http://" + "127.0.0.1:5000" + "/admin/model/" + id).end(next);
},
put: function() {},
"delete": function() {}
};
},{"lodash":34,"superagent":37}],12:[function(require,module,exports){
(function (global){
; var __browserify_shim_require__=require;(function browserifyShim(module, exports, require, define, browserify_shim__define__module__export__) {
/*! Licensed under MIT, https://github.com/sofish/pen */
(function(root, doc) {
var Pen, debugMode, selection, utils = {};
var toString = Object.prototype.toString;
var slice = Array.prototype.slice;
// allow command list
var commandsReg = {
block: /^(?:p|h[1-6]|blockquote|pre)$/,
inline: /^(?:bold|italic|underline|insertorderedlist|insertunorderedlist|indent|outdent)$/,
source: /^(?:createlink|unlink)$/,
insert: /^(?:inserthorizontalrule|insertimage|insert)$/,
wrap: /^(?:code)$/
};
var lineBreakReg = /^(?:blockquote|pre|div)$/i;
var effectNodeReg = /(?:[pubia]|h[1-6]|blockquote|[uo]l|li)/i;
var strReg = {
whiteSpace: /(^\s+)|(\s+$)/g,
mailTo: /^(?!mailto:|.+\/|.+#|.+\?)(.*@.*\..+)$/,
http: /^(?!\w+?:\/\/|mailto:|\/|\.\/|\?|#)(.*)$/
};
var autoLinkReg = {
url: /((https?|ftp):\/\/|www\.)[^\s<]{3,}/gi,
prefix: /^(?:https?|ftp):\/\//i,
notLink: /^(?:img|a|input|audio|video|source|code|pre|script|head|title|style)$/i,
maxLength: 100
};
// type detect
utils.is = function(obj, type) {
return toString.call(obj).slice(8, -1) === type;
};
utils.forEach = function(obj, iterator, arrayLike) {
if (!obj) return;
if (arrayLike == null) arrayLike = utils.is(obj, 'Array');
if (arrayLike) {
for (var i = 0, l = obj.length; i < l; i++) iterator(obj[i], i, obj);
} else {
for (var key in obj) {
if (obj.hasOwnProperty(key)) iterator(obj[key], key, obj);
}
}
};
// copy props from a obj
utils.copy = function(defaults, source) {
utils.forEach(source, function (value, key) {
defaults[key] = utils.is(value, 'Object') ? utils.copy({}, value) :
utils.is(value, 'Array') ? utils.copy([], value) : value;
});
return defaults;
};
// log
utils.log = function(message, force) {
if (debugMode || force)
console.log('%cPEN DEBUGGER: %c' + message, 'font-family:arial,sans-serif;color:#1abf89;line-height:2em;', 'font-family:cursor,monospace;color:#333;');
};
utils.delayExec = function (fn) {
var timer = null;
return function (delay) {
clearTimeout(timer);
timer = setTimeout(function() {
fn();
}, delay || 1);
};
};
// merge: make it easy to have a fallback
utils.merge = function(config) {
// default settings
var defaults = {
class: 'pen',
debug: false,
toolbar: null, // custom toolbar
stay: config.stay || !config.debug,
stayMsg: 'Are you going to leave here?',
textarea: '<textarea name="content"></textarea>',
list: [
'blockquote', 'h2', 'h3', 'p', 'code', 'insertorderedlist', 'insertunorderedlist', 'inserthorizontalrule',
'indent', 'outdent', 'bold', 'italic', 'underline', 'createlink', 'insertimage'
],
cleanAttrs: ['id', 'class', 'style', 'name'],
cleanTags: ['script']
};
// user-friendly config
if (config.nodeType === 1) {
defaults.editor = config;
} else if (config.match && config.match(/^#[\S]+$/)) {
defaults.editor = doc.getElementById(config.slice(1));
} else {
defaults = utils.copy(defaults, config);
}
return defaults;
};
function commandOverall(ctx, cmd, val) {
var message = ' to exec 「' + cmd + '」 command' + (val ? (' with value: ' + val) : '');
try {
doc.execCommand(cmd, false, val);
} catch(err) {
// TODO: there's an error when insert a image to document, bug not a bug
return utils.log('fail' + message, true);
}
utils.log('success' + message);
}
function commandInsert(ctx, name, val) {
var node = getNode(ctx);
if (!node) return;
ctx._range.selectNode(node);
ctx._range.collapse(false);
// hide menu when a image was inserted
if(name === 'insertimage' && ctx._menu) toggleNode(ctx._menu, true);
return commandOverall(ctx, name, val);
}
function commandBlock(ctx, name) {
var list = effectNode(ctx, getNode(ctx), true);
if (list.indexOf(name) !== -1) name = 'p';
return commandOverall(ctx, 'formatblock', name);
}
function commandWrap(ctx, tag, value) {
value = '<' + tag + '>' + (value||selection.toString()) + '</' + tag + '>';
return commandOverall(ctx, 'insertHTML', value);
}
function initToolbar(ctx) {
var icons = '', inputStr = '<input class="pen-input" placeholder="http://" />';
ctx._toolbar = ctx.config.toolbar;
if (!ctx._toolbar) {
var toolList = ctx.config.list;
utils.forEach(toolList, function (name) {
var klass = 'pen-icon icon-' + name;
icons += '<i class="' + klass + '" data-action="' + name + '"></i>';
}, true);
if (toolList.indexOf('createlink') >= 0 || toolList.indexOf('createlink') >= 0)
icons += inputStr;
} else if (ctx._toolbar.querySelectorAll('[data-action=createlink]').length ||
ctx._toolbar.querySelectorAll('[data-action=insertimage]').length) {
icons += inputStr;
}
if (icons) {
ctx._menu = doc.createElement('div');
ctx._menu.setAttribute('class', ctx.config.class + '-menu pen-menu');
ctx._menu.innerHTML = icons;
ctx._inputBar = ctx._menu.querySelector('input');
toggleNode(ctx._menu, true);
doc.body.appendChild(ctx._menu);
}
if (ctx._toolbar && ctx._inputBar) toggleNode(ctx._inputBar);
}
function initEvents(ctx) {
var toolbar = ctx._toolbar || ctx._menu, editor = ctx.config.editor;
var toggleMenu = utils.delayExec(function() {
ctx.highlight().menu();
});
var outsideClick = function() {};
function updateStatus(delay) {
ctx._range = ctx.getRange();
toggleMenu(delay);
}
if (ctx._menu) {
var setpos = function() {
if (ctx._menu.style.display === 'block') ctx.menu();
};
// change menu offset when window resize / scroll
addListener(ctx, root, 'resize', setpos);
addListener(ctx, root, 'scroll', setpos);
// toggle toolbar on mouse select
var selecting = false;
addListener(ctx, editor, 'mousedown', function() {
selecting = true;
});
addListener(ctx, editor, 'mouseleave', function() {
if (selecting) updateStatus(800);
selecting = false;
});
addListener(ctx, editor, 'mouseup', function() {
if (selecting) updateStatus(100);
selecting = false;
});
// Hide menu when focusing outside of editor
outsideClick = function(e) {
if (ctx._menu && !containsNode(editor, e.target) && !containsNode(ctx._menu, e.target)) {
removeListener(ctx, doc, 'click', outsideClick);
toggleMenu(100);
}
};
} else {
addListener(ctx, editor, 'click', function() {
updateStatus(0);
});
}
addListener(ctx, editor, 'keyup', function(e) {
if (e.which === 8 && ctx.isEmpty()) return lineBreak(ctx, true);
// toggle toolbar on key select
if (e.which !== 13 || e.shiftKey) return updateStatus(400);
var node = getNode(ctx, true);
if (!node || !node.nextSibling || !lineBreakReg.test(node.nodeName)) return;
if (node.nodeName !== node.nextSibling.nodeName) return;
// hack for webkit, make 'enter' behavior like as firefox.
if (node.lastChild.nodeName !== 'BR') node.appendChild(doc.createElement('br'));
utils.forEach(node.nextSibling.childNodes, function(child) {
if (child) node.appendChild(child);
}, true);
node.parentNode.removeChild(node.nextSibling);
focusNode(ctx, node.lastChild, ctx.getRange());
});
// check line break
addListener(ctx, editor, 'keydown', function(e) {
editor.classList.remove('pen-placeholder');
if (e.which !== 13 || e.shiftKey) return;
var node = getNode(ctx, true);
if (!node || !lineBreakReg.test(node.nodeName)) return;
var lastChild = node.lastChild;
if (!lastChild || !lastChild.previousSibling) return;
if (lastChild.previousSibling.textContent || lastChild.textContent) return;
// quit block mode for 2 'enter'
e.preventDefault();
var p = doc.createElement('p');
p.innerHTML = '<br>';
node.removeChild(lastChild);
if (!node.nextSibling) node.parentNode.appendChild(p);
else node.parentNode.insertBefore(p, node.nextSibling);
focusNode(ctx, p, ctx.getRange());
});
var menuApply = function(action, value) {
ctx.execCommand(action, value);
ctx._range = ctx.getRange();
ctx.highlight().menu();
};
// toggle toolbar on key select
addListener(ctx, toolbar, 'click', function(e) {
var node = e.target, action;
while (node !== toolbar && !(action = node.getAttribute('data-action'))) {
node = node.parentNode;
}
if (!action) return;
if (!/(?:createlink)|(?:insertimage)/.test(action)) return menuApply(action);
if (!ctx._inputBar) return;
// create link
var input = ctx._inputBar;
if (toolbar === ctx._menu) toggleNode(input);
else {
ctx._inputActive = true;
ctx.menu();
}
if (ctx._menu.style.display === 'none') return;
setTimeout(function() { input.focus(); }, 400);
var createlink = function() {
var inputValue = input.value;
if (!inputValue) action = 'unlink';
else {
inputValue = input.value
.replace(strReg.whiteSpace, '')
.replace(strReg.mailTo, 'mailto:$1')
.replace(strReg.http, 'http://$1');
}
menuApply(action, inputValue);
if (toolbar === ctx._menu) toggleNode(input, false);
else toggleNode(ctx._menu, true);
};
input.onkeypress = function(e) {
if (e.which === 13) return createlink();
};
});
// listen for placeholder
addListener(ctx, editor, 'focus', function() {
if (ctx.isEmpty()) lineBreak(ctx, true);
addListener(ctx, doc, 'click', outsideClick);
});
addListener(ctx, editor, 'blur', function() {
checkPlaceholder(ctx);
ctx.checkContentChange();
});
// listen for paste and clear style
addListener(ctx, editor, 'paste', function() {
setTimeout(function() {
ctx.cleanContent();
});
});
}
function addListener(ctx, target, type, listener) {
if (ctx._events.hasOwnProperty(type)) {
ctx._events[type].push(listener);
} else {
ctx._eventTargets = ctx._eventTargets || [];
ctx._eventsCache = ctx._eventsCache || [];
var index = ctx._eventTargets.indexOf(target);
if (index < 0) index = ctx._eventTargets.push(target) - 1;
ctx._eventsCache[index] = ctx._eventsCache[index] || {};
ctx._eventsCache[index][type] = ctx._eventsCache[index][type] || [];
ctx._eventsCache[index][type].push(listener);
target.addEventListener(type, listener, false);
}
return ctx;
}
// trigger local events
function triggerListener(ctx, type) {
if (!ctx._events.hasOwnProperty(type)) return;
var args = slice.call(arguments, 2);
utils.forEach(ctx._events[type], function (listener) {
listener.apply(ctx, args);
});
}
function removeListener(ctx, target, type, listener) {
var events = ctx._events[type];
if (!events) {
var _index = ctx._eventTargets.indexOf(target);
if (_index >= 0) events = ctx._eventsCache[_index][type];
}
if (!events) return ctx;
var index = events.indexOf(listener);
if (index >= 0) events.splice(index, 1);
target.removeEventListener(type, listener, false);
return ctx;
}
function removeAllListeners(ctx) {
utils.forEach(this._events, function (events) {
events.length = 0;
}, false);
if (!ctx._eventsCache) return ctx;
utils.forEach(ctx._eventsCache, function (events, index) {
var target = ctx._eventTargets[index];
utils.forEach(events, function (listeners, type) {
utils.forEach(listeners, function (listener) {
target.removeEventListener(type, listener, false);
}, true);
}, false);
}, true);
ctx._eventTargets = [];
ctx._eventsCache = [];
return ctx;
}
function checkPlaceholder(ctx) {
ctx.config.editor.classList[ctx.isEmpty() ? 'add' : 'remove']('pen-placeholder');
}
function trim(str) {
return (str || '').replace(/^\s+|\s+$/g, '');
}
// node.contains is not implemented in IE10/IE11
function containsNode(parent, child) {
if (parent === child) return true;
child = child.parentNode;
while (child) {
if (child === parent) return true;
child = child.parentNode;
}
return false;
}
function getNode(ctx, byRoot) {
var node, root = ctx.config.editor;
ctx._range = ctx._range || ctx.getRange();
node = ctx._range.commonAncestorContainer;
if (!node || node === root) return null;
while (node && (node.nodeType !== 1) && (node.parentNode !== root)) node = node.parentNode;
while (node && byRoot && (node.parentNode !== root)) node = node.parentNode;
return containsNode(root, node) ? node : null;
}
// node effects
function effectNode(ctx, el, returnAsNodeName) {
var nodes = [];
el = el || ctx.config.editor;
while (el && el !== ctx.config.editor) {
if (el.nodeName.match(effectNodeReg)) {
nodes.push(returnAsNodeName ? el.nodeName.toLowerCase() : el);
}
el = el.parentNode;
}
return nodes;
}
// breakout from node
function lineBreak(ctx, empty) {
var range = ctx._range = ctx.getRange(), node = doc.createElement('p');
if (empty) ctx.config.editor.innerHTML = '';
node.innerHTML = '<br>';
range.insertNode(node);
focusNode(ctx, node.childNodes[0], range);
}
function focusNode(ctx, node, range) {
range.setStartAfter(node);
range.setEndBefore(node);
range.collapse(false);
ctx.setRange(range);
}
function autoLink(node) {
if (node.nodeType === 1) {
if (autoLinkReg.notLink.test(node.tagName)) return;
utils.forEach(node.childNodes, function (child) {
autoLink(child);
}, true);
} else if (node.nodeType === 3) {
var result = urlToLink(node.nodeValue || '');
if (!result.links) return;
var frag = doc.createDocumentFragment(),
div = doc.createElement('div');
div.innerHTML = result.text;
while (div.childNodes.length) frag.appendChild(div.childNodes[0]);
node.parentNode.replaceChild(frag, node);
}
}
function urlToLink(str) {
var count = 0;
str = str.replace(autoLinkReg.url, function(url) {
var realUrl = url, displayUrl = url;
count++;
if (url.length > autoLinkReg.maxLength) displayUrl = url.slice(0, autoLinkReg.maxLength) + '...';
// Add http prefix if necessary
if (!autoLinkReg.prefix.test(realUrl)) realUrl = 'http://' + realUrl;
return '<a href="' + realUrl + '">' + displayUrl + '</a>';
});
return {links: count, text: str};
}
function toggleNode(node, hide) {
node.style.display = hide ? 'none' : 'block';
}
Pen = function(config) {
if (!config) throw new Error('Can\'t find config');
debugMode = config.debug;
// merge user config
var defaults = utils.merge(config);
var editor = defaults.editor;
if (!editor || editor.nodeType !== 1) throw new Error('Can\'t find editor');
// set default class
editor.classList.add(defaults.class);
// set contenteditable
editor.setAttribute('contenteditable', 'true');
// assign config
this.config = defaults;
// set placeholder
if (defaults.placeholder) editor.setAttribute('data-placeholder', defaults.placeholder);
checkPlaceholder(this);
// save the selection obj
this.selection = selection;
// define local events
this._events = {change: []};
// enable toolbar
initToolbar(this);
// init events
initEvents(this);
// to check content change
this._prevContent = this.getContent();
// enable markdown covert
if (this.markdown) this.markdown.init(this);
// stay on the page
if (this.config.stay) this.stay(this.config);
};
Pen.prototype.on = function(type, listener) {
addListener(this, this.config.editor, type, listener);
return this;
};
Pen.prototype.isEmpty = function(node) {
node = node || this.config.editor;
return !(node.querySelector('img')) && !(node.querySelector('blockquote')) &&
!(node.querySelector('li')) && !trim(node.textContent);
};
Pen.prototype.getContent = function() {
return this.isEmpty() ? '' : trim(this.config.editor.innerHTML);
};
Pen.prototype.setContent = function(html) {
this.config.editor.innerHTML = html;
this.cleanContent();
return this;
};
Pen.prototype.checkContentChange = function () {
var prevContent = this._prevContent, currentContent = this.getContent();
if (prevContent === currentContent) return;
this._prevContent = currentContent;
triggerListener(this, 'change', currentContent, prevContent);
};
Pen.prototype.getRange = function() {
var editor = this.config.editor, range = selection.rangeCount && selection.getRangeAt(0);
if (!range) range = doc.createRange();
if (!containsNode(editor, range.commonAncestorContainer)) {
range.selectNodeContents(editor);
range.collapse(false);
}
return range;
};
Pen.prototype.setRange = function(range) {
range = range || this._range;
if (!range) {
range = this.getRange();
range.collapse(false); // set to end
}
try {
selection.removeAllRanges();
selection.addRange(range);
} catch (e) {/* IE throws error sometimes*/}
return this;
};
Pen.prototype.focus = function(focusStart) {
if (!focusStart) this.setRange();
this.config.editor.focus();
return this;
};
Pen.prototype.execCommand = function(name, value) {
name = name.toLowerCase();
this.setRange();
if (commandsReg.block.test(name)) {
commandBlock(this, name);
} else if (commandsReg.inline.test(name) || commandsReg.source.test(name)) {
commandOverall(this, name, value);
} else if (commandsReg.insert.test(name)) {
commandInsert(this, name, value);
} else if (commandsReg.wrap.test(name)) {
commandWrap(this, name, value);
} else {
utils.log('can not find command function for name: ' + name + (value ? (', value: ' + value) : ''), true);
}
if (name === 'indent') this.checkContentChange();
else this.cleanContent({cleanAttrs: ['style']});
};
// remove attrs and tags
// pen.cleanContent({cleanAttrs: ['style'], cleanTags: ['id']})
Pen.prototype.cleanContent = function(options) {
var editor = this.config.editor;
if (!options) options = this.config;
utils.forEach(options.cleanAttrs, function (attr) {
utils.forEach(editor.querySelectorAll('[' + attr + ']'), function(item) {
item.removeAttribute(attr);
}, true);
}, true);
utils.forEach(options.cleanTags, function (tag) {
utils.forEach(editor.querySelectorAll(tag), function(item) {
item.parentNode.removeChild(item);
}, true);
}, true);
checkPlaceholder(this);
this.checkContentChange();
return this;
};
// auto link content, return content
Pen.prototype.autoLink = function() {
autoLink(this.config.editor);
return this.getContent();
};
// highlight menu
Pen.prototype.highlight = function() {
var toolbar = this._toolbar || this._menu
, node = getNode(this);
// remove all highlights
utils.forEach(toolbar.querySelectorAll('.active'), function(el) {
el.classList.remove('active');
}, true);
if (!node) return this;
var effects = effectNode(this, node)
, inputBar = this._inputBar
, highlight;
if (inputBar && toolbar === this._menu) {
// display link input if createlink enabled
inputBar.style.display = 'none';
// reset link input value
inputBar.value = '';
}
highlight = function(str) {
if (!str) return;
var el = toolbar.querySelector('[data-action=' + str + ']');
return el && el.classList.add('active');
};
utils.forEach(effects, function(item) {
var tag = item.nodeName.toLowerCase();
switch(tag) {
case 'a':
if (inputBar) inputBar.value = item.getAttribute('href');
tag = 'createlink';
break;
case 'img':
if (inputBar) inputBar.value = item.getAttribute('src');
tag = 'insertimage';
break;
case 'i':
tag = 'italic';
break;
case 'u':
tag = 'underline';
break;
case 'b':
tag = 'bold';
break;
case 'pre':
case 'code':
tag = 'code';
break;
case 'ul':
tag = 'insertunorderedlist';
break;
case 'ol':
tag = 'insertorderedlist';
break;
case 'li':
tag = 'indent';
break;
}
highlight(tag);
}, true);
return this;
};
// show menu
Pen.prototype.menu = function() {
if (!this._menu) return this;
if (selection.isCollapsed) {
this._menu.style.display = 'none'; //hide menu
this._inputActive = false;
return this;
}
if (this._toolbar) {
if (!this._inputBar || !this._inputActive) return this;
}
var offset = this._range.getBoundingClientRect()
, menuPadding = 10
, top = offset.top - menuPadding
, left = offset.left + (offset.width / 2)
, menu = this._menu
, menuOffset = {x: 0, y: 0}
, stylesheet = this._stylesheet;
// fixes some browser double click visual discontinuity
// if the offset has no width or height it should not be used
if (offset.width === 0 && offset.height === 0) return this;
// store the stylesheet used for positioning the menu horizontally
if (this._stylesheet === undefined) {
var style = document.createElement("style");
document.head.appendChild(style);
this._stylesheet = stylesheet = style.sheet;
}
// display block to caculate its width & height
menu.style.display = 'block';
menuOffset.x = left - (menu.clientWidth / 2);
menuOffset.y = top - menu.clientHeight;
// check to see if menu has over-extended its bounding box. if it has,
// 1) apply a new class if overflowed on top;
// 2) apply a new rule if overflowed on the left
if (stylesheet.cssRules.length > 0) {
stylesheet.deleteRule(0);
}
if (menuOffset.x < 0) {
menuOffset.x = 0;
stylesheet.insertRule('.pen-menu:after {left: ' + left + 'px;}', 0);
} else {
stylesheet.insertRule('.pen-menu:after {left: 50%; }', 0);
}
if (menuOffset.y < 0) {
menu.classList.add('pen-menu-below');
menuOffset.y = offset.top + offset.height + menuPadding;
} else {
menu.classList.remove('pen-menu-below');
}
menu.style.top = menuOffset.y + 'px';
menu.style.left = menuOffset.x + 'px';
return this;
};
Pen.prototype.stay = function(config) {
var ctx = this;
if (!window.onbeforeunload) {
window.onbeforeunload = function() {
if (!ctx._isDestroyed) return config.stayMsg;
};
}
};
Pen.prototype.destroy = function(isAJoke) {
var destroy = isAJoke ? false : true
, attr = isAJoke ? 'setAttribute' : 'removeAttribute';
if (!isAJoke) {
removeAllListeners(this);
try {
selection.removeAllRanges();
if (this._menu) this._menu.parentNode.removeChild(this._menu);
} catch (e) {/* IE throws error sometimes*/}
} else {
initToolbar(this);
initEvents(this);
}
this._isDestroyed = destroy;
this.config.editor[attr]('contenteditable', '');
return this;
};
Pen.prototype.rebuild = function() {
return this.destroy('it\'s a joke');
};
// a fallback for old browers
root.Pen = function(config) {
if (!config) return utils.log('can\'t find config', true);
var defaults = utils.merge(config)
, klass = defaults.editor.getAttribute('class');
klass = klass ? klass.replace(/\bpen\b/g, '') + ' pen-textarea ' + defaults.class : 'pen pen-textarea';
defaults.editor.setAttribute('class', klass);
defaults.editor.innerHTML = defaults.textarea;
return defaults.editor;
};
// export content as markdown
var regs = {
a: [/<a\b[^>]*href=["']([^"]+|[^']+)\b[^>]*>(.*?)<\/a>/ig, '[$2]($1)'],
img: [/<img\b[^>]*src=["']([^\"+|[^']+)[^>]*>/ig, ''],
b: [/<b\b[^>]*>(.*?)<\/b>/ig, '**$1**'],
i: [/<i\b[^>]*>(.*?)<\/i>/ig, '***$1***'],
h: [/<h([1-6])\b[^>]*>(.*?)<\/h\1>/ig, function(a, b, c) {
return '\n' + ('######'.slice(0, b)) + ' ' + c + '\n';
}],
li: [/<(li)\b[^>]*>(.*?)<\/\1>/ig, '* $2\n'],
blockquote: [/<(blockquote)\b[^>]*>(.*?)<\/\1>/ig, '\n> $2\n'],
pre: [/<pre\b[^>]*>(.*?)<\/pre>/ig, '\n```\n$1\n```\n'],
p: [/<p\b[^>]*>(.*?)<\/p>/ig, '\n$1\n'],
hr: [/<hr\b[^>]*>/ig, '\n---\n']
};
Pen.prototype.toMd = function() {
var html = this.getContent()
.replace(/\n+/g, '') // remove line break
.replace(/<([uo])l\b[^>]*>(.*?)<\/\1l>/ig, '$2'); // remove ul/ol
for(var p in regs) {
if (regs.hasOwnProperty(p))
html = html.replace.apply(html, regs[p]);
}
return html.replace(/\*{5}/g, '**');
};
// make it accessible
if (doc.getSelection) {
selection = doc.getSelection();
root.Pen = Pen;
}
}(window, document));
; browserify_shim__define__module__export__(typeof Pen != "undefined" ? Pen : window.Pen);
}).call(global, undefined, undefined, undefined, undefined, function defineExport(ex) { module.exports = ex; });
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],13:[function(require,module,exports){
(function (process){
exports.alphasort = alphasort
exports.alphasorti = alphasorti
exports.setopts = setopts
exports.ownProp = ownProp
exports.makeAbs = makeAbs
exports.finish = finish
exports.mark = mark
exports.isIgnored = isIgnored
exports.childrenIgnored = childrenIgnored
function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
}
var path = require("path")
var minimatch = require("minimatch")
var isAbsolute = require("path-is-absolute")
var Minimatch = minimatch.Minimatch
function alphasorti (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase())
}
function alphasort (a, b) {
return a.localeCompare(b)
}
function setupIgnores (self, options) {
self.ignore = options.ignore || []
if (!Array.isArray(self.ignore))
self.ignore = [self.ignore]
if (self.ignore.length) {
self.ignore = self.ignore.map(ignoreMap)
}
}
function ignoreMap (pattern) {
var gmatcher = null
if (pattern.slice(-3) === '/**') {
var gpattern = pattern.replace(/(\/\*\*)+$/, '')
gmatcher = new Minimatch(gpattern)
}
return {
matcher: new Minimatch(pattern),
gmatcher: gmatcher
}
}
function setopts (self, pattern, options) {
if (!options)
options = {}
// base-matching: just use globstar for that.
if (options.matchBase && -1 === pattern.indexOf("/")) {
if (options.noglobstar) {
throw new Error("base matching requires globstar")
}
pattern = "**/" + pattern
}
self.silent = !!options.silent
self.pattern = pattern
self.strict = options.strict !== false
self.realpath = !!options.realpath
self.realpathCache = options.realpathCache || Object.create(null)
self.follow = !!options.follow
self.dot = !!options.dot
self.mark = !!options.mark
self.nodir = !!options.nodir
if (self.nodir)
self.mark = true
self.sync = !!options.sync
self.nounique = !!options.nounique
self.nonull = !!options.nonull
self.nosort = !!options.nosort
self.nocase = !!options.nocase
self.stat = !!options.stat
self.noprocess = !!options.noprocess
self.maxLength = options.maxLength || Infinity
self.cache = options.cache || Object.create(null)
self.statCache = options.statCache || Object.create(null)
self.symlinks = options.symlinks || Object.create(null)
setupIgnores(self, options)
self.changedCwd = false
var cwd = process.cwd()
if (!ownProp(options, "cwd"))
self.cwd = cwd
else {
self.cwd = options.cwd
self.changedCwd = path.resolve(options.cwd) !== cwd
}
self.root = options.root || path.resolve(self.cwd, "/")
self.root = path.resolve(self.root)
if (process.platform === "win32")
self.root = self.root.replace(/\\/g, "/")
self.nomount = !!options.nomount
// disable comments and negation unless the user explicitly
// passes in false as the option.
options.nonegate = options.nonegate === false ? false : true
options.nocomment = options.nocomment === false ? false : true
deprecationWarning(options)
self.minimatch = new Minimatch(pattern, options)
self.options = self.minimatch.options
}
// TODO(isaacs): remove entirely in v6
// exported to reset in tests
exports.deprecationWarned
function deprecationWarning(options) {
if (!options.nonegate || !options.nocomment) {
if (process.noDeprecation !== true && !exports.deprecationWarned) {
var msg = 'glob WARNING: comments and negation will be disabled in v6'
if (process.throwDeprecation)
throw new Error(msg)
else if (process.traceDeprecation)
console.trace(msg)
else
console.error(msg)
exports.deprecationWarned = true
}
}
}
function finish (self) {
var nou = self.nounique
var all = nou ? [] : Object.create(null)
for (var i = 0, l = self.matches.length; i < l; i ++) {
var matches = self.matches[i]
if (!matches || Object.keys(matches).length === 0) {
if (self.nonull) {
// do like the shell, and spit out the literal glob
var literal = self.minimatch.globSet[i]
if (nou)
all.push(literal)
else
all[literal] = true
}
} else {
// had matches
var m = Object.keys(matches)
if (nou)
all.push.apply(all, m)
else
m.forEach(function (m) {
all[m] = true
})
}
}
if (!nou)
all = Object.keys(all)
if (!self.nosort)
all = all.sort(self.nocase ? alphasorti : alphasort)
// at *some* point we statted all of these
if (self.mark) {
for (var i = 0; i < all.length; i++) {
all[i] = self._mark(all[i])
}
if (self.nodir) {
all = all.filter(function (e) {
return !(/\/$/.test(e))
})
}
}
if (self.ignore.length)
all = all.filter(function(m) {
return !isIgnored(self, m)
})
self.found = all
}
function mark (self, p) {
var abs = makeAbs(self, p)
var c = self.cache[abs]
var m = p
if (c) {
var isDir = c === 'DIR' || Array.isArray(c)
var slash = p.slice(-1) === '/'
if (isDir && !slash)
m += '/'
else if (!isDir && slash)
m = m.slice(0, -1)
if (m !== p) {
var mabs = makeAbs(self, m)
self.statCache[mabs] = self.statCache[abs]
self.cache[mabs] = self.cache[abs]
}
}
return m
}
// lotta situps...
function makeAbs (self, f) {
var abs = f
if (f.charAt(0) === '/') {
abs = path.join(self.root, f)
} else if (isAbsolute(f) || f === '') {
abs = f
} else if (self.changedCwd) {
abs = path.resolve(self.cwd, f)
} else {
abs = path.resolve(f)
}
return abs
}
// Return true, if pattern ends with globstar '**', for the accompanying parent directory.
// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents
function isIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path))
})
}
function childrenIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return !!(item.gmatcher && item.gmatcher.match(path))
})
}
}).call(this,require('_process'))
},{"_process":31,"minimatch":18,"path":30,"path-is-absolute":24}],14:[function(require,module,exports){
(function (process){
// Approach:
//
// 1. Get the minimatch set
// 2. For each pattern in the set, PROCESS(pattern, false)
// 3. Store matches per-set, then uniq them
//
// PROCESS(pattern, inGlobStar)
// Get the first [n] items from pattern that are all strings
// Join these together. This is PREFIX.
// If there is no more remaining, then stat(PREFIX) and
// add to matches if it succeeds. END.
//
// If inGlobStar and PREFIX is symlink and points to dir
// set ENTRIES = []
// else readdir(PREFIX) as ENTRIES
// If fail, END
//
// with ENTRIES
// If pattern[n] is GLOBSTAR
// // handle the case where the globstar match is empty
// // by pruning it out, and testing the resulting pattern
// PROCESS(pattern[0..n] + pattern[n+1 .. $], false)
// // handle other cases.
// for ENTRY in ENTRIES (not dotfiles)
// // attach globstar + tail onto the entry
// // Mark that this entry is a globstar match
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true)
//
// else // not globstar
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
// Test ENTRY against pattern[n]
// If fails, continue
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
//
// Caveat:
// Cache all stats and readdirs results to minimize syscall. Since all
// we ever care about is existence and directory-ness, we can just keep
// `true` for files, and [children,...] for directories, or `false` for
// things that don't exist.
module.exports = glob
var fs = require('fs')
var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var inherits = require('inherits')
var EE = require('events').EventEmitter
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var globSync = require('./sync.js')
var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
var ownProp = common.ownProp
var inflight = require('inflight')
var util = require('util')
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored
var once = require('once')
function glob (pattern, options, cb) {
if (typeof options === 'function') cb = options, options = {}
if (!options) options = {}
if (options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return globSync(pattern, options)
}
return new Glob(pattern, options, cb)
}
glob.sync = globSync
var GlobSync = glob.GlobSync = globSync.GlobSync
// old api surface
glob.glob = glob
glob.hasMagic = function (pattern, options_) {
var options = util._extend({}, options_)
options.noprocess = true
var g = new Glob(pattern, options)
var set = g.minimatch.set
if (set.length > 1)
return true
for (var j = 0; j < set[0].length; j++) {
if (typeof set[0][j] !== 'string')
return true
}
return false
}
glob.Glob = Glob
inherits(Glob, EE)
function Glob (pattern, options, cb) {
if (typeof options === 'function') {
cb = options
options = null
}
if (options && options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return new GlobSync(pattern, options)
}
if (!(this instanceof Glob))
return new Glob(pattern, options, cb)
setopts(this, pattern, options)
this._didRealPath = false
// process each pattern in the minimatch set
var n = this.minimatch.set.length
// The matches are stored as {<filename>: true,...} so that
// duplicates are automagically pruned.
// Later, we do an Object.keys() on these.
// Keep them as a list so we can fill in when nonull is set.
this.matches = new Array(n)
if (typeof cb === 'function') {
cb = once(cb)
this.on('error', cb)
this.on('end', function (matches) {
cb(null, matches)
})
}
var self = this
var n = this.minimatch.set.length
this._processing = 0
this.matches = new Array(n)
this._emitQueue = []
this._processQueue = []
this.paused = false
if (this.noprocess)
return this
if (n === 0)
return done()
for (var i = 0; i < n; i ++) {
this._process(this.minimatch.set[i], i, false, done)
}
function done () {
--self._processing
if (self._processing <= 0)
self._finish()
}
}
Glob.prototype._finish = function () {
assert(this instanceof Glob)
if (this.aborted)
return
if (this.realpath && !this._didRealpath)
return this._realpath()
common.finish(this)
this.emit('end', this.found)
}
Glob.prototype._realpath = function () {
if (this._didRealpath)
return
this._didRealpath = true
var n = this.matches.length
if (n === 0)
return this._finish()
var self = this
for (var i = 0; i < this.matches.length; i++)
this._realpathSet(i, next)
function next () {
if (--n === 0)
self._finish()
}
}
Glob.prototype._realpathSet = function (index, cb) {
var matchset = this.matches[index]
if (!matchset)
return cb()
var found = Object.keys(matchset)
var self = this
var n = found.length
if (n === 0)
return cb()
var set = this.matches[index] = Object.create(null)
found.forEach(function (p, i) {
// If there's a problem with the stat, then it means that
// one or more of the links in the realpath couldn't be
// resolved. just return the abs value in that case.
p = self._makeAbs(p)
fs.realpath(p, self.realpathCache, function (er, real) {
if (!er)
set[real] = true
else if (er.syscall === 'stat')
set[p] = true
else
self.emit('error', er) // srsly wtf right here
if (--n === 0) {
self.matches[index] = set
cb()
}
})
})
}
Glob.prototype._mark = function (p) {
return common.mark(this, p)
}
Glob.prototype._makeAbs = function (f) {
return common.makeAbs(this, f)
}
Glob.prototype.abort =