PageSourceSearch

https://www.chemin-neuf.org/wp-content/plugins/wpplugin-ccn-formid…/query//frm-query.js?ver=1790244145

js chemin-neuf.org collected 2026-10-02 11:04:20 UTC 11,752 bytes, 272 lines download raw bytes

1console.log('frm query front')
2
3jQuery(document).ready(function($) {
4    ccfrm_query_fields_init()
5})
6    
7function ccfrm_query_fields_init() {
8    let $ = jQuery
9    let frmQueryFields = {}
10    let cache = {}
11
12    // When a radio field is changed, we need to empty the hidden input[type=text] field for the "other" value
13    $('.frm_radio input[type="radio"]').on('change', function() {
14        let other = $(this).closest('.frm_opt_container').find('input[type="text"].frm_other_input')
15        if (other.length) other.val('')
16    })
17
18    // Retrieve all dynamic fields of query fields
19    $('.frm-field-query').each(function() {
20        if ($(this).hasClass('init-completed')) return
21        let id = $(this).attr('id')
22        // console.log('init frm query', id)
23        let self = $(this)
24        frmQueryFields[id] = {
25            form: $(this).data('form'),
26            field: $(this).data('field'),
27            value_field: $(this).data('value-field'),
28            where: typeof $(this).data('where') == 'string' ? JSON.parse($(this).data('where')) : $(this).data('where'),
29        }
30        // console.log('new frmQueryField '+id, JSON.stringify(frmQueryFields[id]))
31        for (let k in frmQueryFields[id].where) {
32            let v = frmQueryFields[id].where[k]
33            if (/\[.+\]/g.test(v)) {
34                let fieldIdsToWatch = Array.from(v.matchAll(/\[(\d+)\]/g), el => el.length > 1 ? el[1] : null).filter(el => !!el);
35                for (let frmId of fieldIdsToWatch) {
36                    // console.log('try to find watchel', `[name="item_meta[${frmId}]"]`)
37                    let watchEl = $(`[name="item_meta[${frmId}]"]`)
38                    if (!watchEl.length) {
39                        console.log('cannot find watchel', `[name="item_meta[${frmId}]"]`)
40                        continue;
41                    }
42                    watchEl.on('change', function() {computeQuery(id)})
43                }
44            }
45        }
46
47        // listen to hide/show events of the field
48        let style_mem = $(this).parent().attr('style')
49        // console.log('style_mem', style_mem)
50        let observer = new MutationObserver(function(mutations) {
51            mutations.forEach(function(mutation) {
52                // console.log('new parent style?', style_mem, self.parent().attr('style'))
53                if (mutation.type === "attributes" && style_mem != self.parent().attr('style')) {
54                    // console.log('attributes changed, recomputing query field '+id)
55                    style_mem = self.parent().attr('style')
56                    if (self.parent().css('display') == 'none') self.val('')
57                    else computeQuery(id);
58                }
59            });
60        });
61        observer.observe($(this).parent()[0], {attributes: true});
62
63        // console.log('new frmQueryField2 '+id, JSON.stringify(frmQueryFields[id]))
64        computeQuery(id);
65        let viz_mem = $(this).parent().css('display')
66        $(this).parent().on('change', function() {
67            if (viz_mem == $(this).css('display')) return;
68            // console.log('parent changed display=', id, $(this).css('display'))
69            viz_mem = $(this).css('display')
70            computeQuery(id);
71        })
72        setTimeout(_ => computeQuery(id), 2000)
73
74        $(this).addClass('init-completed')
75    })
76
77    async function computeQuery(queryFieldId) {
78        // console.log('computeQuery', queryFieldId)
79        let qEl = $('#'+queryFieldId)
80        if (qEl.parent().css('display') == 'none') return qEl.val('').trigger('change')
81
82        if (!qEl.length || !frmQueryFields[queryFieldId]) return console.warn("Cannot find Query field with id ", queryFieldId, frmQueryFields)
83
84        let data = JSON.parse(JSON.stringify(frmQueryFields[queryFieldId]))
85        // console.log('data', data, JSON.stringify(frmQueryFields[queryFieldId]))
86        for (let k in data.where) {
87            let v = frmQueryFields[queryFieldId].where[k]
88            if (/\[.+\]/g.test(v)) {
89                let fieldIds = Array.from(v.matchAll(/\[(\d+)\]/g), el => el.length > 1 ? el[1] : null).filter(el => !!el);
90                let computedVal = v;
91                for (let frmId of fieldIds) {
92                    let el = $(`[name="item_meta[${frmId}]"]`)
93                    // console.log('el', frmId, el.length, getVal(el))
94                    if (!el.length) {
95                        data.where[k] = ''
96                        continue;
97                    }
98                    let new_val = getVal(frmId);
99                    // if (!/^\d+$/.test(new_val)) new_val = JSON.stringify(new_val)
100                    computedVal = computedVal.replaceAll('['+frmId+']', new_val)
101                }
102                // console.log('final computed val', computedVal)
103                // computedVal = eval('(function() {return ' + computedVal + '})()')
104                data.where[k] = computedVal
105            }
106        }
107        // Add the target user ID if current user has admin rights
108        // if (frmFieldQuery.user_id) data.user_id = frmFieldQuery.user_id
109        data.limit = qEl.data('limit') || -1
110        if (qEl.data('all')) data.field = null
111
112        let hash = await computeHash(data)
113        let qResult = null;
114        if (cache[hash]) {
115            qResult = cache[hash]
116        } else {
117            qResult = await frmfieldquery_request('frm-field-query/v1/form-query', {
118                method: 'POST',
119                data,
120            })
121            cache[hash] = qResult
122        }
123        
124        console.log('computeQuery', qResult, data)
125        // if (typeof qResult == 'object') qResult = JSON.stringify(qResult.map(e => ({id: e.id, ...e.metas, label: e.metas[frmQueryFields[queryFieldId].field] })) )
126        let qResultString = (typeof qResult == 'object') ? JSON.stringify(qResult) : qResult
127        qEl.val(qResultString).trigger('change')
128
129        // To trigger Formidable Forms change detection
130        let triggerChange = (el) => {
131            let evt = new Event("change");
132            Object.defineProperty(evt, 'currentTarget', el[0]);
133            Object.defineProperty(evt, 'originalEvent', {writable: true, value: new Event('change')});
134            // qEl[0].className = "frm_chzn"; // TODO delete, obsolete
135            let qFieldId = el.attr('name').replace(/^item_meta\[(.+)\]$/g, '$1')
136            jQuery( document ).trigger( 'frmFieldChanged', [ el[0], qFieldId, evt ]);
137        }
138
139        // Update the radio options
140        let current_val = qEl.attr('value')
141        console.log('computeQuery current_val', current_val, data.field)
142        if (qEl.find('.frm_radio').length) {
143            qResult.forEach(opt => {
144                let radio = qEl.find(`input[type="radio"][value="${opt.value}"]`)
145                if (radio.length) {
146                    let label = radio.closest('label')
147                    // replace label textnode with new value but do not touch the radio input inside the label el
148                    label.contents().filter(function() {
149                        return this.nodeType === 3
150                    }).replaceWith(opt.label || opt.value)
151                    radio.addClass('dynamic')
152                } else {
153                    let newRadio = jQuery(`<div class="frm_radio dynamic"><label>${opt.label || opt.value}</label></div>`)
154                    let newRadioInput = qEl.find('input[type="radio"]').eq(0).clone()
155                    newRadioInput.val(opt.value).prop('checked', false)
156                    newRadio.find('label').prepend(newRadioInput)
157                    qEl.find('.frm_radio').eq(0).before(newRadio) // TODO choose between append and before
158                    radio = qEl.find(`input[type="radio"][value="${opt.value}"]`)
159                }
160                // Check the radio if it is equal to the current value
161                if (opt.value == current_val && radio.length) {
162                    qEl.find('input[type="text"].frm_other_input').val('')
163                    qEl.find('input[type="radio"]').prop('checked', false)
164                    radio.prop('checked', true)
165                    qEl.val(current_val)
166                    triggerChange(radio)
167                }
168            })
169            // Remove all "dynamic" radios that are not in the result
170            qEl.find('.frm_radio.dynamic').each(function() {
171                let val = $(this).find('input[type="radio"]').val()
172                if (!qResult.find(e => e.value == val)) $(this).remove()
173            })
174        }
175
176        
177    }
178
179    function getVal(frmId) {
180        let el = jQuery(`[name="item_meta[${frmId}]"]`)
181        // console.log('getVal', frmId, el.length, el.val(), el, el.eq(0).attr('type'))
182        if (!el.length) return '';
183        let type = el.eq(0).attr('type')?.toLowerCase() || '';
184        if (el[0].tagName == "SELECT" || ['text', 'hidden', 'email', 'date', 'number'].includes(type)) return el.val();
185        if (type == 'radio') {
186            let result = null;
187            // console.log("EL ATTR", frmId)
188            jQuery(`[name="item_meta[${frmId}]"]`).each(function() {
189                if (jQuery(this).is(':checked')) result = jQuery(this).val()
190            })
191            return result;
192        }
193    }
194
195    async function computeHash(message) {
196        if (typeof message != 'string') message = JSON.stringify(message);
197        const msgUint8 = new TextEncoder().encode(message);                           // encode comme (utf-8) Uint8Array
198        const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);           // fait le condensé
199        const hashArray = Array.from(new Uint8Array(hashBuffer));
199                     // convertit le buffer en tableau d'octet
200        const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convertit le tableau en chaîne hexadélimale
201        return hashHex;
202    }
203
204}
205
206const FRMFIELDQUERY_CACHE = {}
207async function frmfieldquery_options_get(field_id, where) {
208    let field = await ccnfrm_field_get(field_id);
209    if (!field) return [];
210    let options = field.field_options;
211    let data = {
212        form: options.opt_form,
213        field: options.opt_field,
214        value_field: options.opt_value_field,
215        where,
216        limit: options.opt_limit,
217        order_by: options.opt_order_by,
218        order_dir: options.opt_order,
219    }
220    let hash = ccnfrm_hash(data)
221    if (FRMFIELDQUERY_CACHE[hash]) {
222        this.queryValueList = FRMFIELDQUERY_CACHE[hash]
223        return FRMFIELDQUERY_CACHE[hash];
224    }
225    let qResult = await frmfieldquery_request('frm-field-query/v1/form-query', {
226        method: 'POST',
227        data,
228    })
229    console.log('qResult', qResult, data)
230    FRMFIELDQUERY_CACHE[hash] = qResult
231    this.queryValueList = qResult
232    return qResult;
233}
234
235
236
237
238
239/**
240 * Sends a request to the backoffice
241 * 
242 * @param string url 
243 * @param {} config 
244 * @param {} headers 
245 * @returns 
246 */
247 async function frmfieldquery_request(url, config = {}, headers = {}) {
248    config = {
249        method: 'GET',
250        ...config
251    }
252    headers = {
253        'X-WP-Nonce': frmFieldQuery.nonce,
254        ...headers
255    }
256    return new Promise((resolve, reject) => {
257        jQuery.ajax({
258            url: frmFieldQuery.root_ep + url, // frmFieldQuery.root_ep
259            beforeSend: function( xhr ) {
260                for(let k in headers) xhr.setRequestHeader(k, headers[k]);
261            },
262            type: config.method.toUpperCase(),
263            dataType: config.dataType || "json",
264            data: config.data,
265        }).fail(err => reject(err.responseJSON || err))
266        .done(res => {
267            if (res['error']) reject(res);
268            if (config.redirect) document.location = config.redirect;
269            resolve(res)
270        });
271    })
272}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.