From c183ca9fa39c408d2d02cdf90310c6b2860d7172 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 13:33:20 -0400 Subject: [PATCH 1/9] Update code style Normalize usage of spaces and semicolons. --- lib/api/css.js | 10 +++++----- test/api.css.js | 35 +++++++++++++++++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index 307c704574..5266201b3c 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -8,7 +8,7 @@ * @api public */ -exports.css = function(prop, val){ +exports.css = function(prop, val) { if (undefined == prop) return get(this); switch (arguments.length) { @@ -30,7 +30,7 @@ exports.css = function(prop, val){ * @api private */ -function set(self, prop, val){ +function set(self, prop, val) { if ('string' == typeof prop) { var styles = get(self); styles[prop] = val; @@ -52,7 +52,7 @@ function set(self, prop, val){ * @api private */ -function get(self, prop){ +function get(self, prop) { var styles = parse(self.attr('style')); if (undefined == styles) throw new Error('undefined'); return 2 == arguments.length @@ -68,7 +68,7 @@ function get(self, prop){ * @api private */ -function stringify(obj){ +function stringify(obj) { return Object.keys(obj || {}) .reduce(function(str, prop){ return str += '' @@ -88,7 +88,7 @@ function stringify(obj){ * @api private */ -function parse(styles){ +function parse(styles) { styles = (styles || '').trim(); if ('' == styles) return {}; diff --git a/test/api.css.js b/test/api.css.js index a77ca3aa18..9e451afc2c 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -1,43 +1,42 @@ - var expect = require('expect.js'); var $ = require('..'); -describe('$(...)', function(){ +describe('$(...)', function() { - describe('.css', function(){ - it('(): should get all styles as object', function(){ + describe('.css', function() { + it('(): should get all styles as object', function() { var el = $('
  • '); expect(el.css()).to.eql({ hai: 'there', wassup: 0 }); - }) + }); - it('(undefined): should retrun all styles as object', function(){ + it('(undefined): should retrun all styles as object', function() { var el = $('
  • '); expect(el.css()).to.eql({ color: 'white' }); - }) + }); - it('(prop): should return a css property value', function(){ + it('(prop): should return a css property value', function() { var el = $('
  • '); expect(el.css('hai')).to.equal('there'); - }) + }); - it('(prop, val): should set a css property', function(){ + it('(prop, val): should set a css property', function() { var el = $('
  • '); el.css('wassup', 0); expect(el.attr('style')).to.equal('wassup: 0;'); - }) + }); - it('(obj): should set each key and val', function(){ + it('(obj): should set each key and val', function() { var el = $('
  • '); el.css({ foo: 0 }); expect(el.attr('style')).to.equal('foo: 0;'); - }) + }); describe('parser', function(){ - it('should allow any whitespace between declarations', function(){ + it('should allow any whitespace between declarations', function() { var el = $('
  • '); expect(el.css()).to.eql({ one: 0, two: 1 }); - }) - }) - }) + }); + }); + }); -}) +}); From 4ec20812a0dd5bacb56e90111e02ae3ce7e0cac9 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 14:53:46 -0400 Subject: [PATCH 2/9] Manage context explicitly Instead of passing the context as a required first argument, manage it using JavaScript's `Function#call` facilities. This makes private functions easier to read and maintain. --- lib/api/css.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index 5266201b3c..84d92d1ea6 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -9,53 +9,51 @@ */ exports.css = function(prop, val) { - if (undefined == prop) return get(this); + if (undefined == prop) return get.call(this); switch (arguments.length) { - case 2: return set(this, prop, val); - case 0: return get(this); + case 2: return set.call(this, prop, val); + case 0: return get.call(this); case 1: return 'object' == typeof prop - ? set(this, prop) - : get(this, prop); + ? set.call(this, prop) + : get.call(this, prop); } }; /** * Set styles of all elements. * - * @param {Cheerio} self * @param {String|Object} prop * @param {String} val * @return {self} * @api private */ -function set(self, prop, val) { +function set(prop, val) { if ('string' == typeof prop) { - var styles = get(self); + var styles = get.call(this); styles[prop] = val; - return self.attr('style', stringify(styles)); + return this.attr('style', stringify(styles)); } else if ('object' == typeof prop) { Object.keys(prop).forEach(function(k){ - set(self, k, prop[k]); - }); - return self; + set.call(this, k, prop[k]); + }, this); + return this; } } /** * Get parsed styles of the first element. * - * @param {Cheerio} self * @param {String} prop * @return {Object} * @api private */ -function get(self, prop) { - var styles = parse(self.attr('style')); +function get(prop) { + var styles = parse(this.attr('style')); if (undefined == styles) throw new Error('undefined'); - return 2 == arguments.length + return 1 == arguments.length ? styles[prop] : styles; } From b44dcd1f35395e7e84391ff52a927b82e067b655 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 17:04:17 -0400 Subject: [PATCH 3/9] Fix bug in setting styles When setting the style of a multi-element selection, ensure that each style is set independently. --- lib/api/css.js | 12 ++++++------ test/api.css.js | 12 +++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index 84d92d1ea6..f4130a200d 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -11,12 +11,12 @@ exports.css = function(prop, val) { if (undefined == prop) return get.call(this); - switch (arguments.length) { - case 2: return set.call(this, prop, val); - case 0: return get.call(this); - case 1: return 'object' == typeof prop - ? set.call(this, prop) - : get.call(this, prop); + if (arguments.length === 2 || typeof prop === 'object') { + return this.each(function(idx) { + set.call(this, prop, val); + }); + } else { + return get.call(this, prop); } }; diff --git a/test/api.css.js b/test/api.css.js index 9e451afc2c..f786949a50 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -20,15 +20,17 @@ describe('$(...)', function() { }); it('(prop, val): should set a css property', function() { - var el = $('
  • '); - el.css('wassup', 0); - expect(el.attr('style')).to.equal('wassup: 0;'); + var el = $('
  • '); + el.css('color', 'red'); + expect(el.attr('style')).to.equal('margin: 0; color: red;'); + expect(el.eq(1).attr('style')).to.equal('color: red;'); }); it('(obj): should set each key and val', function() { - var el = $('
  • '); + var el = $('
  • '); el.css({ foo: 0 }); - expect(el.attr('style')).to.equal('foo: 0;'); + expect(el.eq(0).attr('style')).to.equal('padding: 0; foo: 0;'); + expect(el.eq(1).attr('style')).to.equal('foo: 0;'); }); describe('parser', function(){ From 7f0b771c6940b457b4072e185dba9001f98e9200 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 14:58:28 -0400 Subject: [PATCH 4/9] Implement API for unsetting styles --- lib/api/css.js | 6 +++++- test/api.css.js | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/api/css.js b/lib/api/css.js index f4130a200d..9644142c32 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -32,7 +32,11 @@ exports.css = function(prop, val) { function set(prop, val) { if ('string' == typeof prop) { var styles = get.call(this); - styles[prop] = val; + if (val === '') { + delete styles[prop]; + } else { + styles[prop] = val; + } return this.attr('style', stringify(styles)); } else if ('object' == typeof prop) { Object.keys(prop).forEach(function(k){ diff --git a/test/api.css.js b/test/api.css.js index f786949a50..9200865a6a 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -26,6 +26,12 @@ describe('$(...)', function() { expect(el.eq(1).attr('style')).to.equal('color: red;'); }); + it('(prop, ""): should unset a css property', function() { + var el = $('
  • '); + el.css('padding', ''); + expect(el.attr('style')).to.equal('margin: 0;'); + }); + it('(obj): should set each key and val', function() { var el = $('
  • '); el.css({ foo: 0 }); From d46a8a9e472950afbfa7b93b684168eb3d13fba5 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 15:32:12 -0400 Subject: [PATCH 5/9] Implement API for getting multiple styles --- lib/api/css.js | 16 ++++++++++++---- test/api.css.js | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index 9644142c32..f574a4371a 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -1,3 +1,5 @@ +var _ = require('underscore'); +var toString = Object.prototype.toString; /** * Set / Get css. @@ -11,7 +13,9 @@ exports.css = function(prop, val) { if (undefined == prop) return get.call(this); - if (arguments.length === 2 || typeof prop === 'object') { + if (arguments.length === 2 || + // When `prop` is a "plain" object + (toString.call(prop) === '[object Object]')) { return this.each(function(idx) { set.call(this, prop, val); }); @@ -57,9 +61,13 @@ function set(prop, val) { function get(prop) { var styles = parse(this.attr('style')); if (undefined == styles) throw new Error('undefined'); - return 1 == arguments.length - ? styles[prop] - : styles; + if (typeof prop === 'string') { + return styles[prop]; + } else if (_.isArray(prop)) { + return _.pick(styles, prop); + } else { + return styles; + } } /** diff --git a/test/api.css.js b/test/api.css.js index 9200865a6a..40f6e2fd11 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -19,6 +19,11 @@ describe('$(...)', function() { expect(el.css('hai')).to.equal('there'); }); + it('([prop1, prop2]): should return the specified property values as an object', function() { + var el = $('
  • '); + expect(el.css(['margin', 'color'])).to.eql({ margin: '1px', color: 'blue' }); + }); + it('(prop, val): should set a css property', function() { var el = $('
  • '); el.css('color', 'red'); From 877dade0109bbc6e462e9c68a745e2294b9bdb5e Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 17:23:50 -0400 Subject: [PATCH 6/9] Implement API for setting styles with a function --- lib/api/css.js | 12 +++++++++--- test/api.css.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index f574a4371a..a9bde99a12 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -17,7 +17,7 @@ exports.css = function(prop, val) { // When `prop` is a "plain" object (toString.call(prop) === '[object Object]')) { return this.each(function(idx) { - set.call(this, prop, val); + set.call(this, prop, val, idx); }); } else { return get.call(this, prop); @@ -29,18 +29,24 @@ exports.css = function(prop, val) { * * @param {String|Object} prop * @param {String} val + * @param {Number} idx - optional index within the selection * @return {self} * @api private */ -function set(prop, val) { +function set(prop, val, idx) { if ('string' == typeof prop) { var styles = get.call(this); + if (_.isFunction(val)) { + val = val.call(this[0], idx, this[0]); + } + if (val === '') { delete styles[prop]; - } else { + } else if (val != null) { styles[prop] = val; } + return this.attr('style', stringify(styles)); } else if ('object' == typeof prop) { Object.keys(prop).forEach(function(k){ diff --git a/test/api.css.js b/test/api.css.js index 40f6e2fd11..1a77245b6e 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -37,6 +37,34 @@ describe('$(...)', function() { expect(el.attr('style')).to.equal('margin: 0;'); }); + describe('(prop, function):', function() { + beforeEach(function() { + this.$el = $('
    '); + }); + + it('should iterate over the selection', function() { + var count = 0; + var $el = this.$el; + this.$el.css('margin', function(idx, elem) { + expect(idx).to.equal(count); + expect(elem).to.equal($el[count]); + expect(this).to.equal($el[count]); + count++; + }); + expect(count).to.equal(3); + }); + + it('should set each attribute independently', function() { + var values = ['4px', '', undefined]; + this.$el.css('margin', function(idx) { + return values[idx]; + }); + expect(this.$el.eq(0).attr('style')).to.equal('margin: 4px;'); + expect(this.$el.eq(1).attr('style')).to.equal(''); + expect(this.$el.eq(2).attr('style')).to.equal('margin: 0;'); + }); + }); + it('(obj): should set each key and val', function() { var el = $('
  • '); el.css({ foo: 0 }); From 579909ce342355609faa0157141f966999ab8c0b Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 17:53:04 -0400 Subject: [PATCH 7/9] Remove undocumented functionality The 0-argument signature is not supported by jQuery's `css` method. --- lib/api/css.js | 2 -- test/api.css.js | 12 +----------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/api/css.js b/lib/api/css.js index a9bde99a12..7b0b1349bd 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -11,8 +11,6 @@ var toString = Object.prototype.toString; */ exports.css = function(prop, val) { - if (undefined == prop) return get.call(this); - if (arguments.length === 2 || // When `prop` is a "plain" object (toString.call(prop) === '[object Object]')) { diff --git a/test/api.css.js b/test/api.css.js index 1a77245b6e..564d95a125 100644 --- a/test/api.css.js +++ b/test/api.css.js @@ -4,16 +4,6 @@ var $ = require('..'); describe('$(...)', function() { describe('.css', function() { - it('(): should get all styles as object', function() { - var el = $('
  • '); - expect(el.css()).to.eql({ hai: 'there', wassup: 0 }); - }); - - it('(undefined): should retrun all styles as object', function() { - var el = $('
  • '); - expect(el.css()).to.eql({ color: 'white' }); - }); - it('(prop): should return a css property value', function() { var el = $('
  • '); expect(el.css('hai')).to.equal('there'); @@ -75,7 +65,7 @@ describe('$(...)', function() { describe('parser', function(){ it('should allow any whitespace between declarations', function() { var el = $('
  • '); - expect(el.css()).to.eql({ one: 0, two: 1 }); + expect(el.css(['one', 'two'])).to.eql({ one: 0, two: 1 }); }); }); }); From 36cc068bc3102e0e5da2bff7d41369fdf460a548 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Tue, 17 Sep 2013 17:58:57 -0400 Subject: [PATCH 8/9] Document 'css' method --- Readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Readme.md b/Readme.md index 15c187437e..44dc7db186 100644 --- a/Readme.md +++ b/Readme.md @@ -544,6 +544,10 @@ $('ul').text() // Pear ``` +#### .css( [propertName] )
    .css( [ propertyNames] )
    .css( [propertyName], [value] )
    .css( [propertName], [function] )
    .css( [properties] ) + +Get the value of a style property for the first element in the set of matched elements or set one or more CSS properties for every matched element. + ### Rendering When you're ready to render the document, you can use the `html` utility function: From 2d73bcbd578165c4140d2d42a2e105233f4db698 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Wed, 18 Sep 2013 10:19:07 -0400 Subject: [PATCH 9/9] Remove dead code path This condition is never satisfied because the private `parse` function never returns `undefined` or `null`. --- lib/api/css.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/api/css.js b/lib/api/css.js index 7b0b1349bd..5346d01b7e 100644 --- a/lib/api/css.js +++ b/lib/api/css.js @@ -64,7 +64,6 @@ function set(prop, val, idx) { function get(prop) { var styles = parse(this.attr('style')); - if (undefined == styles) throw new Error('undefined'); if (typeof prop === 'string') { return styles[prop]; } else if (_.isArray(prop)) {