PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / static / scripts / wp-stateless.js

wp-stateless.js in WP-Stateless – Google Cloud Storage trunk, at static/scripts/wp-stateless.js

834 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var $wildcards_select = jQuery('.select-wildcards').select2({
2 tags: true,
3 tokenSeparators: ['/'],
4 createTag: function (params) {
5 var term = jQuery.trim(params.term)
6
7 if (term === '') {
8 return null
9 }
10
11 let tags = [
12 '%site_id%',
13 '%site_url%',
14 '%site_url_host%',
15 '%site_url_path%',
16 '%date_year/date_month%',
17 ]
18
19 // Remove special chars from tags
20 if (!/^[a-zA-Z0-9_\-.]+$/.test(term) && jQuery.inArray(term, tags) == -1) {
21 term = term.replace(/[^a-zA-Z0-9_\-.]/g, '')
22 }
23
24 return {
25 id: term,
26 text: term,
27 }
28 },
29 templateSelection: function (state) {
30 // Add slash at the en of the tag
31 return state.text
32 },
33 insertTag: function (data, tag) {
34 // Insert the tag at the end of the results
35 data.push(tag)
36 },
37 })
38
39 jQuery('.select-wildcards').on('select2:select', function (evt) {
40 var element = evt.params.data.element
41 var $element = jQuery(element)
42 let $element_value = $element.value
43
44 $element.detach()
45 jQuery(this).append($element)
46
47 /**
48 * add slash after tag
49 */
50 if ($element_value !== '/') {
51 // Create the DOM option that is pre-selected by default
52 var newState = new Option('/', '/', true, true)
53 jQuery(newState).prop('disabled', true)
54 // Append it to the select
55 jQuery(this).append(newState)
56 }
57
58 jQuery(this).trigger('change')
59 prepare_preview_url()
60 })
61
62 jQuery('.select-wildcards').on('select2:unselect', function (evt) {
63 if (evt.params.data.id === '/') {
64 var element = evt.params.data.element
65 var $element = jQuery(element)
66 $element.detach()
67 }
68 prepare_preview_url()
69 })
70
71 function prepare_preview_url() {
72 let root_dir = ''
73 let selected_wildcards = jQuery('.select-wildcards').val()
74
75 if (selected_wildcards !== null) {
76 root_dir = selected_wildcards.join('/')
77 }
78
79 jQuery('#sm_root_dir').val(root_dir)
80 jQuery('#sm_root_dir').trigger('change')
81 }
82
83 function replace_wildcard_to_the_end(wildcards, remove_slashes = false) {
84 if (remove_slashes) {
85 jQuery('.select-wildcards > option').each(function () {
86 if (this.value == '/') {
87 jQuery(this).detach()
88 }
89 })
90 }
91 wildcards.forEach(function (wildcard) {
92 wildcard_exist = false
93 jQuery('.select-wildcards > option').each(function () {
94 if (this.value === wildcard && this.value !== '/') {
95 jQuery(this).detach()
96 jQuery('.select-wildcards').append(jQuery(this))
97 wildcard_exist = true
98 }
99 })
100 if (!wildcard_exist) {
101 var newState = new Option('/', '/', true, true)
102 jQuery(newState).prop('disabled', true)
103 // Append it to the select
104 jQuery('.select-wildcards').append(newState)
105 }
106 })
107 }
108
109 // Application
110 var wpStatelessSettingsApp = {
111 sm: {},
112 backup: {},
113 is_ssl: false,
114
115 // Show notices for readonly fields
116 showNotice: function (field) {
117 if (this.sm.readonly && this.sm.readonly[field]) {
118 var slug = this.sm.readonly[field]
119
120 jQuery(`#notice-${field}`).html(this.sm.strings[slug])
121 jQuery(`[name="sm[${field}]"]`).prop('disabled', true)
122 } else {
123 jQuery(`#notice-${field}`).html('')
124 jQuery(`[name="sm[${field}]"]`).prop('disabled', false)
125 }
126 },
127
128 showSupportedTypes: function () {
129 value = jQuery('#sm_body_rewrite').val()
130
131 if ( ['true', 'enable_editor', 'enable_meta'].indexOf(value) > -1 ) {
132 jQuery('.supported-file-types').show()
133 } else {
134 jQuery('.supported-file-types').hide()
135 }
136 },
137
138 setIsSSL: function () {
139 this.is_ssl = jQuery('#custom_domain').val().indexOf('https://') === 0
140
141 if (this.is_ssl) {
142 jQuery('.notice-is-ssl').show()
143 } else {
144 jQuery('.notice-is-ssl').hide()
145 }
146 },
147
148 getRadioValue: function(name) {
149 return jQuery(`input[name="${name}"]:checked`).val()
150 },
151
152 enableHashifyFileName: function () {
153 var mode = this.getRadioValue('sm[mode]')
154
155 if ( ['stateless', 'ephemeral'].indexOf(mode) > -1
156 && this.sm.readonly['hashify_file_name'] != 'constant' ) {
157 this.backup['hashify_file_name'] = jQuery('#cache_busting').val()
158 jQuery('#cache_busting').val('true')
159 } else if ( this.backup['hashify_file_name'] ) {
160 jQuery('#cache_busting').val( this.backup['hashify_file_name'] )
161 }
162
163 if ( ['stateless', 'ephemeral'].indexOf(mode) > -1 ) {
164 jQuery('#cache_busting').prop('disabled', true)
165 } else {
166 this.showNotice('hashify_file_name')
167 }
168
169 if ( ['stateless', 'ephemeral'].indexOf(mode) > -1 && this.sm.readonly['hashify_file_name'] != 'constant') {
170 jQuery('#notice-hashify_file_name-mode').show()
171 } else {
172 jQuery('#notice-hashify_file_name-mode').hide()
173 }
174 },
175
176 enableDynamicImageSupport: function () {
177 var mode = this.getRadioValue('sm[mode]')
178
179 if ( mode == 'stateless' && this.sm.readonly['dynamic_image_support'] != 'constant' ) {
180 this.backup['dynamic_image_support'] = jQuery('#dynamic_image_support').val()
181 jQuery('#dynamic_image_support').val('false')
182 } else if ( this.backup['dynamic_image_support'] ) {
183 jQuery('#dynamic_image_support').val( this.backup['dynamic_image_support'] )
184 }
185
186 if (mode == 'stateless') {
187 jQuery('#dynamic_image_support').prop('disabled', true)
188 } else {
189 this.showNotice('dynamic_image_support')
190 }
191
192 if (mode == 'stateless' && this.sm.readonly['dynamic_image_support'] != 'constant') {
193 jQuery('#notice-dynamic_image_support-mode').show()
194 } else {
195 jQuery('#notice-dynamic_image_support-mode').hide()
196 }
197 },
198
199 switchBucketFolderType: function() {
200 var value = jQuery('#sm_root_dir').val()
201 var folderType = jQuery('#sm_bucket_folder_type').val()
202
203 switch (value) {
204 case '%date_year/date_month%':
205 folderType = 'single-site'
206 break;
207 case 'sites/%site_id%/%date_year/date_month%':
208 folderType = 'multi-site'
209 break;
210 case '':
211 if ( this.sm.network_admin )
212 folderType = ''
213 break;
214 default:
215 folderType = 'custom'
216 }
217
218 if ( jQuery('#sm_bucket_folder_type').val() != folderType ) {
219 jQuery('#sm_bucket_folder_type').val( folderType)
220 }
221
222 setTimeout(function () {
223 jQuery('#permalink_structure').trigger('change')
224 }, 1)
225 },
226
227 switchRootDir: function() {
228 var value = jQuery('#sm_bucket_folder_type').val()
229
230 switch (value) {
231 case 'single-site':
232 replace_wildcard_to_the_end(['/', '%date_year/date_month%', '/'], true)
233 $wildcards_select
234 .val(['/', '%date_year/date_month%', '/'])
235 .trigger('change')
236 break;
237 case 'multi-site':
238 replace_wildcard_to_the_end(
239 ['/', 'sites', '/', '%site_id%', '/', '%date_year/date_month%', '/'],
240 true
241 )
242 $wildcards_select
243 .val([
244 '/',
245 'sites',
246 '/',
247 '%site_id%',
248 '/',
249 '%date_year/date_month%',
250 '/',
251 ])
252 .trigger('change')
253 break;
254 case '':
255 if ( wp_stateless_settings.network_admin ) {
256 $wildcards_select.val(null).trigger('change')
257 }
258 break;
259 }
260
261 prepare_preview_url()
262 },
263
264 generatePreviewUrl: function() {
265 var host = 'https://storage.googleapis.com/'
266 var hash =
267 jQuery('#cache_busting').val() == 'true'
268 ? Date.now().toString(36) + '-'
269 : ''
270 var custom_domain = jQuery('#custom_domain').val().toString()
271 var root_dir = jQuery('#sm_root_dir').val().toString()
272 var bucket = jQuery('#bucket_name').val().toString()
273
274 jQuery.each(this.sm.wildcards, function (index, item) {
275 var reg = new RegExp(index, 'g')
276 root_dir = root_dir.replace(reg, item[0])
277 })
278
279 var tags = [
280 '%date_year%',
281 '%date_month%',
282 '%site_id%',
283 '%site_url%',
284 '%site_url_host%',
285 '%site_url_path%',
286 ]
287
288 var value_splitted = root_dir.split('/')
289
290 for (var i = 0; i < value_splitted.length; i++) {
291 if (
292 !/^[a-zA-Z0-9_\-.]+$/.test(value_splitted[i]) &&
293 value_splitted[i] != '' &&
294 jQuery.inArray(value_splitted[i], tags) == -1
295 ) {
296 value_splitted[i] = value_splitted[i].replace(/[^a-zA-Z0-9_\-.]/g, '')
297 }
298 }
299
300 root_dir = value_splitted.join('/')
301 root_dir = root_dir.replace(/(\/+)/g, '/')
302 root_dir = root_dir.replace(/^\//, '')
303 root_dir = root_dir.replace(/\/$/, '')
304
305 if (root_dir) {
306 root_dir = root_dir + '/'
307 }
308
309 custom_domain = custom_domain.replace(/\/+$/, '') // removing trailing slashes
310 custom_domain = custom_domain.replace(/https?:\/\//, '') // removing http:// or https:// from the beginning.
311 host += bucket.length > 0 ? bucket : '{bucket-name}'
312
313 if (
314 custom_domain !== 'storage.googleapis.com' &&
315 bucket.length > 0 &&
316 custom_domain.length > 0 &&
317 (this.is_ssl || custom_domain == bucket)
318 ) {
319 host = this.is_ssl ? 'https://' : 'http://' // bucket name will be host
320 host += custom_domain
321 }
322
323 host += '/' + root_dir + hash + 'your-image-name.jpeg'
324
325 jQuery('#file_url_grp_preview').val(host)
326 },
327
328 showCustomEmail: function () {
329 if( jQuery('#sm_status_email_type').val() == 'custom' ) {
330 jQuery('.sm-status-email-address').show()
331 } else {
332 jQuery('.sm-status-email-address').hide()
333 }
334 },
335
336 // Init application
337 init: function () {
338 this.sm = wp_stateless_settings || {}
339 this.sm.readonly = this.sm.readonly || {}
340
341 var readonly = Object.keys(this.sm.readonly);
342
343 for (var key of readonly) {
344 this.showNotice(key)
345 }
346
347 if (this.sm.network_admin) {
348 jQuery('#cache_busting').val('true')
349 this.sm.readonly.hashify_file_name = true
350 }
351
352 // Disable root dir editing if it's readonly
353 if (this.sm.readonly['root_dir']) {
354 $wildcards_select.prop('disabled', true)
355 jQuery('#sm_bucket_folder_type').prop('disabled', true)
356 }
357
358 // Show supported file types
359 jQuery('#sm_body_rewrite').on('change', this.showSupportedTypes)
360 this.showSupportedTypes()
361
362 // Check if custom domain is SSL
363 jQuery('#custom_domain').on('change', this.setIsSSL.bind(this))
364 this.setIsSSL()
365
366 // Check if hashify file name is enabled
367 jQuery('[name="sm[mode]"').on('change', this.enableHashifyFileName.bind(this))
368 this.enableHashifyFileName()
369
370 // Check if dynamic image support is enabled
371 jQuery('[name="sm[mode]"').on('change', this.enableDynamicImageSupport.bind(this))
372 this.enableDynamicImageSupport()
373
374 // Switch folder type depending on root dir
375 jQuery('#sm_root_dir').on('change', this.switchBucketFolderType.bind(this))
376 this.switchBucketFolderType()
377
378 // Update root dir depending on folder type
379 jQuery('#sm_bucket_folder_type').on('change', this.switchRootDir)
380
381 // Generate preview URL
382 jQuery('#bucket_name').on('change', this.generatePreviewUrl.bind(this))
383 jQuery('#sm_root_dir').on('change', this.generatePreviewUrl.bind(this))
384 jQuery('#custom_domain').on('change', this.generatePreviewUrl.bind(this))
385 this.generatePreviewUrl()
386
387 // Update root dir depending on folder type
388 jQuery('#sm_status_email_type').on('change', this.showCustomEmail)
389 this.showCustomEmail()
390 }
391 };
392
393 wpStatelessSettingsApp.init();
394
395 // Processing application
396 wpStatelessProcessingApp = {
397 errors: [],
398 canRun: true,
399 processes: [],
400 token: window.wp_stateless_configs.REST_API_TOKEN,
401 apiRoot: window.wp_stateless_configs.api_root + 'sync/',
402
403 blockUI: function () {
404 this.canRun = false
405
406 this.processes.map( function (process) {
407 process.refreshButtons()
408 })
409 },
410
411 unblockUI: function () {
412 this.canRun = true
413
414 this.processes.map( function (process) {
415 process.refreshButtons()
416 })
417 },
418
419 /**
420 * Prevent global changes
421 */
422 preventChanges: function () {
423 var isRunning = this.processes.find( function (process) {
424 return process.is_running
425 }) ? true : false
426
427 jQuery('#save-settings,#save-compatibility').prop('disabled', isRunning)
428 },
429
430 /**
431 * Handle errors display
432 */
433 addError: function (error) {
434 this.errors.push(error)
435
436 jQuery('#stless_sync_tab #errors').show()
437
438 var html = this.errors.map(function (error) {
439 return '<li>' + error + '</li>'
440 })
441
442 jQuery('#stless_sync_tab #errors ul').html(html)
443 },
444
445 /**
446 * Process response error
447 */
448 processError: function (error) {
449 var message = error && error.responseJSON && error.responseJSON.message
450 ? error.responseJSON.message
451 : window.stateless_l10n.something_went_wrong
452
453 this.addError(message)
454 },
455
456 /**
457 * Load process data
458 */
459 init: function () {
460 var that = this
461 that.blockUI()
462
463 jQuery.ajax({
464 method: 'GET',
465 url: that.apiRoot + 'getProcesses',
466 headers: {
467 'x-wps-auth': that.token,
468 },
469 })
470 .done(function (response) {
471 if (response && response.data) {
472 var processes = response.data || {}
473 for (var i in processes) {
474 var process = new ProcessingClass(processes[i], that)
475 process.refreshBox()
476 that.processes.push(process)
477 }
478 } else {
479 that.addError(window.stateless_l10n.something_went_wrong)
480 }
481 })
482 .fail(function (error) {
483 that.processError(error)
484 })
485 .always(function () {
486 that.unblockUI()
487 })
488 },
489
490 /**
491 * Refresh the process data
492 */
493 refreshProcess: function (process) {
494 var that = this
495
496 jQuery.ajax({
497 method: 'GET',
498 url: that.apiRoot + 'getProcess/' + String(window.btoa(process.id)).replace(/=+/, ''),
499 headers: {
500 'x-wps-auth': that.token,
501 },
502 })
503 .done(function (response) {
504 if ( response && response.data && response.ok ){
505 if (!response.data.is_running) {
506 process.stopPolling()
507 process.queued_items = process.getProgressTotal()
508 process.processed_items = process.getProgressTotal()
509
510 setTimeout(function () {
511 Object.assign(process, response.data)
512 }, 3000)
513
514 } else {
515 Object.assign(process, response.data)
516 }
517
518 process.refreshBox()
519 }
520 })
521 .fail(function (error) {
522 process.stopPolling()
523 that.processError(error)
524 })
525 },
526
527 /**
528 * Run the process
529 */
530 runProcess: function (process) {
531 var that = this
532 that.blockUI()
533
534 var data = {
535 id: process.id,
536 limit: process.limit,
537 order: process.order,
538 }
539
540 jQuery.ajax({
541 method: 'POST',
542 url: that.apiRoot + 'run',
543 headers: {
544 'x-wps-auth': that.token,
545 'Content-Type': 'application/json',
546 },
547 dataType: 'json',
548 data: JSON.stringify(data),
549 })
550 .then(function (response) {
551 if (response && response.ok) {
552 process.is_running = true
553 process.is_stopping = false
554
555 process.refreshBox()
556 process.startPolling()
557 } else {
558 var message = response && response.data && response.data.message
559 ? response.data.message
560 : window.stateless_l10n.something_went_wrong
561
562 that.addError(message)
563 }
564 })
565 .fail(function (error) {
566 process.stopPolling()
567 that.processError(error)
568 })
569 .always(function () {
570 that.unblockUI()
571 })
572 },
573
574 /**
575 * Stop the process
576 */
577 stopProcess: function (process) {
578 var that = this
579 process.is_stopping = true
580 var data = {
581 id: process.id,
582 }
583
584 jQuery.ajax({
585 method: 'POST',
586 url: that.apiRoot + 'stop',
587 headers: {
588 'x-wps-auth': that.token,
589 'Content-Type': 'application/json',
590 },
591 dataType: 'json',
592 data: JSON.stringify(data),
593 })
594 .done(function (response) {
595 if (response && response.ok) {
596 }
597 })
598 .fail(function (error) {
599 that.processError(error)
600 })
601 }
602 }
603
604 wpStatelessProcessingApp.init()
605
606 /**
607 * ProcessingClass
608 *
609 * @param {*} data
610 */
611 function ProcessingClass(data, app) {
612 this.id = ''
613 this.total_items = 0
614 this.queued_items = 0
615 this.processed_items = 0
616 this.is_running = false
617 this.limit = 0
618 this.limitEnabled = false
619 this.order = 'desc'
620
621 // Build an instance
622 Object.assign(this, data)
623
624 this.app = app
625 this.interval = null
626 this.htmlId = this.id.replace(/[^a-zA-Z0-9]/g, '') // remove double backslashes
627 this.htmlBox = jQuery(`[data-id="${this.htmlId}"]`)
628
629 /**
630 * Start polling for changes
631 */
632 this.startPolling = function () {
633 var that = this
634 this.stopPolling()
635 this.interval = setInterval(function () {
636 that.app.refreshProcess(that)
637 }, 5000)
638 }
639
640 /**
641 * Stop polling for changes
642 */
643 this.stopPolling = function () {
644 clearInterval(this.interval)
645 }
646
647 /**
648 * Get Progress bar possible total
649 */
650 this.getProgressTotal = function () {
651 if (this.limit > 0 && this.limit <= this.total_items) {
652 return this.limit
653 }
654 return this.total_items
655 }
656
657 /**
658 * Get Total queued count
659 */
660 this.getQueuedTotal = function () {
661 return this.queued_items > this.total_items
662 ? this.total_items
663 : this.queued_items
664 }
665
666 /**
667 * Get processed total
668 */
669 this.getProcessedTotal = function () {
670 return this.processed_items > this.getQueuedTotal()
671 ? this.getQueuedTotal()
672 : this.processed_items
673 }
674
675 /**
676 * Calculate percentage
677 */
678 this.percentage = function (part, base) {
679 return parseInt((100 / base) * part) + '%'
680 }
681
682 /**
683 * Stop the process
684 */
685 this.refreshProgress = function () {
686 this.htmlBox.find('.legend .total span').html( this.getProgressTotal() )
687 this.htmlBox.find('.legend .queued span').html( this.getQueuedTotal() )
688 this.htmlBox.find('.legend .processed span').html( this.processed_items )
689
690 this.htmlBox.find('.bar.total').css({
691 'background-color': this.getProgressTotal() == this.getProcessedTotal() ? '#02ae7a' : false
692 })
693 this.htmlBox.find('.bar.queued').css({
694 width: this.percentage( this.getQueuedTotal(), this.getProgressTotal() ),
695 'background-color': this.getProgressTotal() == this.getProcessedTotal() ? '#02ae7a' : false
696 })
697 this.htmlBox.find('.bar.processed').css({
698 width: this.percentage( this.getProcessedTotal(), this.getQueuedTotal() ),
699 'background-color': this.getProgressTotal() == this.getProcessedTotal() ? '#02ae7a' : false
700 })
701
702 if (this.notices && this.notices.length) {
703 this.htmlBox.find('.progress-notice').show()
704
705 for (var i in this.notices) {
706 this.htmlBox.find('.progress-notice').append('<p>' + this.notices[i] + '</p>')
707 }
708 }
709 }
710
711 /**
712 * Check if Run button can be pressed
713 */
714 this.canRun = function () {
715 return this.total_items > 0 && !this.is_running && this.app.canRun
716 }
717
718 /**
719 * Check if Stop button can be pressed
720 */
721 this.canStop = function () {
722 return this.is_running && !this.is_stopping
723 }
724
725 /**
726 * Refresh buttons state
727 */
728 this.refreshButtons = function () {
729 if ( this.canStop() ) {
730 this.htmlBox.find('.actions .button-secondary').removeClass('disabled')
731 } else {
732 this.htmlBox.find('.actions .button-secondary').addClass('disabled')
733 }
734
735 if ( this.canRun() ) {
736 this.htmlBox.find('.actions .button-primary').removeClass('disabled')
737 } else {
738 this.htmlBox.find('.actions .button-primary').addClass('disabled')
739 }
740 }
741
742 /**
743 * Refresh the progress data
744 */
745 this.refreshBox = function () {
746 this.htmlBox.find('.inside ul span').html(this.total_items)
747
748 if (this.is_running) {
749 this.startPolling()
750
751 this.htmlBox.find('.dashicons-update').css('display', 'inline-block')
752 this.htmlBox.find('.progress').show()
753
754 this.htmlBox.find('.limit_enabled').prop('disabled', true)
755 this.htmlBox.find('.limit_field input').prop('disabled', true)
756 this.htmlBox.find('.order_value').prop('disabled', true)
757
758 this.refreshProgress()
759 } else {
760 this.stopPolling()
761
762 this.htmlBox.find('.dashicons-update').css('display', 'none')
763 this.htmlBox.find('.progress').hide()
764 this.htmlBox.find('.progress-notice').hide()
765
766 this.htmlBox.find('.limit_enabled').prop('disabled', false)
767 this.htmlBox.find('.limit_field input').prop('disabled', !this.limitEnabled)
768 this.htmlBox.find('.order_value').prop('disabled', false)
769 }
770
771 if (this.limitEnabled || this.limit > 0) {
772 this.htmlBox.find('.limit_field input').css('visibility', 'visible')
773 } else {
774 this.htmlBox.find('.limit_field input').css('visibility', 'hidden')
775 }
776
777 this.refreshButtons()
778 this.app.preventChanges()
779 }
780
781 /**
782 * Enable limit handler
783 */
784 this.enableLimit = function (event) {
785 this.limitEnabled = jQuery(event.target).is(':checked')
786
787 this.limit = 0
788 this.htmlBox.find('.limit_field input').val(0)
789
790 this.refreshBox()
791 }
792
793 /**
794 * Change limit handler
795 */
796 this.changeLimit = function (event) {
797 this.limit = jQuery(event.target).val()
798 }
799
800 /**
801 * Change sorting handler
802 */
803 this.changeOrder = function (event) {
804 this.order = jQuery(event.target).val()
805 }
806
807 /**
808 * Run the process
809 */
810 this.run = function () {
811 if ( this.canRun() ) {
812 this.app.runProcess(this)
813 }
814 }
815
816 /**
817 * Stop the process
818 */
819 this.stop = function () {
820 if ( this.canStop() ) {
821 this.app.stopProcess(this)
822 }
823 }
824
825 /**
826 * Bind event handlers
827 */
828 jQuery(document).on('change', `[data-id="${this.htmlId}"] .limit_enabled`, this.enableLimit.bind(this))
829 this.htmlBox.find('.limit_field input').change( this.changeLimit.bind(this) )
830 this.htmlBox.find('.order_value').change( this.changeOrder.bind(this) )
831 this.htmlBox.find('.actions .button-primary').click( this.run.bind(this) )
832 this.htmlBox.find('.actions .button-secondary').click( this.stop.bind(this) )
833 }
834