PluginProbe
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more / 3.7.2
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more v3.7.2
3.7.2 3.7.1 3.7.0 3.6.0 3.6.1 3.5.2 trunk 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.6.0 2.6.1 All 73 releases
stockpack / assets / js / stockpack-generate.js

stockpack-generate.js in StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more 3.7.2, at assets/js/stockpack-generate.js

297 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { clearGeneratedImages, generatedImages } from './models/stockpack-generated-store';
2
3 const AI_PROVIDER = 'Magnific AI';
4
5 const GENERATED_PROVIDER = 'magnific';
6
7 const StockpackGenerate = wp.media.View.extend( {
8 tagName: 'div',
9 className: 'stockpack-generate',
10 id: 'stockpack-generate',
11
12 events: {
13 'click .stockpack-generate-button': 'generate',
14 'click .stockpack-generate-clear': 'clear',
15 'keydown .stockpack-generate-prompt': 'maybeGenerate',
16 'change .stockpack-generate-model': 'showCost',
17 'change .stockpack-generate-refine': 'showCost',
18 },
19
20 initialize() {
21 this.model.on( 'change:provider', this.toggle, this );
22
23 if ( this.options.selection ) {
24 this.options.selection.on( 'selection:single', this.updateRefine, this );
25 this.options.selection.on( 'selection:unsingle', this.updateRefine, this );
26 }
27
28 if ( this.options.collection ) {
29 this.options.collection.on( 'add reset', this.updateClear, this );
30 this.options.collection.on( 'add', this.imageArrived, this );
31 }
32
33 this.controller.on( 'generation:failed', this.stopWaiting, this );
34
35 window.jQuery( document ).on( 'stockpack:wallet.stockpackGenerate', ( event, wallet ) => this.showBalance( wallet ) );
36 },
37
38 remove() {
39 window.jQuery( document ).off( 'stockpack:wallet.stockpackGenerate' );
40
41 return wp.media.View.prototype.remove.apply( this, arguments );
42 },
43
44 imageArrived() {
45 this.stopWaiting();
46 this.$el.find( '.stockpack-generate-refine' ).prop( 'checked', false );
47
48 if ( this.options.selection ) {
49 this.options.selection.reset();
50 }
51
52 this.updateRefine();
53 },
54
55 l10n() {
56 const strings = wp.media.view.l10n.stockpack.generate || {};
57 return {
58 prompt: strings.prompt || 'Describe the image you want',
59 button: strings.button || 'Generate',
60 working: strings.working || 'Generating…',
61 models: strings.models || { 'mystic-25': 'Mystic 2.5', 'flux-1': 'Flux.1' },
62 credits: strings.credits || {},
63 cost: strings.cost || '%s / image',
64 note: strings.note || '',
65 refine: strings.refine || {},
66 wallet: strings.wallet || {},
67 };
68 },
69
70 isActive() {
71 return AI_PROVIDER === this.model.get( 'provider' );
72 },
73
74 render() {
75 const strings = this.l10n();
76 let options = '';
77
78 _.each( strings.models, function( label, value ) {
79 options += '<option value="' + _.escape( value ) + '">' + _.escape( label ) + '</option>';
80 } );
81
82 this.$el.html(
83 '<input type="text" class="stockpack-generate-prompt" placeholder="' + _.escape( strings.prompt ) + '" />' +
84 '<select class="stockpack-generate-model">' + options + '</select>' +
85 '<label class="stockpack-generate-refine-label" title="' + _.escape( strings.refine.hint || '' ) + '">' +
86 '<input type="checkbox" class="stockpack-generate-refine" disabled />' +
87 _.escape( strings.refine.label || 'Refine the selected image' ) + '</label>' +
88 '<button type="button" class="button button-primary stockpack-generate-button">' +
89 _.escape( strings.button ) + '</button>' +
90 '<button type="button" class="button-link stockpack-generate-clear">' +
91 _.escape( strings.clear || 'Clear' ) + '</button>' +
92 '<span class="stockpack-generate-cost" title="' + _.escape( strings.note ) + '"></span>' +
93 '<span class="stockpack-generate-balance"></span>' +
94 '<span class="stockpack-generate-status" aria-live="polite">' +
95 '<span class="stockpack-generate-pulse" aria-hidden="true"></span>' +
96 '<span class="stockpack-generate-elapsed"></span></span>'
97 );
98
99 this.updateClear();
100 this.updateRefine();
101 this.showCost();
102 this.showBalance();
103 this.toggle();
104
105 _.defer( () => this.toggle() );
106
107 return this;
108 },
109
110 selectedImage() {
111 if ( ! this.options.selection ) {
112 return null;
113 }
114
115 const single = this.options.selection.single();
116
117 if ( ! single || ! single.get( 'url' ) || GENERATED_PROVIDER !== single.get( 'provider' ) ) {
118 return null;
119 }
120
121 return single;
122 },
123
124 updateRefine() {
125 const usable = !! this.selectedImage();
126 const $box = this.$el.find( '.stockpack-generate-refine' );
127
128 if ( ! usable ) {
129 $box.prop( 'checked', false );
130 }
131
132 $box.prop( 'disabled', ! usable );
133
134 this.$el.find( '.stockpack-generate-refine-label' )
135 .css( 'display', usable ? 'inline-flex' : 'none' );
136
137 this.showCost();
138 },
139
140 isRefining() {
141 return this.$el.find( '.stockpack-generate-refine' ).is( ':checked' ) && !! this.selectedImage();
142 },
143
144
145 startWaiting() {
146 const strings = this.l10n();
147
148 this.startedAt = new Date().getTime();
149 this.$el.addClass( 'is-generating' );
150 this.$el.find( '.stockpack-generate-button' ).prop( 'disabled', true );
151
152 this.coreSpinner().css( 'display', 'none' );
153
154 const tick = () => {
155 const seconds = Math.round( ( new Date().getTime() - this.startedAt ) / 1000 );
156
157 this.$el.find( '.stockpack-generate-elapsed' ).text(
158 ( strings.working || 'Generating…' ) + ' ' + seconds + 's'
159 );
160 };
161
162 tick();
163 this.waitTimer = window.setInterval( tick, 1000 );
164
165 this.waitLimit = window.setTimeout( () => this.stopWaiting(), 5 * 60 * 1000 );
166 },
167
168 stopWaiting() {
169 if ( this.waitTimer ) {
170 window.clearInterval( this.waitTimer );
171 this.waitTimer = null;
172 }
173
174 if ( this.waitLimit ) {
175 window.clearTimeout( this.waitLimit );
176 this.waitLimit = null;
177 }
178
179 this.$el.removeClass( 'is-generating' );
180 this.$el.find( '.stockpack-generate-button' ).prop( 'disabled', false );
181 this.$el.find( '.stockpack-generate-elapsed' ).text( '' );
182 this.coreSpinner().css( 'display', '' );
183 },
184
185 coreSpinner() {
186 return this.$el.closest( '.stockpack-browser' ).find( '> .media-toolbar .spinner' );
187 },
188
189 updateClear() {
190 this.$el.find( '.stockpack-generate-clear' )
191 .css( 'display', generatedImages().length ? 'inline-block' : 'none' );
192 },
193
194 clear() {
195 clearGeneratedImages();
196 this.updateClear();
197
198 this.model.set( {
199 search: '',
200 refine_url: '',
201 seed: new Date().getTime(),
202 } );
203 },
204
205 showCost() {
206 const strings = this.l10n();
207 const model = this.$el.find( '.stockpack-generate-model' ).val();
208 const cost = strings.credits[ model ];
209 const refining = this.isRefining();
210 const $cost = this.$el.find( '.stockpack-generate-cost' );
211
212 if ( 'unavailable' === strings.wallet.mode ) {
213 $cost.empty().addClass( 'is-unavailable' ).attr( 'title', '' )
214 .append( document.createTextNode( ( strings.wallet.unavailable || '' ) + ' ' ) )
215 .append( this.link( strings.wallet.connect_url, strings.wallet.connect ) )
216 .append( document.createTextNode( ' · ' ) )
217 .append( this.link( strings.wallet.top_up_url, strings.wallet.top_up ) );
218 return;
219 }
220
221 if ( ! cost ) {
222 $cost.text( '' );
223 return;
224 }
225
226 const multiplier = refining ? ( strings.refine.multiply || 2 ) : 1;
227 const shown = 1 === multiplier ? cost : cost + ' × ' + multiplier;
228
229 $cost.text( strings.cost.replace( '%s', shown ) )
230 .attr( 'title', refining && strings.refine.note ? strings.refine.note : strings.note );
231 },
232
233 link( url, text ) {
234 return window.jQuery( '<a target="_blank" rel="noopener"></a>' )
235 .attr( 'href', url || '#' )
236 .text( text || url || '' );
237 },
238
239 showBalance( wallet ) {
240 const strings = this.l10n();
241 const state = wallet || strings.wallet;
242 const $balance = this.$el.find( '.stockpack-generate-balance' );
243
244 if ( ! state || 'managed' !== state.mode ) {
245 $balance.hide().empty();
246 return;
247 }
248
249 const label = ( strings.wallet.balance_label || 'Balance: %s credits' )
250 .replace( '%s', state.balance_text || String( state.balance || 0 ) );
251
252 $balance.empty()
253 .append( document.createTextNode( label + ' ' ) )
254 .append( this.link( state.top_up_url || strings.wallet.top_up_url, strings.wallet.top_up ) )
255 .css( 'display', 'inline' );
256 },
257
258 toggle() {
259 const active = this.isActive();
260
261 this.$el.css( 'display', active ? 'inline-flex' : 'none' );
262
263 this.$el.closest( '.media-toolbar-primary' )
264 .toggleClass( 'stockpack-generating', active );
265 },
266
267 maybeGenerate( event ) {
268 if ( 13 === event.keyCode ) {
269 event.preventDefault();
270 this.generate();
271 }
272 },
273
274 generate() {
275 const prompt = this.$el.find( '.stockpack-generate-prompt' ).val();
276
277 if ( ! prompt ) {
278 return;
279 }
280
281 const refining = this.isRefining();
282 const source = refining ? this.selectedImage() : null;
283
284 this.startWaiting();
285
286 this.model.set( {
287 search: prompt,
288 ai_model: this.$el.find( '.stockpack-generate-model' ).val(),
289 refine_url: source ? source.get( 'url' ) : '',
290 seed: new Date().getTime(),
291 } );
292 },
293 } );
294
295 export { AI_PROVIDER };
296 export default StockpackGenerate;
297