/*! * Sir Trevor JS v0.5.0-beta1 * * Released under the MIT license * www.opensource.org/licenses/MIT * * 2015-01-09 */ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.SirTrevor=e()}}(function(){var define,module,exports;return (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 // For all details and docs: https://github.com/paulmillr/array.prototype.find // Fixes and tests supplied by Duncan Hall (function(globals){ if (Array.prototype.find) return; var find = function(predicate) { var list = Object(this); var length = list.length < 0 ? 0 : list.length >>> 0; // ES.ToUint32; if (length === 0) return undefined; if (typeof predicate !== 'function' || Object.prototype.toString.call(predicate) !== '[object Function]') { throw new TypeError('Array#find: predicate must be a function'); } var thisArg = arguments[1]; for (var i = 0, value; i < length; i++) { value = list[i]; if (predicate.call(thisArg, value, i, list)) return value; } return undefined; }; if (Object.defineProperty) { try { Object.defineProperty(Array.prototype, 'find', { value: find, configurable: true, enumerable: false, writable: true }); } catch(e) {} } if (!Array.prototype.find) { Array.prototype.find = find; } })(this); },{}],3:[function(require,module,exports){ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as a module. define('eventable', function() { return (root.Eventable = factory()); }); } else if (typeof exports !== 'undefined') { // Node. Does not work with strict CommonJS, but only CommonJS-like // enviroments that support module.exports, like Node. module.exports = factory(); } else { // Browser globals root.Eventable = factory(); } }(this, function() { // Copy and pasted straight out of Backbone 1.0.0 // We'll try and keep this updated to the latest var array = []; var slice = array.slice; function once(func) { var memo, times = 2; return function() { if (--times > 0) { memo = func.apply(this, arguments); } else { func = null; } return memo; }; } // Backbone.Events // --------------- // A module that can be mixed in to *any object* in order to provide it with // custom events. You may bind with `on` or remove with `off` callback // functions to an event; `trigger`-ing an event fires all callbacks in // succession. // // var object = {}; // extend(object, Backbone.Events); // object.on('expand', function(){ alert('expanded'); }); // object.trigger('expand'); // var Eventable = { // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. on: function(name, callback, context) { if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; this._events || (this._events = {}); var events = this._events[name] || (this._events[name] = []); events.push({callback: callback, context: context, ctx: context || this}); return this; }, // Bind an event to only be triggered a single time. After the first time // the callback is invoked, it will be removed. once: function(name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; var func = once(function() { self.off(name, func); callback.apply(this, arguments); }); func._callback = callback; return this.on(name, func, context); }, // Remove one or many callbacks. If `context` is null, removes all // callbacks with that function. If `callback` is null, removes all // callbacks for the event. If `name` is null, removes all bound // callbacks for all events. off: function(name, callback, context) { var retain, ev, events, names, i, l, j, k; if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; if (!name && !callback && !context) { this._events = {}; return this; } names = name ? [name] : Object.keys(this._events); for (i = 0, l = names.length; i < l; i++) { name = names[i]; if (events = this._events[name]) { this._events[name] = retain = []; if (callback || context) { for (j = 0, k = events.length; j < k; j++) { ev = events[j]; if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || (context && context !== ev.context)) { retain.push(ev); } } } if (!retain.length) delete this._events[name]; } } return this; }, // Trigger one or many events, firing all bound callbacks. Callbacks are // passed the same arguments as `trigger` is, apart from the event name // (unless you're listening on `"all"`, which will cause your callback to // receive the true name of the event as the first argument). trigger: function(name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; var events = this._events[name]; var allEvents = this._events.all; if (events) triggerEvents(events, args); if (allEvents) triggerEvents(allEvents, arguments); return this; }, // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. stopListening: function(obj, name, callback) { var listeners = this._listeners; if (!listeners) return this; var deleteListener = !name && !callback; if (typeof name === 'object') callback = this; if (obj) (listeners = {})[obj._listenerId] = obj; for (var id in listeners) { listeners[id].off(name, callback, this); if (deleteListener) delete this._listeners[id]; } return this; } }; // Regular expression used to split event strings. var eventSplitter = /\s+/; // Implement fancy features of the Events API such as multiple event // names `"change blur"` and jQuery-style event maps `{change: action}` // in terms of the existing API. var eventsApi = function(obj, action, name, rest) { if (!name) return true; // Handle event maps. if (typeof name === 'object') { for (var key in name) { obj[action].apply(obj, [key, name[key]].concat(rest)); } return false; } // Handle space separated event names. if (eventSplitter.test(name)) { var names = name.split(eventSplitter); for (var i = 0, l = names.length; i < l; i++) { obj[action].apply(obj, [names[i]].concat(rest)); } return false; } return true; }; // A difficult-to-believe, but optimized internal dispatch function for // triggering events. Tries to keep the usual cases speedy (most internal // Backbone events have 3 arguments). var triggerEvents = function(events, args) { var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; switch (args.length) { case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); } }; var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; // Inversion-of-control versions of `on` and `once`. Tell *this* object to // listen to an event in another object ... keeping track of what it's // listening to. function addListenMethod(method, implementation) { Eventable[method] = function(obj, name, callback) { var listeners = this._listeners || (this._listeners = {}); var id = obj._listenerId || (obj._listenerId = (new Date()).getTime()); listeners[id] = obj; if (typeof name === 'object') callback = this; obj[implementation](name, callback, this); return this; }; } addListenMethod('listenTo', 'on'); addListenMethod('listenToOnce', 'once'); // Aliases for backwards compatibility. Eventable.bind = Eventable.on; Eventable.unbind = Eventable.off; return Eventable; })); },{}],4:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var forOwn = require('lodash.forown'), isFunction = require('lodash.isfunction'); /** `Object#toString` result shortcuts */ var argsClass = '[object Arguments]', arrayClass = '[object Array]', objectClass = '[object Object]', stringClass = '[object String]'; /** Used for native method references */ var objectProto = Object.prototype; /** Used to resolve the internal [[Class]] of values */ var toString = objectProto.toString; /** * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a * length of `0` and objects with no own enumerable properties are considered * "empty". * * @static * @memberOf _ * @category Objects * @param {Array|Object|string} value The value to inspect. * @returns {boolean} Returns `true` if the `value` is empty, else `false`. * @example * * _.isEmpty([1, 2, 3]); * // => false * * _.isEmpty({}); * // => true * * _.isEmpty(''); * // => true */ function isEmpty(value) { var result = true; if (!value) { return result; } var className = toString.call(value), length = value.length; if ((className == arrayClass || className == stringClass || className == argsClass ) || (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { return !length; } forOwn(value, function() { return (result = false); }); return result; } module.exports = isEmpty; },{"lodash.forown":5,"lodash.isfunction":28}],5:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var baseCreateCallback = require('lodash._basecreatecallback'), keys = require('lodash.keys'), objectTypes = require('lodash._objecttypes'); /** * Iterates over own enumerable properties of an object, executing the callback * for each property. The callback is bound to `thisArg` and invoked with three * arguments; (value, key, object). Callbacks may exit iteration early by * explicitly returning `false`. * * @static * @memberOf _ * @type Function * @category Objects * @param {Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {*} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `object`. * @example * * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { * console.log(key); * }); * // => logs '0', '1', and 'length' (property order is not guaranteed across environments) */ var forOwn = function(collection, callback, thisArg) { var index, iterable = collection, result = iterable; if (!iterable) return result; if (!objectTypes[typeof iterable]) return result; callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); var ownIndex = -1, ownProps = objectTypes[typeof iterable] && keys(iterable), length = ownProps ? ownProps.length : 0; while (++ownIndex < length) { index = ownProps[ownIndex]; if (callback(iterable[index], index, collection) === false) return result; } return result }; module.exports = forOwn; },{"lodash._basecreatecallback":6,"lodash._objecttypes":24,"lodash.keys":25}],6:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var bind = require('lodash.bind'), identity = require('lodash.identity'), setBindData = require('lodash._setbinddata'), support = require('lodash.support'); /** Used to detected named functions */ var reFuncName = /^\s*function[ \n\r\t]+\w/; /** Used to detect functions containing a `this` reference */ var reThis = /\bthis\b/; /** Native method shortcuts */ var fnToString = Function.prototype.toString; /** * The base implementation of `_.createCallback` without support for creating * "_.pluck" or "_.where" style callbacks. * * @private * @param {*} [func=identity] The value to convert to a callback. * @param {*} [thisArg] The `this` binding of the created callback. * @param {number} [argCount] The number of arguments the callback accepts. * @returns {Function} Returns a callback function. */ function baseCreateCallback(func, thisArg, argCount) { if (typeof func != 'function') { return identity; } // exit early for no `thisArg` or already bound by `Function#bind` if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } var bindData = func.__bindData__; if (typeof bindData == 'undefined') { if (support.funcNames) { bindData = !func.name; } bindData = bindData || !support.funcDecomp; if (!bindData) { var source = fnToString.call(func); if (!support.funcNames) { bindData = !reFuncName.test(source); } if (!bindData) { // checks if `func` references the `this` keyword and stores the result bindData = reThis.test(source); setBindData(func, bindData); } } } // exit early if there are no `this` references or `func` is bound if (bindData === false || (bindData !== true && bindData[1] & 1)) { return func; } switch (argCount) { case 1: return function(value) { return func.call(thisArg, value); }; case 2: return function(a, b) { return func.call(thisArg, a, b); }; case 3: return function(value, index, collection) { return func.call(thisArg, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(thisArg, accumulator, value, index, collection); }; } return bind(func, thisArg); } module.exports = baseCreateCallback; },{"lodash._setbinddata":7,"lodash.bind":10,"lodash.identity":21,"lodash.support":22}],7:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var isNative = require('lodash._isnative'), noop = require('lodash.noop'); /** Used as the property descriptor for `__bindData__` */ var descriptor = { 'configurable': false, 'enumerable': false, 'value': null, 'writable': false }; /** Used to set meta data on functions */ var defineProperty = (function() { // IE 8 only accepts DOM elements try { var o = {}, func = isNative(func = Object.defineProperty) && func, result = func(o, o, o) && func; } catch(e) { } return result; }()); /** * Sets `this` binding data on a given function. * * @private * @param {Function} func The function to set data on. * @param {Array} value The data array to set. */ var setBindData = !defineProperty ? noop : function(func, value) { descriptor.value = value; defineProperty(func, '__bindData__', descriptor); }; module.exports = setBindData; },{"lodash._isnative":8,"lodash.noop":9}],8:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** Used for native method references */ var objectProto = Object.prototype; /** Used to resolve the internal [[Class]] of values */ var toString = objectProto.toString; /** Used to detect if a method is native */ var reNative = RegExp('^' + String(toString) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/toString| for [^\]]+/g, '.*?') + '$' ); /** * Checks if `value` is a native function. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. */ function isNative(value) { return typeof value == 'function' && reNative.test(value); } module.exports = isNative; },{}],9:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** * A no-operation function. * * @static * @memberOf _ * @category Utilities * @example * * var object = { 'name': 'fred' }; * _.noop(object) === undefined; * // => true */ function noop() { // no operation performed } module.exports = noop; },{}],10:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var createWrapper = require('lodash._createwrapper'), slice = require('lodash._slice'); /** * Creates a function that, when called, invokes `func` with the `this` * binding of `thisArg` and prepends any additional `bind` arguments to those * provided to the bound function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to bind. * @param {*} [thisArg] The `this` binding of `func`. * @param {...*} [arg] Arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * var func = function(greeting) { * return greeting + ' ' + this.name; * }; * * func = _.bind(func, { 'name': 'fred' }, 'hi'); * func(); * // => 'hi fred' */ function bind(func, thisArg) { return arguments.length > 2 ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) : createWrapper(func, 1, null, null, thisArg); } module.exports = bind; },{"lodash._createwrapper":11,"lodash._slice":20}],11:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var baseBind = require('lodash._basebind'), baseCreateWrapper = require('lodash._basecreatewrapper'), isFunction = require('lodash.isfunction'), slice = require('lodash._slice'); /** * Used for `Array` method references. * * Normally `Array.prototype` would suffice, however, using an array literal * avoids issues in Narwhal. */ var arrayRef = []; /** Native method shortcuts */ var push = arrayRef.push, unshift = arrayRef.unshift; /** * Creates a function that, when called, either curries or invokes `func` * with an optional `this` binding and partially applied arguments. * * @private * @param {Function|string} func The function or method name to reference. * @param {number} bitmask The bitmask of method flags to compose. * The bitmask may be composed of the following flags: * 1 - `_.bind` * 2 - `_.bindKey` * 4 - `_.curry` * 8 - `_.curry` (bound) * 16 - `_.partial` * 32 - `_.partialRight` * @param {Array} [partialArgs] An array of arguments to prepend to those * provided to the new function. * @param {Array} [partialRightArgs] An array of arguments to append to those * provided to the new function. * @param {*} [thisArg] The `this` binding of `func`. * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new function. */ function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { var isBind = bitmask & 1, isBindKey = bitmask & 2, isCurry = bitmask & 4, isCurryBound = bitmask & 8, isPartial = bitmask & 16, isPartialRight = bitmask & 32; if (!isBindKey && !isFunction(func)) { throw new TypeError; } if (isPartial && !partialArgs.length) { bitmask &= ~16; isPartial = partialArgs = false; } if (isPartialRight && !partialRightArgs.length) { bitmask &= ~32; isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; if (bindData && bindData !== true) { // clone `bindData` bindData = slice(bindData); if (bindData[2]) { bindData[2] = slice(bindData[2]); } if (bindData[3]) { bindData[3] = slice(bindData[3]); } // set `thisBinding` is not previously bound if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } // set if previously bound but not currently (subsequent curried functions) if (!isBind && bindData[1] & 1) { bitmask |= 8; } // set curried arity if not yet set if (isCurry && !(bindData[1] & 4)) { bindData[5] = arity; } // append partial left arguments if (isPartial) { push.apply(bindData[2] || (bindData[2] = []), partialArgs); } // append partial right arguments if (isPartialRight) { unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs); } // merge flags bindData[1] |= bitmask; return createWrapper.apply(null, bindData); } // fast path for `_.bind` var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); } module.exports = createWrapper; },{"lodash._basebind":12,"lodash._basecreatewrapper":16,"lodash._slice":20,"lodash.isfunction":28}],12:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var baseCreate = require('lodash._basecreate'), isObject = require('lodash.isobject'), setBindData = require('lodash._setbinddata'), slice = require('lodash._slice'); /** * Used for `Array` method references. * * Normally `Array.prototype` would suffice, however, using an array literal * avoids issues in Narwhal. */ var arrayRef = []; /** Native method shortcuts */ var push = arrayRef.push; /** * The base implementation of `_.bind` that creates the bound function and * sets its meta data. * * @private * @param {Array} bindData The bind data array. * @returns {Function} Returns the new bound function. */ function baseBind(bindData) { var func = bindData[0], partialArgs = bindData[2], thisArg = bindData[4]; function bound() { // `Function#bind` spec // http://es5.github.io/#x15.3.4.5 if (partialArgs) { // avoid `arguments` object deoptimizations by using `slice` instead // of `Array.prototype.slice.call` and not assigning `arguments` to a // variable as a ternary expression var args = slice(partialArgs); push.apply(args, arguments); } // mimic the constructor's `return` behavior // http://es5.github.io/#x13.2.2 if (this instanceof bound) { // ensure `new bound` is an instance of `func` var thisBinding = baseCreate(func.prototype), result = func.apply(thisBinding, args || arguments); return isObject(result) ? result : thisBinding; } return func.apply(thisArg, args || arguments); } setBindData(bound, bindData); return bound; } module.exports = baseBind; },{"lodash._basecreate":13,"lodash._setbinddata":7,"lodash._slice":20,"lodash.isobject":29}],13:[function(require,module,exports){ (function (global){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var isNative = require('lodash._isnative'), isObject = require('lodash.isobject'), noop = require('lodash.noop'); /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate; /** * The base implementation of `_.create` without support for assigning * properties to the created object. * * @private * @param {Object} prototype The object to inherit from. * @returns {Object} Returns the new object. */ function baseCreate(prototype, properties) { return isObject(prototype) ? nativeCreate(prototype) : {}; } // fallback for browsers without `Object.create` if (!nativeCreate) { baseCreate = (function() { function Object() {} return function(prototype) { if (isObject(prototype)) { Object.prototype = prototype; var result = new Object; Object.prototype = null; } return result || global.Object(); }; }()); } module.exports = baseCreate; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"lodash._isnative":14,"lodash.isobject":29,"lodash.noop":15}],14:[function(require,module,exports){ module.exports=require(8) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash._isnative/index.js":8}],15:[function(require,module,exports){ module.exports=require(9) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash.noop/index.js":9}],16:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var baseCreate = require('lodash._basecreate'), isObject = require('lodash.isobject'), setBindData = require('lodash._setbinddata'), slice = require('lodash._slice'); /** * Used for `Array` method references. * * Normally `Array.prototype` would suffice, however, using an array literal * avoids issues in Narwhal. */ var arrayRef = []; /** Native method shortcuts */ var push = arrayRef.push; /** * The base implementation of `createWrapper` that creates the wrapper and * sets its meta data. * * @private * @param {Array} bindData The bind data array. * @returns {Function} Returns the new function. */ function baseCreateWrapper(bindData) { var func = bindData[0], bitmask = bindData[1], partialArgs = bindData[2], partialRightArgs = bindData[3], thisArg = bindData[4], arity = bindData[5]; var isBind = bitmask & 1, isBindKey = bitmask & 2, isCurry = bitmask & 4, isCurryBound = bitmask & 8, key = func; function bound() { var thisBinding = isBind ? thisArg : this; if (partialArgs) { var args = slice(partialArgs); push.apply(args, arguments); } if (partialRightArgs || isCurry) { args || (args = slice(arguments)); if (partialRightArgs) { push.apply(args, partialRightArgs); } if (isCurry && args.length < arity) { bitmask |= 16 & ~32; return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); } } args || (args = arguments); if (isBindKey) { func = thisBinding[key]; } if (this instanceof bound) { thisBinding = baseCreate(func.prototype); var result = func.apply(thisBinding, args); return isObject(result) ? result : thisBinding; } return func.apply(thisBinding, args); } setBindData(bound, bindData); return bound; } module.exports = baseCreateWrapper; },{"lodash._basecreate":17,"lodash._setbinddata":7,"lodash._slice":20,"lodash.isobject":29}],17:[function(require,module,exports){ module.exports=require(13) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash.bind/node_modules/lodash._createwrapper/node_modules/lodash._basebind/node_modules/lodash._basecreate/index.js":13,"lodash._isnative":18,"lodash.isobject":29,"lodash.noop":19}],18:[function(require,module,exports){ module.exports=require(8) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash._isnative/index.js":8}],19:[function(require,module,exports){ module.exports=require(9) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash.noop/index.js":9}],20:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** * Slices the `collection` from the `start` index up to, but not including, * the `end` index. * * Note: This function is used instead of `Array#slice` to support node lists * in IE < 9 and to ensure dense arrays are returned. * * @private * @param {Array|Object|string} collection The collection to slice. * @param {number} start The start index. * @param {number} end The end index. * @returns {Array} Returns the new array. */ function slice(array, start, end) { start || (start = 0); if (typeof end == 'undefined') { end = array ? array.length : 0; } var index = -1, length = end - start || 0, result = Array(length < 0 ? 0 : length); while (++index < length) { result[index] = array[start + index]; } return result; } module.exports = slice; },{}],21:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** * This method returns the first argument provided to it. * * @static * @memberOf _ * @category Utilities * @param {*} value Any value. * @returns {*} Returns `value`. * @example * * var object = { 'name': 'fred' }; * _.identity(object) === object; * // => true */ function identity(value) { return value; } module.exports = identity; },{}],22:[function(require,module,exports){ (function (global){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var isNative = require('lodash._isnative'); /** Used to detect functions containing a `this` reference */ var reThis = /\bthis\b/; /** * An object used to flag environments features. * * @static * @memberOf _ * @type Object */ var support = {}; /** * Detect if functions can be decompiled by `Function#toString` * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). * * @memberOf _.support * @type boolean */ support.funcDecomp = !isNative(global.WinRTError) && reThis.test(function() { return this; }); /** * Detect if `Function#name` is supported (all but IE). * * @memberOf _.support * @type boolean */ support.funcNames = typeof Function.name == 'string'; module.exports = support; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"lodash._isnative":23}],23:[function(require,module,exports){ module.exports=require(8) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash._isnative/index.js":8}],24:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** Used to determine if values are of the language type Object */ var objectTypes = { 'boolean': false, 'function': true, 'object': true, 'number': false, 'string': false, 'undefined': false }; module.exports = objectTypes; },{}],25:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var isNative = require('lodash._isnative'), isObject = require('lodash.isobject'), shimKeys = require('lodash._shimkeys'); /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys; /** * Creates an array composed of the own enumerable property names of an object. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns an array of property names. * @example * * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) */ var keys = !nativeKeys ? shimKeys : function(object) { if (!isObject(object)) { return []; } return nativeKeys(object); }; module.exports = keys; },{"lodash._isnative":26,"lodash._shimkeys":27,"lodash.isobject":29}],26:[function(require,module,exports){ module.exports=require(8) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._basecreatecallback/node_modules/lodash._setbinddata/node_modules/lodash._isnative/index.js":8}],27:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var objectTypes = require('lodash._objecttypes'); /** Used for native method references */ var objectProto = Object.prototype; /** Native method shortcuts */ var hasOwnProperty = objectProto.hasOwnProperty; /** * A fallback implementation of `Object.keys` which produces an array of the * given object's own enumerable property names. * * @private * @type Function * @param {Object} object The object to inspect. * @returns {Array} Returns an array of property names. */ var shimKeys = function(object) { var index, iterable = object, result = []; if (!iterable) return result; if (!(objectTypes[typeof object])) return result; for (index in iterable) { if (hasOwnProperty.call(iterable, index)) { result.push(index); } } return result }; module.exports = shimKeys; },{"lodash._objecttypes":24}],28:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** * Checks if `value` is a function. * * @static * @memberOf _ * @category Objects * @param {*} value The value to check. * @returns {boolean} Returns `true` if the `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true */ function isFunction(value) { return typeof value == 'function'; } module.exports = isFunction; },{}],29:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var objectTypes = require('lodash._objecttypes'); /** * Checks if `value` is the language type of Object. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @category Objects * @param {*} value The value to check. * @returns {boolean} Returns `true` if the `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(1); * // => false */ function isObject(value) { // check if the value is the ECMAScript language type of Object // http://es5.github.io/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 return !!(value && objectTypes[typeof value]); } module.exports = isObject; },{"lodash._objecttypes":30}],30:[function(require,module,exports){ module.exports=require(24) },{"/Users/andrewwalker/sites/sir-trevor-js/node_modules/lodash.isempty/node_modules/lodash.forown/node_modules/lodash._objecttypes/index.js":24}],31:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** `Object#toString` result shortcuts */ var stringClass = '[object String]'; /** Used for native method references */ var objectProto = Object.prototype; /** Used to resolve the internal [[Class]] of values */ var toString = objectProto.toString; /** * Checks if `value` is a string. * * @static * @memberOf _ * @category Objects * @param {*} value The value to check. * @returns {boolean} Returns `true` if the `value` is a string, else `false`. * @example * * _.isString('fred'); * // => true */ function isString(value) { return typeof value == 'string' || value && typeof value == 'object' && toString.call(value) == stringClass || false; } module.exports = isString; },{}],32:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** * Checks if `value` is `undefined`. * * @static * @memberOf _ * @category Objects * @param {*} value The value to check. * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`. * @example * * _.isUndefined(void 0); * // => true */ function isUndefined(value) { return typeof value == 'undefined'; } module.exports = isUndefined; },{}],33:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var isFunction = require('lodash.isfunction'); /** * Resolves the value of property `key` on `object`. If `key` is a function * it will be invoked with the `this` binding of `object` and its result returned, * else the property value is returned. If `object` is falsey then `undefined` * is returned. * * @static * @memberOf _ * @category Utilities * @param {Object} object The object to inspect. * @param {string} key The name of the property to resolve. * @returns {*} Returns the resolved value. * @example * * var object = { * 'cheese': 'crumpets', * 'stuff': function() { * return 'nonsense'; * } * }; * * _.result(object, 'cheese'); * // => 'crumpets' * * _.result(object, 'stuff'); * // => 'nonsense' */ function result(object, key) { if (object) { var value = object[key]; return isFunction(value) ? object[key]() : value; } } module.exports = result; },{"lodash.isfunction":28}],34:[function(require,module,exports){ /** * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm/` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ var defaults = require('lodash.defaults'), escape = require('lodash.escape'), escapeStringChar = require('lodash._escapestringchar'), keys = require('lodash.keys'), reInterpolate = require('lodash._reinterpolate'), templateSettings = require('lodash.templatesettings'), values = require('lodash.values'); /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** * Used to match ES6 template delimiters * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to ensure capturing order of template delimiters */ var reNoMatch = /($^)/; /** Used to match unescaped characters in compiled string literals */ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; /** * A micro-templating method that handles arbitrary delimiters, preserves * whitespace, and correctly escapes quotes within interpolated code. * * Note: In the development build, `_.template` utilizes sourceURLs for easier * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl * * For more information on precompiling templates see: * http://lodash.com/custom-builds * * For more information on Chrome extension sandboxes see: * http://developer.chrome.com/stable/extensions/sandboxingEval.html * * @static * @memberOf _ * @category Utilities * @param {string} text The template text. * @param {Object} data The data object used to populate the text. * @param {Object} [options] The options object. * @param {RegExp} [options.escape] The "escape" delimiter. * @param {RegExp} [options.evaluate] The "evaluate" delimiter. * @param {Object} [options.imports] An object to import into the template as local variables. * @param {RegExp} [options.interpolate] The "interpolate" delimiter. * @param {string} [sourceURL] The sourceURL of the template's compiled source. * @param {string} [variable] The data object variable name. * @returns {Function|string} Returns a compiled function when no `data` object * is given, else it returns the interpolated text. * @example * * // using the "interpolate" delimiter to create a compiled template * var compiled = _.template('hello <%= name %>'); * compiled({ 'name': 'fred' }); * // => 'hello fred' * * // using the "escape" delimiter to escape HTML in data property values * _.template('<%- value %>', { 'value': '' ].join("\n")); module.exports = Block.extend({ type: "tweet", droppable: true, pastable: true, fetchable: true, drop_options: { re_render_on_reorder: true }, title: function(){ return i18n.t('blocks:tweet:title'); }, fetchUrl: function(tweetID) { return "/tweets/?tweet_id=" + tweetID; }, icon_name: 'twitter', loadData: function(data) { if (_.isUndefined(data.status_url)) { data.status_url = ''; } this.$inner.find('iframe').remove(); this.$inner.prepend(tweet_template(data)); }, onContentPasted: function(event){ // Content pasted. Delegate to the drop parse method var input = $(event.target), val = input.val(); // Pass this to the same handler as onDrop this.handleTwitterDropPaste(val); }, handleTwitterDropPaste: function(url){ if (!this.validTweetUrl(url)) { utils.log("Invalid Tweet URL"); return; } // Twitter status var tweetID = url.match(/[^\/]+$/); if (!_.isEmpty(tweetID)) { this.loading(); tweetID = tweetID[0]; var ajaxOptions = { url: this.fetchUrl(tweetID), dataType: "json" }; this.fetch(ajaxOptions, this.onTweetSuccess, this.onTweetFail); } }, validTweetUrl: function(url) { return (utils.isURI(url) && url.indexOf("twitter") !== -1 && url.indexOf("status") !== -1); }, onTweetSuccess: function(data) { // Parse the twitter object into something a bit slimmer.. var obj = { user: { profile_image_url: data.user.profile_image_url, profile_image_url_https: data.user.profile_image_url_https, screen_name: data.user.screen_name, name: data.user.name }, id: data.id_str, text: data.text, created_at: data.created_at, entities: data.entities, status_url: "https://twitter.com/" + data.user.screen_name + "/status/" + data.id_str }; this.setAndLoadData(obj); this.ready(); }, onTweetFail: function() { this.addMessage(i18n.t("blocks:tweet:fetch_error")); this.ready(); }, onDrop: function(transferData){ var url = transferData.getData('text/plain'); this.handleTwitterDropPaste(url); } }); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../block":146,"../lodash":178,"../utils":184}],161:[function(require,module,exports){ "use strict"; var _ = require('../lodash'); var utils = require('../utils'); var Block = require('../block'); module.exports = Block.extend({ // more providers at https://gist.github.com/jeffling/a9629ae28e076785a14f providers: { vimeo: { regex: /(?:http[s]?:\/\/)?(?:www.)?vimeo.com\/(.+)/, html: "" }, youtube: { regex: /(?:http[s]?:\/\/)?(?:www.)?(?:(?:youtube.com\/watch\?(?:.*)(?:v=))|(?:youtu.be\/))([^&].+)/, html: "" } }, type: 'video', title: function() { return i18n.t('blocks:video:title'); }, droppable: true, pastable: true, icon_name: 'video', loadData: function(data){ if (!this.providers.hasOwnProperty(data.source)) { return; } var source = this.providers[data.source]; var protocol = window.location.protocol === "file:" ? "http:" : window.location.protocol; var aspectRatioClass = source.square ? 'with-square-media' : 'with-sixteen-by-nine-media'; this.$editor .addClass('st-block__editor--' + aspectRatioClass) .html(_.template(source.html, { protocol: protocol, remote_id: data.remote_id, width: this.$editor.width() // for videos like vine })); }, onContentPasted: function(event){ this.handleDropPaste(event.target.value); }, matchVideoProvider: function(provider, index, url) { var match = provider.regex.exec(url); if(match == null || _.isUndefined(match[1])) { return {}; } return { source: index, remote_id: match[1] }; }, handleDropPaste: function(url){ if (!utils.isURI(url)) { return; } for(var key in this.providers) { if (!this.providers.hasOwnProperty(key)) { continue; } this.setAndLoadData( this.matchVideoProvider(this.providers[key], key, url) ); } }, onDrop: function(transferData){ var url = transferData.getData('text/plain'); this.handleDropPaste(url); } }); },{"../block":146,"../lodash":178,"../utils":184}],162:[function(require,module,exports){ "use strict"; var drop_options = { html: ['
', '<%= _.result(block, "icon_name") %>', '

<%= i18n.t("general:drop", { block: "" + _.result(block, "title") + "" }) %>', '

'].join('\n'), re_render_on_reorder: false }; var paste_options = { html: ['"', ' class="st-block__paste-input st-paste-block">'].join('') }; var upload_options = { html: [ '
', '', '', '
' ].join('\n') }; module.exports = { debug: false, scribeDebug: false, skipValidation: false, version: "0.4.0", language: "en", instances: [], defaults: { defaultType: false, spinner: { className: 'st-spinner', lines: 9, length: 8, width: 3, radius: 6, color: '#000', speed: 1.4, trail: 57, shadow: false, left: '50%', top: '50%' }, Block: { drop_options: drop_options, paste_options: paste_options, upload_options: upload_options, }, blockLimit: 0, blockTypeLimits: {}, required: [], uploadUrl: '/attachments', baseImageUrl: '/sir-trevor-uploads/', errorsContainer: undefined, convertToMarkdown: false, convertFromMarkdown: true, formatBar: { commands: [ { name: "Bold", title: "bold", cmd: "bold", keyCode: 66, text : "B" }, { name: "Italic", title: "italic", cmd: "italic", keyCode: 73, text : "i" }, { name: "Link", title: "link", iconName: "link", cmd: "linkPrompt", text : "link", }, { name: "Unlink", title: "unlink", iconName: "link", cmd: "unlink", text : "link", }, ], }, } }; },{}],163:[function(require,module,exports){ (function (global){ "use strict"; /* * Sir Trevor Editor * -- * Represents one Sir Trevor editor instance (with multiple blocks) * Each block references this instance. * BlockTypes are global however. */ var _ = require('./lodash'); var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var config = require('./config'); var utils = require('./utils'); var Events = require('./events'); var EventBus = require('./event-bus'); var FormEvents = require('./form-events'); var BlockControls = require('./block-controls'); var BlockManager = require('./block-manager'); var FloatingBlockControls = require('./floating-block-controls'); var FormatBar = require('./format-bar'); var EditorStore = require('./extensions/editor-store'); var ErrorHandler = require('./error-handler'); var Editor = function(options) { this.initialize(options); }; Object.assign(Editor.prototype, require('./function-bind'), require('./events'), { bound: ['onFormSubmit', 'hideAllTheThings', 'changeBlockPosition', 'removeBlockDragOver', 'renderBlock', 'resetBlockControls', 'blockLimitReached'], events: { 'block:reorder:dragend': 'removeBlockDragOver', 'block:content:dropped': 'removeBlockDragOver' }, initialize: function(options) { utils.log("Init SirTrevor.Editor"); this.options = Object.assign({}, config.defaults, options || {}); this.ID = _.uniqueId('st-editor-'); if (!this._ensureAndSetElements()) { return false; } if(!_.isUndefined(this.options.onEditorRender) && _.isFunction(this.options.onEditorRender)) { this.onEditorRender = this.options.onEditorRender; } // Mediated events for *this* Editor instance this.mediator = Object.assign({}, Events); this._bindFunctions(); config.instances.push(this); this.build(); FormEvents.bindFormSubmit(this.$form); }, /* * Build the Editor instance. * Check to see if we've been passed JSON already, and if not try and * create a default block. * If we have JSON then we need to build all of our blocks from this. */ build: function() { this.$el.hide(); this.errorHandler = new ErrorHandler(this.$outer, this.mediator, this.options.errorsContainer); this.store = new EditorStore(this.$el.val(), this.mediator); this.block_manager = new BlockManager(this.options, this.ID, this.mediator); this.block_controls = new BlockControls(this.block_manager.blockTypes, this.mediator); this.fl_block_controls = new FloatingBlockControls(this.$wrapper, this.ID, this.mediator); this.formatBar = new FormatBar(this.options.formatBar, this.mediator); this.mediator.on('block:changePosition', this.changeBlockPosition); this.mediator.on('block-controls:reset', this.resetBlockControls); this.mediator.on('block:limitReached', this.blockLimitReached); this.mediator.on('block:render', this.renderBlock); this.dataStore = "Please use store.retrieve();"; this._setEvents(); this.$wrapper.prepend(this.fl_block_controls.render().$el); $(document.body).append(this.formatBar.render().$el); this.$outer.append(this.block_controls.render().$el); $(window).bind('click', this.hideAllTheThings); this.createBlocks(); this.$wrapper.addClass('st-ready'); if(!_.isUndefined(this.onEditorRender)) { this.onEditorRender(); } }, createBlocks: function() { var store = this.store.retrieve(); if (store.data.length > 0) { store.data.forEach(function(block) { this.mediator.trigger('block:create', block.type, block.data); }, this); } else if (this.options.defaultType !== false) { this.mediator.trigger('block:create', this.options.defaultType, {}); } }, destroy: function() { // Destroy the rendered sub views this.formatBar.destroy(); this.fl_block_controls.destroy(); this.block_controls.destroy(); // Destroy all blocks this.blocks.forEach(function(block) { this.mediator.trigger('block:remove', this.block.blockID); }, this); // Stop listening to events this.mediator.stopListening(); this.stopListening(); // Remove instance config.instances = config.instances.filter(function(instance) { return instance.ID !== this.ID; }, this); // Clear the store this.store.reset(); this.$outer.replaceWith(this.$el.detach()); }, reinitialize: function(options) { this.destroy(); this.initialize(options || this.options); }, resetBlockControls: function() { this.block_controls.renderInContainer(this.$wrapper); this.block_controls.hide(); }, blockLimitReached: function(toggle) { this.$wrapper.toggleClass('st--block-limit-reached', toggle); }, _setEvents: function() { Object.keys(this.events).forEach(function(type) { EventBus.on(type, this[this.events[type]], this); }, this); }, hideAllTheThings: function(e) { this.block_controls.hide(); this.formatBar.hide(); }, store: function(method, options){ utils.log("The store method has been removed, please call store[methodName]"); return this.store[method].call(this, options || {}); }, renderBlock: function(block) { this._renderInPosition(block.render().$el); this.hideAllTheThings(); this.scrollTo(block.$el); block.trigger("onRender"); }, scrollTo: function(element) { $('html, body').animate({ scrollTop: element.position().top }, 300, "linear"); }, removeBlockDragOver: function() { this.$outer.find('.st-drag-over').removeClass('st-drag-over'); }, changeBlockPosition: function($block, selectedPosition) { selectedPosition = selectedPosition - 1; var blockPosition = this.getBlockPosition($block), $blockBy = this.$wrapper.find('.st-block').eq(selectedPosition); var where = (blockPosition > selectedPosition) ? "Before" : "After"; if($blockBy && $blockBy.attr('id') !== $block.attr('id')) { this.hideAllTheThings(); $block["insert" + where]($blockBy); this.scrollTo($block); } }, _renderInPosition: function(block) { if (this.block_controls.currentContainer) { this.block_controls.currentContainer.after(block); } else { this.$wrapper.append(block); } }, validateAndSaveBlock: function(block, shouldValidate) { if ((!config.skipValidation || shouldValidate) && !block.valid()) { this.mediator.trigger('errors:add', { text: _.result(block, 'validationFailMsg') }); utils.log("Block " + block.blockID + " failed validation"); return; } var blockData = block.getData(); utils.log("Adding data for block " + block.blockID + " to block store:", blockData); this.store.addData(blockData); }, /* * Handle a form submission of this Editor instance. * Validate all of our blocks, and serialise all data onto the JSON objects */ onFormSubmit: function(shouldValidate) { // if undefined or null or anything other than false - treat as true shouldValidate = (shouldValidate === false) ? false : true; utils.log("Handling form submission for Editor " + this.ID); this.mediator.trigger('errors:reset'); this.store.reset(); this.validateBlocks(shouldValidate); this.block_manager.validateBlockTypesExist(shouldValidate); this.mediator.trigger('errors:render'); this.$el.val(this.store.toString()); return this.errorHandler.errors.length; }, validateBlocks: function(shouldValidate) { var self = this; this.$wrapper.find('.st-block').each(function(idx, block) { var _block = self.block_manager.findBlockById($(block).attr('id')); if (!_.isUndefined(_block)) { self.validateAndSaveBlock(_block, shouldValidate); } }); }, findBlockById: function(block_id) { return this.block_manager.findBlockById(block_id); }, getBlocksByType: function(block_type) { return this.block_manager.getBlocksByType(block_type); }, getBlocksByIDs: function(block_ids) { return this.block_manager.getBlocksByIDs(block_ids); }, getBlockPosition: function($block) { return this.$wrapper.find('.st-block').index($block); }, _ensureAndSetElements: function() { if(_.isUndefined(this.options.el) || _.isEmpty(this.options.el)) { utils.log("You must provide an el"); return false; } this.$el = this.options.el; this.el = this.options.el[0]; this.$form = this.$el.parents('form'); var $outer = $("
").attr({ 'id': this.ID, 'class': 'st-outer', 'dropzone': 'copy link move' }); var $wrapper = $("
").attr({ 'class': 'st-blocks' }); // Wrap our element in lots of containers *eww* this.$el.wrap($outer).wrap($wrapper); this.$outer = this.$form.find('#' + this.ID); this.$wrapper = this.$outer.find('.st-blocks'); return true; } }); module.exports = Editor; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./block-controls":139,"./block-manager":141,"./config":162,"./error-handler":164,"./event-bus":165,"./events":166,"./extensions/editor-store":167,"./floating-block-controls":170,"./form-events":171,"./format-bar":172,"./function-bind":173,"./lodash":178,"./utils":184}],164:[function(require,module,exports){ (function (global){ "use strict"; var _ = require('./lodash'); var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var ErrorHandler = function($wrapper, mediator, container) { this.$wrapper = $wrapper; this.mediator = mediator; this.$el = container; if (_.isUndefined(this.$el)) { this._ensureElement(); this.$wrapper.prepend(this.$el); } this.$el.hide(); this._bindFunctions(); this._bindMediatedEvents(); this.initialize(); }; Object.assign(ErrorHandler.prototype, require('./function-bind'), require('./mediated-events'), require('./renderable'), { errors: [], className: "st-errors", eventNamespace: 'errors', mediatedEvents: { 'reset': 'reset', 'add': 'addMessage', 'render': 'render' }, initialize: function() { var $list = $("
    "); this.$el.append("

    " + i18n.t("errors:title") + "

    ") .append($list); this.$list = $list; }, render: function() { if (this.errors.length === 0) { return false; } this.errors.forEach(this.createErrorItem, this); this.$el.show(); }, createErrorItem: function(error) { var $error = $("
  • ", { class: "st-errors__msg", html: error.text }); this.$list.append($error); }, addMessage: function(error) { this.errors.push(error); }, reset: function() { if (this.errors.length === 0) { return false; } this.errors = []; this.$list.html(''); this.$el.hide(); } }); module.exports = ErrorHandler; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./function-bind":173,"./lodash":178,"./mediated-events":179,"./renderable":180}],165:[function(require,module,exports){ "use strict"; module.exports = Object.assign({}, require('./events')); },{"./events":166}],166:[function(require,module,exports){ "use strict"; module.exports = require('eventablejs'); },{"eventablejs":3}],167:[function(require,module,exports){ "use strict"; /* * Sir Trevor Editor Store * By default we store the complete data on the instances $el * We can easily extend this and store it on some server or something */ var _ = require('../lodash'); var utils = require('../utils'); var EditorStore = function(data, mediator) { this.mediator = mediator; this.initialize(data ? data.trim() : ''); }; Object.assign(EditorStore.prototype, { initialize: function(data) { this.store = this._parseData(data) || { data: [] }; }, retrieve: function() { return this.store; }, toString: function(space) { return JSON.stringify(this.store, undefined, space); }, reset: function() { utils.log("Resetting the EditorStore"); this.store = { data: [] }; }, addData: function(data) { this.store.data.push(data); return this.store; }, _parseData: function(data) { var result; if (data.length === 0) { return result; } try { // Ensure the JSON string has a data element that's an array var jsonStr = JSON.parse(data); if (!_.isUndefined(jsonStr.data)) { result = jsonStr; } } catch(e) { this.mediator.trigger( 'errors:add', { text: i18n.t("errors:load_fail") }); this.mediator.trigger('errors:render'); console.log('Sorry there has been a problem with parsing the JSON'); console.log(e); } return result; } }); module.exports = EditorStore; },{"../lodash":178,"../utils":184}],168:[function(require,module,exports){ (function (global){ "use strict"; /* * Sir Trevor Uploader * Generic Upload implementation that can be extended for blocks */ var _ = require('../lodash'); var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var config = require('../config'); var utils = require('../utils'); var EventBus = require('../event-bus'); module.exports = function(block, file, success, error) { EventBus.trigger('onUploadStart'); var uid = [block.blockID, (new Date()).getTime(), 'raw'].join('-'); var data = new FormData(); data.append('attachment[name]', file.name); data.append('attachment[file]', file); data.append('attachment[uid]', uid); block.resetMessages(); var callbackSuccess = function(data) { utils.log('Upload callback called'); EventBus.trigger('onUploadStop'); if (!_.isUndefined(success) && _.isFunction(success)) { success.apply(block, arguments); } }; var callbackError = function(jqXHR, status, errorThrown) { utils.log('Upload callback error called'); EventBus.trigger('onUploadStop'); if (!_.isUndefined(error) && _.isFunction(error)) { error.call(block, status); } }; var xhr = $.ajax({ url: config.defaults.uploadUrl, data: data, cache: false, contentType: false, processData: false, dataType: 'json', type: 'POST' }); block.addQueuedItem(uid, xhr); xhr.done(callbackSuccess) .fail(callbackError) .always(block.removeQueuedItem.bind(block, uid)); return xhr; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../config":162,"../event-bus":165,"../lodash":178,"../utils":184}],169:[function(require,module,exports){ (function (global){ "use strict"; /* * SirTrevor.Submittable * -- * We need a global way of setting if the editor can and can't be submitted, * and a way to disable the submit button and add messages (when appropriate) * We also need this to be highly extensible so it can be overridden. * This will be triggered *by anything* so it needs to subscribe to events. */ var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var utils = require('../utils'); var EventBus = require('../event-bus'); var Submittable = function($form) { this.$form = $form; this.intialize(); }; Object.assign(Submittable.prototype, { intialize: function(){ this.submitBtn = this.$form.find("input[type='submit']"); var btnTitles = []; this.submitBtn.each(function(i, btn){ btnTitles.push($(btn).attr('value')); }); this.submitBtnTitles = btnTitles; this.canSubmit = true; this.globalUploadCount = 0; this._bindEvents(); }, setSubmitButton: function(e, message) { this.submitBtn.attr('value', message); }, resetSubmitButton: function(){ var titles = this.submitBtnTitles; this.submitBtn.each(function(index, item) { $(item).attr('value', titles[index]); }); }, onUploadStart: function(e){ this.globalUploadCount++; utils.log('onUploadStart called ' + this.globalUploadCount); if(this.globalUploadCount === 1) { this._disableSubmitButton(); } }, onUploadStop: function(e) { this.globalUploadCount = (this.globalUploadCount <= 0) ? 0 : this.globalUploadCount - 1; utils.log('onUploadStop called ' + this.globalUploadCount); if(this.globalUploadCount === 0) { this._enableSubmitButton(); } }, onError: function(e){ utils.log('onError called'); this.canSubmit = false; }, _disableSubmitButton: function(message){ this.setSubmitButton(null, message || i18n.t("general:wait")); this.submitBtn .attr('disabled', 'disabled') .addClass('disabled'); }, _enableSubmitButton: function(){ this.resetSubmitButton(); this.submitBtn .removeAttr('disabled') .removeClass('disabled'); }, _events : { "disableSubmitButton" : "_disableSubmitButton", "enableSubmitButton" : "_enableSubmitButton", "setSubmitButton" : "setSubmitButton", "resetSubmitButton" : "resetSubmitButton", "onError" : "onError", "onUploadStart" : "onUploadStart", "onUploadStop" : "onUploadStop" }, _bindEvents: function(){ Object.keys(this._events).forEach(function(type) { EventBus.on(type, this[this._events[type]], this); }, this); } }); module.exports = Submittable; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../event-bus":165,"../utils":184}],170:[function(require,module,exports){ (function (global){ "use strict"; /* SirTrevor Floating Block Controls -- Draws the 'plus' between blocks */ var _ = require('./lodash'); var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var EventBus = require('./event-bus'); var FloatingBlockControls = function(wrapper, instance_id, mediator) { this.$wrapper = wrapper; this.instance_id = instance_id; this.mediator = mediator; this._ensureElement(); this._bindFunctions(); this.initialize(); }; Object.assign(FloatingBlockControls.prototype, require('./function-bind'), require('./renderable'), require('./events'), { className: "st-block-controls__top", attributes: function() { return { 'data-icon': 'add' }; }, bound: ['handleBlockMouseOut', 'handleBlockMouseOver', 'handleBlockClick', 'onDrop'], initialize: function() { this.$el.on('click', this.handleBlockClick) .dropArea() .bind('drop', this.onDrop); this.$wrapper.on('mouseover', '.st-block', this.handleBlockMouseOver) .on('mouseout', '.st-block', this.handleBlockMouseOut) .on('click', '.st-block--with-plus', this.handleBlockClick); }, onDrop: function(ev) { ev.preventDefault(); var dropped_on = this.$el, item_id = ev.originalEvent.dataTransfer.getData("text/plain"), block = $('#' + item_id); if (!_.isUndefined(item_id) && !_.isEmpty(block) && dropped_on.attr('id') !== item_id && this.instance_id === block.attr('data-instance') ) { dropped_on.after(block); } EventBus.trigger("block:reorder:dropped", item_id); }, handleBlockMouseOver: function(e) { var block = $(e.currentTarget); if (!block.hasClass('st-block--with-plus')) { block.addClass('st-block--with-plus'); } }, handleBlockMouseOut: function(e) { var block = $(e.currentTarget); if (block.hasClass('st-block--with-plus')) { block.removeClass('st-block--with-plus'); } }, handleBlockClick: function(e) { e.stopPropagation(); this.mediator.trigger('block-controls:render', $(e.currentTarget)); } }); module.exports = FloatingBlockControls; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./event-bus":165,"./events":166,"./function-bind":173,"./lodash":178,"./renderable":180}],171:[function(require,module,exports){ "use strict"; var config = require('./config'); var utils = require('./utils'); var EventBus = require('./event-bus'); var Submittable = require('./extensions/submittable'); var formBound = false; // Flag to tell us once we've bound our submit event var FormEvents = { bindFormSubmit: function(form) { if (!formBound) { // XXX: should we have a formBound and submittable per-editor? // telling JSHint to ignore as it'll complain we shouldn't be creating // a new object, but otherwise `this` won't be set in the Submittable // initialiser. Bit weird. new Submittable(form); // jshint ignore:line form.bind('submit', this.onFormSubmit); formBound = true; } }, onBeforeSubmit: function(shouldValidate) { // Loop through all of our instances and do our form submits on them var errors = 0; config.instances.forEach(function(inst, i) { errors += inst.onFormSubmit(shouldValidate); }); utils.log("Total errors: " + errors); return errors; }, onFormSubmit: function(ev) { var errors = FormEvents.onBeforeSubmit(); if(errors > 0) { EventBus.trigger("onError"); ev.preventDefault(); } }, }; module.exports = FormEvents; },{"./config":162,"./event-bus":165,"./extensions/submittable":169,"./utils":184}],172:[function(require,module,exports){ (function (global){ "use strict"; /** * Format Bar * -- * Displayed on focus on a text area. * Renders with all available options for the editor instance */ var _ = require('./lodash'); var $ = (typeof window !== "undefined" ? window.$ : typeof global !== "undefined" ? global.$ : null); var config = require('./config'); var utils = require('./utils'); var FormatBar = function(options, mediator) { this.options = Object.assign({}, config.defaults.formatBar, options || {}); this.commands = this.options.commands; this.mediator = mediator; this._ensureElement(); this._bindFunctions(); this._bindMediatedEvents(); this.initialize.apply(this, arguments); }; Object.assign(FormatBar.prototype, require('./function-bind'), require('./mediated-events'), require('./events'), require('./renderable'), { className: 'st-format-bar', bound: ["onFormatButtonClick", "renderBySelection", "hide"], eventNamespace: 'formatter', mediatedEvents: { 'position': 'renderBySelection', 'show': 'show', 'hide': 'hide' }, initialize: function() { this.$btns = []; this.commands.forEach(function(format) { var btn = $("