From c8ad65efe0bb65c281bccb5cf51632fe56139b3f Mon Sep 17 00:00:00 2001 From: lilia Date: Wed, 29 Oct 2014 16:04:51 -0700 Subject: [PATCH] Switch to bower dependencies Checks in only the files we actually need from bower_components. --- README.md | 6 + background.html | 12 +- bower.json | 14 + .../backbone}/backbone.js | 306 +- .../bootstrap/dist/css}/bootstrap.css | 419 +- .../bytebuffer/dist/ByteBufferAB.js | 3276 ++++++ bower_components/jquery/dist/jquery.js | 9190 +++++++++++++++++ bower_components/long/dist/Long.js | 942 ++ bower_components/protobuf/dist/ProtoBuf.js | 4336 ++++++++ bower_components/underscore/underscore.js | 1415 +++ index.html | 14 +- js-deps/ByteBuffer.min.js | 2320 ----- js-deps/Long.min.js | 26 - js-deps/ProtoBuf.min.js | 3721 ------- js-deps/bootstrap.js | 2114 ---- options.html | 15 +- test/index.html | 12 +- 17 files changed, 19599 insertions(+), 8539 deletions(-) create mode 100644 bower.json rename {js-deps => bower_components/backbone}/backbone.js (86%) rename {stylesheets => bower_components/bootstrap/dist/css}/bootstrap.css (94%) create mode 100644 bower_components/bytebuffer/dist/ByteBufferAB.js create mode 100644 bower_components/jquery/dist/jquery.js create mode 100644 bower_components/long/dist/Long.js create mode 100644 bower_components/protobuf/dist/ProtoBuf.js create mode 100644 bower_components/underscore/underscore.js delete mode 100644 js-deps/ByteBuffer.min.js delete mode 100644 js-deps/Long.min.js delete mode 100644 js-deps/ProtoBuf.min.js delete mode 100644 js-deps/bootstrap.js diff --git a/README.md b/README.md index a31d9786..03410b16 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ Now, in the extension's options, you can register for TextSecure: You should now be able to use the extension. If you need to reset your development environment, open a browser console within the extension options page (or inspect `background.html`) and execute `localStorage.clear()` to clear out the settings. +Dependencies +============ +Dependencies are managed by [bower](bower.io). You'll need to install +node, npm, and bower to change them. If you add a dependency, please +only check in the package files that we actually need. + Tests ===== Please write tests! Our testing framework is mocha and our assertion library is diff --git a/background.html b/background.html index 6d10b280..ce2732d0 100644 --- a/background.html +++ b/background.html @@ -16,14 +16,14 @@ - - - - - - + + + + + + diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..2460e673 --- /dev/null +++ b/bower.json @@ -0,0 +1,14 @@ +{ + "name": "textsecure-chrome", + "version": "0.0.0", + "homepage": "https://github.com/WhisperSystems/TextSecure-Browser", + "license": "GPLV3", + "private": true, + "dependencies": { + "backbone": "~1.1.2", + "underscore": "~1.7.0", + "protobuf": "~3.8.0", + "jquery": "~2.1.1", + "bootstrap": "~3.3.0" + } +} diff --git a/js-deps/backbone.js b/bower_components/backbone/backbone.js similarity index 86% rename from js-deps/backbone.js rename to bower_components/backbone/backbone.js index 28e9e30e..24a550a0 100644 --- a/js-deps/backbone.js +++ b/bower_components/backbone/backbone.js @@ -36,7 +36,9 @@ // Create local references to array methods we'll want to use later. var array = []; + var push = array.push; var slice = array.slice; + var splice = array.splice; // Current version of the library. Keep in sync with `package.json`. Backbone.VERSION = '1.1.2'; @@ -106,46 +108,27 @@ // 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; - - // Remove all callbacks for all events. if (!name && !callback && !context) { this._events = void 0; return this; } - - var names = name ? [name] : _.keys(this._events); - for (var i = 0, length = names.length; i < length; i++) { + names = name ? [name] : _.keys(this._events); + for (i = 0, l = names.length; i < l; i++) { name = names[i]; - - // Bail out if there are no events stored. - var events = this._events[name]; - if (!events) continue; - - // Remove all callbacks for this event. - if (!callback && !context) { - delete this._events[name]; - continue; - } - - // Find any remaining events. - var remaining = []; - for (var j = 0, k = events.length; j < k; j++) { - var event = events[j]; - if ( - callback && callback !== event.callback && - callback !== event.callback._callback || - context && context !== event.context - ) { - remaining.push(event); + 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); + } + } } - } - - // Replace events if there are any remaining. Otherwise, clean up. - if (remaining.length) { - this._events[name] = remaining; - } else { - delete this._events[name]; + if (!retain.length) delete this._events[name]; } } @@ -205,7 +188,7 @@ // Handle space separated event names. if (eventSplitter.test(name)) { var names = name.split(eventSplitter); - for (var i = 0, length = names.length; i < length; i++) { + for (var i = 0, l = names.length; i < l; i++) { obj[action].apply(obj, [names[i]].concat(rest)); } return false; @@ -370,7 +353,7 @@ // Trigger all relevant attribute changes. if (!silent) { if (changes.length) this._pending = options; - for (var i = 0, length = changes.length; i < length; i++) { + for (var i = 0, l = changes.length; i < l; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } } @@ -595,7 +578,6 @@ // Mix in each Underscore method as a proxy to `Model#attributes`. _.each(modelMethods, function(method) { - if (!_[method]) return; Model.prototype[method] = function() { var args = slice.call(arguments); args.unshift(this.attributes); @@ -607,7 +589,7 @@ // ------------------- // If models tend to represent a single row of data, a Backbone Collection is - // more analogous to a table full of data ... or a small slice or page of that + // more analagous to a table full of data ... or a small slice or page of that // table, or a collection of rows that belong together for a particular reason // -- all of the messages in this particular folder, all of the documents // belonging to this particular author, and so on. Collections maintain @@ -661,12 +643,13 @@ var singular = !_.isArray(models); models = singular ? [models] : _.clone(models); options || (options = {}); - for (var i = 0, length = models.length; i < length; i++) { - var model = models[i] = this.get(models[i]); + var i, l, index, model; + for (i = 0, l = models.length; i < l; i++) { + model = models[i] = this.get(models[i]); if (!model) continue; delete this._byId[model.id]; delete this._byId[model.cid]; - var index = this.indexOf(model); + index = this.indexOf(model); this.models.splice(index, 1); this.length--; if (!options.silent) { @@ -686,9 +669,10 @@ options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); var singular = !_.isArray(models); - models = singular ? (models ? [models] : []) : models.slice(); - var id, model, attrs, existing, sort; + models = singular ? (models ? [models] : []) : _.clone(models); + var i, l, id, model, attrs, existing, sort; var at = options.at; + var targetModel = this.model; var sortable = this.comparator && (at == null) && options.sort !== false; var sortAttr = _.isString(this.comparator) ? this.comparator : null; var toAdd = [], toRemove = [], modelMap = {}; @@ -697,12 +681,12 @@ // Turn bare objects into model references, and prevent invalid models // from being added. - for (var i = 0, length = models.length; i < length; i++) { + for (i = 0, l = models.length; i < l; i++) { attrs = models[i] || {}; - if (this._isModel(attrs)) { + if (attrs instanceof Model) { id = model = attrs; } else { - id = attrs[this.model.prototype.idAttribute || 'id']; + id = attrs[targetModel.prototype.idAttribute || 'id']; } // If a duplicate is found, prevent it from being added and @@ -727,14 +711,13 @@ // Do not add multiple models with the same `id`. model = existing || model; - if (!model) continue; if (order && (model.isNew() || !modelMap[model.id])) order.push(model); modelMap[model.id] = true; } // Remove nonexistent models if appropriate. if (remove) { - for (var i = 0, length = this.length; i < length; i++) { + for (i = 0, l = this.length; i < l; ++i) { if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); } if (toRemove.length) this.remove(toRemove, options); @@ -745,13 +728,13 @@ if (sortable) sort = true; this.length += toAdd.length; if (at != null) { - for (var i = 0, length = toAdd.length; i < length; i++) { + for (i = 0, l = toAdd.length; i < l; i++) { this.models.splice(at + i, 0, toAdd[i]); } } else { if (order) this.models.length = 0; var orderedModels = order || toAdd; - for (var i = 0, length = orderedModels.length; i < length; i++) { + for (i = 0, l = orderedModels.length; i < l; i++) { this.models.push(orderedModels[i]); } } @@ -762,7 +745,7 @@ // Unless silenced, it's time to fire all appropriate add/sort events. if (!options.silent) { - for (var i = 0, length = toAdd.length; i < length; i++) { + for (i = 0, l = toAdd.length; i < l; i++) { (model = toAdd[i]).trigger('add', model, this, options); } if (sort || (order && order.length)) this.trigger('sort', this, options); @@ -778,7 +761,7 @@ // Useful for bulk operations and optimizations. reset: function(models, options) { options || (options = {}); - for (var i = 0, length = this.models.length; i < length; i++) { + for (var i = 0, l = this.models.length; i < l; i++) { this._removeReference(this.models[i], options); } options.previousModels = this.models; @@ -912,10 +895,7 @@ // Create a new collection with an identical list of models as this one. clone: function() { - return new this.constructor(this.models, { - model: this.model, - comparator: this.comparator - }); + return new this.constructor(this.models); }, // Private method to reset all internal state. Called when the collection @@ -929,10 +909,7 @@ // Prepare a hash of attributes (or other model) to be added to this // collection. _prepareModel: function(attrs, options) { - if (this._isModel(attrs)) { - if (!attrs.collection) attrs.collection = this; - return attrs; - } + if (attrs instanceof Model) return attrs; options = options ? _.clone(options) : {}; options.collection = this; var model = new this.model(attrs, options); @@ -941,16 +918,11 @@ return false; }, - // Method for checking whether an object should be considered a model for - // the purposes of adding to the collection. - _isModel: function (model) { - return model instanceof Model; - }, - // Internal method to create a model's ties to a collection. _addReference: function(model, options) { this._byId[model.cid] = model; if (model.id != null) this._byId[model.id] = model; + if (!model.collection) model.collection = this; model.on('all', this._onModelEvent, this); }, @@ -984,11 +956,10 @@ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', - 'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; + 'lastIndexOf', 'isEmpty', 'chain', 'sample']; // Mix in each Underscore method as a proxy to `Collection#models`. _.each(methods, function(method) { - if (!_[method]) return; Collection.prototype[method] = function() { var args = slice.call(arguments); args.unshift(this.models); @@ -1001,7 +972,6 @@ // Use attributes instead of properties. _.each(attributeMethods, function(method) { - if (!_[method]) return; Collection.prototype[method] = function(value, context) { var iterator = _.isFunction(value) ? value : function(model) { return model.get(value); @@ -1029,6 +999,7 @@ _.extend(this, _.pick(options, viewOptions)); this._ensureElement(); this.initialize.apply(this, arguments); + this.delegateEvents(); }; // Cached regex to split keys for `delegate`. @@ -1063,35 +1034,19 @@ // Remove this view by taking the element out of the DOM, and removing any // applicable Backbone.Events listeners. remove: function() { - this._removeElement(); + this.$el.remove(); this.stopListening(); return this; }, - // Remove this view's element from the document and all event listeners - // attached to it. Exposed for subclasses using an alternative DOM - // manipulation API. - _removeElement: function() { - this.$el.remove(); - }, - - // Change the view's element (`this.el` property) and re-delegate the - // view's events on the new element. - setElement: function(element) { - this.undelegateEvents(); - this._setElement(element); - this.delegateEvents(); - return this; - }, - - // Creates the `this.el` and `this.$el` references for this view using the - // given `el` and a hash of `attributes`. `el` can be a CSS selector or an - // HTML string, a jQuery context or an element. Subclasses can override - // this to utilize an alternative DOM manipulation API and are only required - // to set the `this.el` property. - _setElement: function(el) { - this.$el = el instanceof Backbone.$ ? el : Backbone.$(el); + // Change the view's element (`this.el` property), including event + // re-delegation. + setElement: function(element, delegate) { + if (this.$el) this.undelegateEvents(); + this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); this.el = this.$el[0]; + if (delegate !== false) this.delegateEvents(); + return this; }, // Set callbacks, where `this.events` is a hash of @@ -1107,6 +1062,8 @@ // pairs. Callbacks will be bound to the view, with `this` set properly. // Uses event delegation for efficiency. // Omitting the selector binds the event to `this.el`. + // This only works for delegate-able events: not `focus`, `blur`, and + // not `change`, `submit`, and `reset` in Internet Explorer. delegateEvents: function(events) { if (!(events || (events = _.result(this, 'events')))) return this; this.undelegateEvents(); @@ -1114,39 +1071,28 @@ var method = events[key]; if (!_.isFunction(method)) method = this[events[key]]; if (!method) continue; + var match = key.match(delegateEventSplitter); - this.delegate(match[1], match[2], _.bind(method, this)); + var eventName = match[1], selector = match[2]; + method = _.bind(method, this); + eventName += '.delegateEvents' + this.cid; + if (selector === '') { + this.$el.on(eventName, method); + } else { + this.$el.on(eventName, selector, method); + } } return this; }, - // Add a single event listener to the view's element (or a child element - // using `selector`). This only works for delegate-able events: not `focus`, - // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer. - delegate: function(eventName, selector, listener) { - this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener); - }, - - // Clears all callbacks previously bound to the view by `delegateEvents`. + // Clears all callbacks previously bound to the view with `delegateEvents`. // You usually don't need to use this, but may wish to if you have multiple // Backbone views attached to the same DOM element. undelegateEvents: function() { - if (this.$el) this.$el.off('.delegateEvents' + this.cid); + this.$el.off('.delegateEvents' + this.cid); return this; }, - // A finer-grained `undelegateEvents` for removing a single delegated event. - // `selector` and `listener` are both optional. - undelegate: function(eventName, selector, listener) { - this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener); - }, - - // Produces a DOM element to be assigned to your view. Exposed for - // subclasses using an alternative DOM manipulation API. - _createElement: function(tagName) { - return document.createElement(tagName); - }, - // Ensure that the View has a DOM element to render into. // If `this.el` is a string, pass it through `$()`, take the first // matching element, and re-assign it to `el`. Otherwise, create @@ -1156,17 +1102,11 @@ var attrs = _.extend({}, _.result(this, 'attributes')); if (this.id) attrs.id = _.result(this, 'id'); if (this.className) attrs['class'] = _.result(this, 'className'); - this.setElement(this._createElement(_.result(this, 'tagName'))); - this._setAttributes(attrs); + var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); + this.setElement($el, false); } else { - this.setElement(_.result(this, 'el')); + this.setElement(_.result(this, 'el'), false); } - }, - - // Set attributes from a hash on this view's element. Exposed for - // subclasses using an alternative DOM manipulation API. - _setAttributes: function(attributes) { - this.$el.attr(attributes); } }); @@ -1244,14 +1184,6 @@ }; } - // Pass along `textStatus` and `errorThrown` from jQuery. - var error = options.error; - options.error = function(xhr, textStatus, errorThrown) { - options.textStatus = textStatus; - options.errorThrown = errorThrown; - if (error) error.apply(this, arguments); - }; - // Make the request, allowing the user to override any Ajax options. var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); model.trigger('request', model, xhr, options); @@ -1319,18 +1251,17 @@ var router = this; Backbone.history.route(route, function(fragment) { var args = router._extractParameters(route, fragment); - if (router.execute(callback, args, name) !== false) { - router.trigger.apply(router, ['route:' + name].concat(args)); - router.trigger('route', name, args); - Backbone.history.trigger('route', router, name, args); - } + router.execute(callback, args); + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); }); return this; }, // Execute a route handler with the provided parameters. This is an // excellent place to do pre-route setup or post-route cleanup. - execute: function(callback, args, name) { + execute: function(callback, args) { if (callback) callback.apply(this, args); }, @@ -1403,6 +1334,12 @@ // Cached regex for stripping leading and trailing slashes. var rootStripper = /^\/+|\/+$/g; + // Cached regex for detecting MSIE. + var isExplorer = /msie [\w.]+/; + + // Cached regex for removing a trailing slash. + var trailingSlash = /\/$/; + // Cached regex for stripping urls of hash. var pathStripper = /#.*$/; @@ -1418,8 +1355,7 @@ // Are we at the app root? atRoot: function() { - var path = this.location.pathname.replace(/[^\/]$/, '$&/'); - return path === this.root && !this.location.search; + return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root; }, // Gets the true hash value. Cannot use location.hash directly due to bug @@ -1429,19 +1365,14 @@ return match ? match[1] : ''; }, - // Get the pathname and search params, without the root. - getPath: function() { - var path = decodeURI(this.location.pathname + this.location.search); - var root = this.root.slice(0, -1); - if (!path.indexOf(root)) path = path.slice(root.length); - return path.slice(1); - }, - - // Get the cross-browser normalized URL fragment from the path or hash. - getFragment: function(fragment) { + // Get the cross-browser normalized URL fragment, either from the URL, + // the hash, or the override. + getFragment: function(fragment, forcePushState) { if (fragment == null) { - if (this._hasPushState || !this._wantsHashChange) { - fragment = this.getPath(); + if (this._hasPushState || !this._wantsHashChange || forcePushState) { + fragment = decodeURI(this.location.pathname + this.location.search); + var root = this.root.replace(trailingSlash, ''); + if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); } else { fragment = this.getHash(); } @@ -1460,43 +1391,36 @@ this.options = _.extend({root: '/'}, this.options, options); this.root = this.options.root; this._wantsHashChange = this.options.hashChange !== false; - this._hasHashChange = 'onhashchange' in window; this._wantsPushState = !!this.options.pushState; this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); - this.fragment = this.getFragment(); - - // Add a cross-platform `addEventListener` shim for older browsers. - var addEventListener = window.addEventListener || function (eventName, listener) { - return attachEvent('on' + eventName, listener); - }; + var fragment = this.getFragment(); + var docMode = document.documentMode; + var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); // Normalize root to always include a leading and trailing slash. this.root = ('/' + this.root + '/').replace(rootStripper, '/'); - // Proxy an iframe to handle location events if the browser doesn't - // support the `hashchange` event, HTML5 history, or the user wants - // `hashChange` but not `pushState`. - if (!this._hasHashChange && this._wantsHashChange && (!this._wantsPushState || !this._hasPushState)) { - var iframe = document.createElement('iframe'); - iframe.src = 'javascript:0'; - iframe.style.display = 'none'; - iframe.tabIndex = -1; - var body = document.body; - // Using `appendChild` will throw on IE < 9 if the document is not ready. - this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow; - this.navigate(this.fragment); + if (oldIE && this._wantsHashChange) { + var frame = Backbone.$('