@@ -2,86 +2,244 @@ import React, {Component, PropTypes} from 'react';
22import cloudinary , { Util } from 'cloudinary-core' ;
33import CloudinaryComponent from '../CloudinaryComponent' ;
44
5+ function firstDefined ( ...values ) {
6+ for ( let value of values ) {
7+ if ( value !== undefined ) return value ;
8+ }
9+ return undefined ;
10+ }
11+
12+ function defaultBreakpoints ( width , steps = 100 ) {
13+ return steps * Math . ceil ( width / steps ) ;
14+ }
15+
16+ function closestAbove ( list , value ) {
17+ var i ;
18+ i = list . length - 2 ;
19+ while ( i >= 0 && list [ i ] >= value ) {
20+ i -- ;
21+ }
22+ return list [ i + 1 ] ;
23+ }
24+
525export default class Image extends CloudinaryComponent {
626 constructor ( props , context ) {
727 super ( props , context ) ;
8- let url = this . getUrl ( props , context ) ;
28+ console . log ( "Image constructor" ) ;
29+ let options = CloudinaryComponent . normalizeOptions ( context , props ) ;
30+ let url = this . getUrl ( options ) ;
931 this . handleResize = this . handleResize . bind ( this ) ;
10- this . state = { url} ;
32+
33+ let state = { responsive : false , url : "" , breakpoints : defaultBreakpoints } ;
34+ this . state = Object . assign ( state , this . prepareState ( props , context ) ) ;
35+ this . state = state ;
36+ console . log ( this ) ;
37+ }
38+
39+ get window ( ) {
40+ return ( this . element && this . element . ownerDocument ) ? ( this . element . ownerDocument . defaultView || window ) : window ;
1141 }
1242
1343 componentWillReceiveProps ( nextProps , nextContext ) {
14- let url = this . getUrl ( nextProps , nextContext ) ;
15- if ( url !== this . state . url ) {
16- console . log ( "setting url " , url ) ;
17- this . setState ( { url, width : 0 } ) ;
44+ console . log ( "componentWillReceiveProps" , nextProps , nextContext ) ;
45+ let state = this . prepareState ( nextProps , nextContext ) ;
46+ this . setState ( state ) ;
47+ }
48+
49+ prepareState ( props = this . props , context = this . context ) {
50+ let options = CloudinaryComponent . normalizeOptions ( context , props ) ;
51+ let url = this . getUrl ( options ) ;
52+ let state = { } ;
53+ console . log ( "prepareState options " , options ) ;
54+ if ( options . breakpoints !== undefined ) {
55+ state . breakpoints = options . breakpoints ;
56+ }
57+ if ( options . responsive ) {
58+ console . log ( "prepareState - responsive" ) ;
59+ state . responsive = true ;
60+ url = this . cloudinary_update ( url , state ) ;
1861 }
62+
63+ let currentState = this . state || { } ;
64+ if ( /* FIXME probably not needed */ Util . isEmpty ( currentState . url ) || url !== currentState . url ) {
65+ console . log ( "prepareState setting url " , url ) ;
66+ state . url = url ;
67+ }
68+ return state ;
1969 }
2070
2171 componentWillMount ( ) {
22- window . addEventListener ( 'resize' , this . handleResize ) ;
72+ console . log ( "componentWillMount" ) ;
73+ super . componentWillMount ( ) ;
2374 }
2475
2576 componentDidMount ( ) {
77+ console . log ( "componentDidMount" ) ;
78+ super . componentDidMount ( ) ;
79+ // now that we have a this.element, we need to calculate the URL
80+ let state = this . prepareState ( ) ;
81+ if ( state . url !== undefined ) {
82+ console . log ( "componentDidMount setting state" ) ;
83+ this . setState ( state ) ;
84+ }
2685 }
2786
2887 componentWillUnmount ( ) {
29- window . removeEventListener ( 'resize' , this . handleResize ) ;
30-
88+ console . log ( "componentWillUnmount" ) ;
89+ this . window . removeEventListener ( 'resize' , this . handleResize ) ;
3190 }
3291
3392 componentWillUpdate ( nextProps , nextState , nextContext ) {
93+ // TODO check responsive. also check for responsive state change.
94+ console . log ( "componentWillUpdate" , nextState ) ;
95+ if ( nextState . responsive ) {
96+ console . log ( "componentWillUpdate - setting listener" ) ;
97+ this . window . addEventListener ( 'resize' , this . handleResize ) ;
98+ }
3499
35100 }
36101
37102 componentDidUpdate ( prevProps , prevState , prevContext ) {
103+ console . log ( "componentDidUpdate" ) ;
38104 }
39105
40106 shouldComponentUpdate ( nextProps , nextState , nextContext ) {
107+ console . log ( "shouldComponentUpdate" ) ;
41108 return true ;
42109 }
43110
44- getUrl ( props , context , width ) {
45- console . log ( "getUrl" , this ) ;
46- width = width || ( this . state ? this . state . width : undefined ) ;
47- console . log ( "width is " , width ) ;
48- if ( width ) {
49- console . log ( "Width is " , width ) ;
50- props = Object . assign ( { width} , props ) ;
51- }
52- console . log ( props ) ;
53- return super . getUrl ( props , context ) ;
54-
55- }
56111 handleResize ( e ) {
57- const width = this . findContainerWidth ( this . element ) ;
58- if ( ! width ) {
59- return ;
112+ let options = CloudinaryComponent . normalizeOptions ( this . context , this . props ) ;
113+ let url = this . getUrl ( options ) ;
114+ if ( this . state . responsive ) {
115+ url = this . cloudinary_update ( url ) ;
116+ let partialState = { url : url } ;
117+ this . setState ( partialState ) ;
60118 }
61- let partialState = { width, url : this . getUrl ( this . props , this . context , width ) } ;
62- this . setState ( partialState ) ;
63119 }
64120
65- findContainerWidth ( element ) {
66- console . log ( "findContainerWidth" ) ;
121+ render ( ) {
122+ var { public_id, responsive, children, ...options } = CloudinaryComponent . normalizeOptions ( this . props , this . context ) ;
123+ console . log ( "render image" , this . _reactInternalInstance . _debugID , this . state . url , this . state . width ) ;
124+ var attributes = cloudinary . Transformation . new ( options ) . toHtmlAttributes ( ) ;
125+ return (
126+ < img { ...attributes } src = { this . state . url } ref = { ( e ) => { this . element = e ; } } />
127+ ) ;
128+ }
129+
130+ // methods from cloudinary_js
131+
132+ findContainerWidth ( ) {
67133 var containerWidth , style ;
68134 containerWidth = 0 ;
135+ let element = this . element ;
69136 while ( ( ( element = element != null ? element . parentNode : void 0 ) instanceof Element ) && ! containerWidth ) {
70- style = window . getComputedStyle ( element ) ;
137+ style = this . window . getComputedStyle ( element ) ;
71138 if ( ! / ^ i n l i n e / . test ( style . display ) ) {
72139 containerWidth = Util . width ( element ) ;
73140 }
74141 }
142+ console . log ( "findContainerWidth returning " , containerWidth ) ;
75143 return containerWidth ;
76144 } ;
77145
78- render ( ) {
79- var { public_id, children, ...options } = CloudinaryComponent . normalizeOptions ( this . props , this . context ) ;
80- console . log ( "render image" , this . state . url , this . state . width ) ;
81- var attributes = cloudinary . Transformation . new ( options ) . toHtmlAttributes ( ) ;
82- return (
83- < img { ...attributes } src = { this . state . url } ref = { ( e ) => { this . element = e ; } } />
84- ) ;
146+ applyBreakpoints ( tag , width , steps , options ) {
147+ console . log ( "applyBreakpoints" ) ;
148+ var ref , ref1 , ref2 , responsive_use_breakpoints ;
149+ options = CloudinaryComponent . normalizeOptions ( this . context , this . props , options ) ;
150+ responsive_use_breakpoints = options . responsiveUseBreakpoints ;
151+ if ( ( ! responsive_use_breakpoints ) || ( responsive_use_breakpoints === 'resize' && ! options . resizing ) ) {
152+ return width ;
153+ } else {
154+ return this . calc_breakpoint ( tag , width , steps ) ;
155+ }
156+ } ;
157+
158+ calc_breakpoint ( element , width , steps ) {
159+ console . log ( "calc_breakpoint" ) ;
160+ var breakpoints , point ;
161+ breakpoints = this . state . breakpoints || defaultBreakpoints ;
162+ if ( Util . isFunction ( breakpoints ) ) {
163+ return breakpoints ( width , steps ) ;
164+ } else {
165+ if ( Util . isString ( breakpoints ) ) {
166+ breakpoints = ( ( function ( ) {
167+ var j , len , ref , results ;
168+ ref = breakpoints . split ( ',' ) ;
169+ results = [ ] ;
170+ for ( j = 0 , len = ref . length ; j < len ; j ++ ) {
171+ point = ref [ j ] ;
172+ results . push ( parseInt ( point ) ) ;
173+ }
174+ return results ;
175+ } ) ( ) ) . sort ( function ( a , b ) {
176+ return a - b ;
177+ } ) ;
178+ }
179+ return closestAbove ( breakpoints , width ) ;
180+ }
181+ } ;
182+
183+ device_pixel_ratio ( roundDpr = true ) {
184+ var dpr , dprString ;
185+ dpr = ( typeof this . window !== "undefined" && this . window !== null ? this . window . devicePixelRatio : void 0 ) || 1 ;
186+ if ( roundDpr ) {
187+ dpr = Math . ceil ( dpr ) ;
188+ }
189+ if ( dpr <= 0 || isNaN ( dpr ) ) {
190+ dpr = 1 ;
191+ }
192+ dprString = dpr . toString ( ) ;
193+ if ( dprString . match ( / ^ \d + $ / ) ) {
194+ dprString += '.0' ;
195+ }
196+ return dprString ;
197+ } ;
198+ updateDpr ( dataSrc , roundDpr ) {
199+ console . log ( "updateDpr" ) ;
200+ return dataSrc . replace ( / \b d p r _ ( 1 \. 0 | a u t o ) \b / g, 'dpr_' + this . device_pixel_ratio ( roundDpr ) ) ;
201+ } ;
202+
203+ maxWidth ( requiredWidth ) {
204+ var imageWidth ;
205+ imageWidth = this . state . width || 0 ;
206+ if ( requiredWidth > imageWidth ) {
207+ imageWidth = requiredWidth ;
208+ this . setState ( { width : requiredWidth } ) ;
209+ }
210+ return imageWidth ;
211+ } ;
212+
213+ cloudinary_update ( url , options = { } ) {
214+ var requiredWidth ;
215+ var match ;
216+ let resultUrl = this . updateDpr ( url , options . roundDpr ) ;
217+ console . group ( "cloudinary_update" , resultUrl ) ;
218+ console . log ( "state" , this . state ) ;
219+ if ( options . responsive || this . state && this . state . responsive ) {
220+ console . log ( "responsive" ) ;
221+ let containerWidth = this . findContainerWidth ( ) ;
222+ if ( containerWidth !== 0 ) {
223+ if ( / w _ a u t o : b r e a k p o i n t s / . test ( resultUrl ) ) {
224+ requiredWidth = this . maxWidth ( containerWidth , this . element ) ;
225+ resultUrl = resultUrl . replace ( / w _ a u t o : b r e a k p o i n t s ( [ _ 0 - 9 ] * ) ( : [ 0 - 9 ] + ) ? / , "w_auto:breakpoints$1:" + requiredWidth ) ;
226+ } else if ( match = / w _ a u t o ( : ( \d + ) ) ? / . exec ( resultUrl ) ) {
227+ requiredWidth = this . applyBreakpoints ( this . element , containerWidth , match [ 2 ] , options ) ;
228+ requiredWidth = this . maxWidth ( requiredWidth , this . element ) ;
229+ resultUrl = resultUrl . replace ( / w _ a u t o [ ^ , \/ ] * / g, "w_" + requiredWidth ) ;
230+ }
231+ // Util.removeAttribute(this.element, 'width');
232+ // if (!options.responsive_preserve_height) {
233+ // Util.removeAttribute(this.element, 'height');
234+ // }
235+ } else {
236+ resultUrl = "" ;
237+ }
238+
239+ }
240+ console . log ( "cloudinary_update returning" , resultUrl ) ;
241+ console . groupEnd ( ) ;
242+ return resultUrl ;
85243 }
86244}
87245
0 commit comments