From 449b155c243731b6a048e7787bfddecbf3f1f211 Mon Sep 17 00:00:00 2001 From: Koen Bok Date: Sat, 19 Apr 2014 12:46:04 +0200 Subject: [PATCH] view.draggable shortcut --- build/framer.js | 255 ++++++++++++------- extras/CactusFramerTest/static/app-cs.coffee | 7 +- src/ui/draggable.coffee | 7 +- src/views/view.coffee | 7 + todo.txt | 3 +- 5 files changed, 185 insertions(+), 94 deletions(-) diff --git a/build/framer.js b/build/framer.js index fa9948bc0..a79783517 100644 --- a/build/framer.js +++ b/build/framer.js @@ -1,7 +1,7 @@ -// Framer 2.0-60-g2c1fd6d (c) 2013 Koen Bok +// Framer 2.0-61-g958bf94 (c) 2013 Koen Bok // https://github.com/koenbok/Framer -window.FramerVersion = "2.0-60-g2c1fd6d"; +window.FramerVersion = "2.0-61-g958bf94"; (function(){var require = function (file, cwd) { @@ -847,9 +847,9 @@ require.define("/src/utils.coffee",function(require,module,exports,__dirname,__f require.define("/node_modules/underscore/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"underscore.js"} }); -require.define("/node_modules/underscore/underscore.js",function(require,module,exports,__dirname,__filename,process,global){// Underscore.js 1.5.2 +require.define("/node_modules/underscore/underscore.js",function(require,module,exports,__dirname,__filename,process,global){// Underscore.js 1.6.0 // http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function() { @@ -914,7 +914,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, } // Current version. - _.VERSION = '1.5.2'; + _.VERSION = '1.6.0'; // Collection Functions // -------------------- @@ -923,7 +923,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Handles objects with the built-in `forEach`, arrays, and raw objects. // Delegates to **ECMAScript 5**'s native `forEach` if available. var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; + if (obj == null) return obj; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { @@ -936,6 +936,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; } } + return obj; }; // Return the results of applying the iterator to each element. @@ -1001,10 +1002,10 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, }; // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { + _.find = _.detect = function(obj, predicate, context) { var result; any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { + if (predicate.call(context, value, index, list)) { result = value; return true; } @@ -1015,33 +1016,33 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Return all the elements that pass a truth test. // Delegates to **ECMAScript 5**'s native `filter` if available. // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { + _.filter = _.select = function(obj, predicate, context) { var results = []; if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results.push(value); + if (predicate.call(context, value, index, list)) results.push(value); }); return results; }; // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { + _.reject = function(obj, predicate, context) { return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); + return !predicate.call(context, value, index, list); }, context); }; // Determine whether all of the elements match a truth test. // Delegates to **ECMAScript 5**'s native `every` if available. // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - iterator || (iterator = _.identity); + _.every = _.all = function(obj, predicate, context) { + predicate || (predicate = _.identity); var result = true; if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context); each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; + if (!(result = result && predicate.call(context, value, index, list))) return breaker; }); return !!result; }; @@ -1049,13 +1050,13 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Determine if at least one element in the object matches a truth test. // Delegates to **ECMAScript 5**'s native `some` if available. // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); + var any = _.some = _.any = function(obj, predicate, context) { + predicate || (predicate = _.identity); var result = false; if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; + if (result || (result = predicate.call(context, value, index, list))) return breaker; }); return !!result; }; @@ -1081,25 +1082,19 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Convenience version of a common use case of `map`: fetching a property. _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); + return _.map(obj, _.property(key)); }; // Convenience version of a common use case of `filter`: selecting only objects // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? void 0 : []; - return _[first ? 'find' : 'filter'](obj, function(value) { - for (var key in attrs) { - if (attrs[key] !== value[key]) return false; - } - return true; - }); + _.where = function(obj, attrs) { + return _.filter(obj, _.matches(attrs)); }; // Convenience version of a common use case of `find`: getting the first object // containing specific `key:value` pairs. _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); + return _.find(obj, _.matches(attrs)); }; // Return the maximum element or (element-based computation). @@ -1109,13 +1104,15 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.max.apply(Math, obj); } - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; + var result = -Infinity, lastComputed = -Infinity; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; - computed > result.computed && (result = {value : value, computed : computed}); + if (computed > lastComputed) { + result = value; + lastComputed = computed; + } }); - return result.value; + return result; }; // Return the minimum element (or element-based computation). @@ -1123,16 +1120,18 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.min.apply(Math, obj); } - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; + var result = Infinity, lastComputed = Infinity; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); + if (computed < lastComputed) { + result = value; + lastComputed = computed; + } }); - return result.value; + return result; }; - // Shuffle an array, using the modern version of the + // Shuffle an array, using the modern version of the // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). _.shuffle = function(obj) { var rand; @@ -1146,11 +1145,12 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, return shuffled; }; - // Sample **n** random values from an array. - // If **n** is not specified, returns a single random element from the array. + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. // The internal `guard` argument allows it to work with `map`. _.sample = function(obj, n, guard) { - if (arguments.length < 2 || guard) { + if (n == null || guard) { + if (obj.length !== +obj.length) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } return _.shuffle(obj).slice(0, Math.max(0, n)); @@ -1158,12 +1158,14 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // An internal function to generate lookup iterators. var lookupIterator = function(value) { - return _.isFunction(value) ? value : function(obj){ return obj[value]; }; + if (value == null) return _.identity; + if (_.isFunction(value)) return value; + return _.property(value); }; // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, value, context) { - var iterator = lookupIterator(value); + _.sortBy = function(obj, iterator, context) { + iterator = lookupIterator(iterator); return _.pluck(_.map(obj, function(value, index, list) { return { value: value, @@ -1183,9 +1185,9 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // An internal function used for aggregate "group by" operations. var group = function(behavior) { - return function(obj, value, context) { + return function(obj, iterator, context) { var result = {}; - var iterator = value == null ? _.identity : lookupIterator(value); + iterator = lookupIterator(iterator); each(obj, function(value, index) { var key = iterator.call(context, value, index, obj); behavior(result, key, value); @@ -1197,7 +1199,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Groups the object's values by a criterion. Pass either a string attribute // to group by, or a function that returns the criterion. _.groupBy = group(function(result, key, value) { - (_.has(result, key) ? result[key] : (result[key] = [])).push(value); + _.has(result, key) ? result[key].push(value) : result[key] = [value]; }); // Indexes the object's values by a criterion, similar to `groupBy`, but for @@ -1216,7 +1218,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Use a comparator function to figure out the smallest index at which // an object should be inserted so as to maintain order. Uses binary search. _.sortedIndex = function(array, obj, iterator, context) { - iterator = iterator == null ? _.identity : lookupIterator(iterator); + iterator = lookupIterator(iterator); var value = iterator.call(context, obj); var low = 0, high = array.length; while (low < high) { @@ -1248,7 +1250,9 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // allows it to work with `_.map`. _.first = _.head = _.take = function(array, n, guard) { if (array == null) return void 0; - return (n == null) || guard ? array[0] : slice.call(array, 0, n); + if ((n == null) || guard) return array[0]; + if (n < 0) return []; + return slice.call(array, 0, n); }; // Returns everything but the last entry of the array. Especially useful on @@ -1263,11 +1267,8 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // values in the array. The **guard** check allows it to work with `_.map`. _.last = function(array, n, guard) { if (array == null) return void 0; - if ((n == null) || guard) { - return array[array.length - 1]; - } else { - return slice.call(array, Math.max(array.length - n, 0)); - } + if ((n == null) || guard) return array[array.length - 1]; + return slice.call(array, Math.max(array.length - n, 0)); }; // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. @@ -1308,6 +1309,16 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, return _.difference(array, slice.call(arguments, 1)); }; + // Split an array into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(array, predicate) { + var pass = [], fail = []; + each(array, function(elem) { + (predicate(elem) ? pass : fail).push(elem); + }); + return [pass, fail]; + }; + // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. @@ -1341,7 +1352,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, var rest = slice.call(arguments, 1); return _.filter(_.uniq(array), function(item) { return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; + return _.contains(other, item); }); }); }; @@ -1356,7 +1367,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { - var length = _.max(_.pluck(arguments, "length").concat(0)); + var length = _.max(_.pluck(arguments, 'length').concat(0)); var results = new Array(length); for (var i = 0; i < length; i++) { results[i] = _.pluck(arguments, '' + i); @@ -1462,19 +1473,27 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, }; // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. _.partial = function(func) { - var args = slice.call(arguments, 1); + var boundArgs = slice.call(arguments, 1); return function() { - return func.apply(this, args.concat(slice.call(arguments))); + var position = 0; + var args = boundArgs.slice(); + for (var i = 0, length = args.length; i < length; i++) { + if (args[i] === _) args[i] = arguments[position++]; + } + while (position < arguments.length) args.push(arguments[position++]); + return func.apply(this, args); }; }; - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. _.bindAll = function(obj) { var funcs = slice.call(arguments, 1); - if (funcs.length === 0) throw new Error("bindAll must be passed function names"); + if (funcs.length === 0) throw new Error('bindAll must be passed function names'); each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); return obj; }; @@ -1513,12 +1532,13 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, var previous = 0; options || (options = {}); var later = function() { - previous = options.leading === false ? 0 : new Date; + previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); + context = args = null; }; return function() { - var now = new Date; + var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; @@ -1528,6 +1548,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, timeout = null; previous = now; result = func.apply(context, args); + context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } @@ -1541,24 +1562,33 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + context = args = null; + } + } + }; + return function() { context = this; args = arguments; - timestamp = new Date(); - var later = function() { - var last = (new Date()) - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) result = func.apply(context, args); - } - }; + timestamp = _.now(); var callNow = immediate && !timeout; if (!timeout) { timeout = setTimeout(later, wait); } - if (callNow) result = func.apply(context, args); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + return result; }; }; @@ -1580,11 +1610,7 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // allowing you to adjust arguments, run code before and after, and // conditionally execute the original function. _.wrap = function(func, wrapper) { - return function() { - var args = [func]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; + return _.partial(wrapper, func); }; // Returns a function that is the composition of a list of functions, each @@ -1614,8 +1640,9 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // Retrieve the names of an object's properties. // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); var keys = []; for (var key in obj) if (_.has(obj, key)) keys.push(key); return keys; @@ -1770,7 +1797,8 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, // from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor))) { + _.isFunction(bCtor) && (bCtor instanceof bCtor)) + && ('constructor' in a && 'constructor' in b)) { return false; } // Add the first object to the stack of traversed objects. @@ -1910,6 +1938,30 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, return value; }; + _.constant = function(value) { + return function () { + return value; + }; + }; + + _.property = function(key) { + return function(obj) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of `key:value` pairs. + _.matches = function(attrs) { + return function(obj) { + if (obj === attrs) return true; //avoid comparing an object to itself. + for (var key in attrs) { + if (attrs[key] !== obj[key]) + return false; + } + return true; + } + }; + // Run a function **n** times. _.times = function(n, iterator, context) { var accum = Array(Math.max(0, n)); @@ -1926,6 +1978,9 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, return min + Math.floor(Math.random() * (max - min + 1)); }; + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { return new Date().getTime(); }; + // List of HTML entities for escaping. var entityMap = { escape: { @@ -2122,6 +2177,18 @@ require.define("/node_modules/underscore/underscore.js",function(require,module, }); + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } }).call(this); }); @@ -2998,6 +3065,15 @@ require.define("/src/views/view.coffee",function(require,module,exports,__dirnam } }; + View.define("draggable", { + get: function() { + if (this._draggable == null) { + this._draggable = new ui.Draggable(this); + } + return this._draggable; + } + }); + View.prototype.addListener = function(event, listener) { View.__super__.addListener.apply(this, arguments); return this._element.addEventListener(event, listener); @@ -4550,6 +4626,7 @@ require.define("/src/ui/draggable.coffee",function(require,module,exports,__dirn }; this._deltas = []; this._isDragging = false; + this.enabled = true; this.attach(); } @@ -4599,12 +4676,14 @@ require.define("/src/ui/draggable.coffee",function(require,module,exports,__dirn Draggable.prototype._updatePosition = function(event) { var correctedDelta, delta, touchEvent; + if (this.enabled === false) { + return; + } this.emit(Events.DragMove, event); touchEvent = Events.touchEvent(event); delta = { - x: touchEvent.clientX - this._start.x({ - y: touchEvent.clientY - this._start.y - }) + x: touchEvent.clientX - this._start.x, + y: touchEvent.clientY - this._start.y }; correctedDelta = { x: delta.x * this.speed.x, diff --git a/extras/CactusFramerTest/static/app-cs.coffee b/extras/CactusFramerTest/static/app-cs.coffee index 9c3071e45..8283e4c74 100644 --- a/extras/CactusFramerTest/static/app-cs.coffee +++ b/extras/CactusFramerTest/static/app-cs.coffee @@ -1,5 +1,4 @@ -view = new View +window.view = new View + +view.draggable = true -view.animate - properties: {x:100} - curve: "cubic-bezier(.2, .5, .4, .2)" \ No newline at end of file diff --git a/src/ui/draggable.coffee b/src/ui/draggable.coffee index db884016c..3fbf21d91 100644 --- a/src/ui/draggable.coffee +++ b/src/ui/draggable.coffee @@ -21,6 +21,8 @@ class exports.Draggable extends EventEmitter @_deltas = [] @_isDragging = false + @enabled = true + @attach() attach: -> @view.on Events.TouchStart, @_touchStart @@ -60,13 +62,16 @@ class exports.Draggable extends EventEmitter _updatePosition: (event) => + if @enabled is false + return + @emit Events.DragMove, event touchEvent = Events.touchEvent event delta = x: touchEvent.clientX - @_start.x - y: touchEvent.clientY - @_start.y + y: touchEvent.clientY - @_start.y # Correct for current drag speed correctedDelta = diff --git a/src/views/view.coffee b/src/views/view.coffee index b51f85a1a..4fa1109ab 100644 --- a/src/views/view.coffee +++ b/src/views/view.coffee @@ -502,6 +502,13 @@ class View extends Frame if @_element.parentNode @_element.parentNode.removeChild @_element + ############################################################################# + ## Draggable + + @define "draggable", + get: -> + @_draggable ?= new ui.Draggable @ + @_draggable ############################################################################# ## Events diff --git a/todo.txt b/todo.txt index f2876cc3a..f4c9aaf99 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,8 @@ + Add a delay option to animations + Fix the draggable -- Fix the curve typo: https://www.facebook.com/groups/framerjs/permalink/469402916520118/ ++ Fix the curve typo: https://www.facebook.com/groups/framerjs/permalink/469402916520118/ + Add a default width, height and color + Fix frame error ++ Add a view.draggable = true|false shortcut for draggable - Add view copy - Make the invisible psd layers invisible in Framer too