UNPKG

brutaljs

Version:

BrutalJS ========

1,674 lines (1,403 loc) 635 kB
(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>&nbsp;> <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\' &amp;&amp; (val.options._meta !== undefined &amp;&amp; val.options._meta.plain)}" value="{model.data[key]}" class="form-control"> <pen data-key="{key}" if="{val.instance === \'String\' &amp;&amp; (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>&nbsp;> {modelName} &nbsp;&nbsp;&nbsp;<a href="/admin#/app/new/{modelName}" class="btn btn-primary btn-sm">Add New</a></h2> <table if="items.length &gt; 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, '![]($1)'], 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 =