PageSourceSearch

https://www.iev-group.com/wp-content/plugins/copy-the-code/includes/assets/js/core.js?ver=5.5.3

js iev-group.com collected 2026-10-04 03:13:10 UTC 6,829 bytes, 262 lines download raw bytes

1(function ($) {
2	const CTCCore = {
3
4		/**
5		 * Init
6		 */
7		init: function () {
8			this._bind();
9		},
10
11		/**
12		 * Binds events
13		 */
14		_bind: function () {
15			$( document ).on( 'click', 'body:not(.block-editor-page) .ctc-block-copy', this.doCopy );
16		},
17
18		/**
19		 * Copy text to clipboard using CTC CopyEngine.
20		 *
21		 * @param {string} text Text to copy.
22		 * @return {Promise<boolean>} Success status.
23		 */
24		copyToClipboard: async function ( text ) {
25			// Method 1: Use CTC CopyEngine.
26			if ( window.CTC && window.CTC.CopyEngine ) {
27				try {
28					const copyEngine = new window.CTC.CopyEngine();
29					const result = await copyEngine.execute( { value: text } );
30					if ( result.success ) {
31						return true;
32					}
33				} catch ( err ) {
34					// Fall through to fallbacks.
35				}
36			}
37
38			// Method 2: Clipboard API.
39			if ( navigator.clipboard && navigator.clipboard.writeText ) {
40				try {
41					await navigator.clipboard.writeText( text );
42					return true;
43				} catch ( err ) {
44					// Fall through.
45				}
46			}
47
48			// Method 3: execCommand fallback.
49			try {
50				const textArea = document.createElement( 'textarea' );
51				textArea.value = text;
52				textArea.style.cssText = 'position:fixed;opacity:0;pointer-events:none;';
53				document.body.appendChild( textArea );
54				textArea.select();
55				const success = document.execCommand( 'copy' );
56				document.body.removeChild( textArea );
57				return success;
58			} catch ( err ) {
59				return false;
60			}
61		},
62
63		/**
64		 * Copy selection from element.
65		 *
66		 * @param {jQuery} $source jQuery element to copy selection from.
67		 * @return {Promise<boolean>} Success status.
68		 */
69		copySelection: async function ( $source ) {
70			if ( ! $source || ! $source.length ) {
71				return false;
72			}
73
74			const element = $source.get( 0 );
75
76			// Get text content, preserving line breaks.
77			const clone = element.cloneNode( true );
78			clone.querySelectorAll( 'br' ).forEach( ( br ) => br.replaceWith( '\n' ) );
79			const text = clone.textContent || '';
80
81			return this.copyToClipboard( text.trim() );
82		},
83
84		/**
85		 * Detect coarse device type from user agent (for block analytics).
86		 *
87		 * @return {string} desktop|mobile|tablet
88		 */
89		_detectDevice: function () {
90			const ua = navigator.userAgent;
91			if ( /tablet|ipad|playbook|silk/i.test( ua ) ) {
92				return 'tablet';
93			}
94			if ( /mobile|iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test( ua ) ) {
95				return 'mobile';
96			}
97			return 'desktop';
98		},
99
100		/**
101		 * Detect browser family (for block analytics).
102		 *
103		 * @return {string} Browser slug.
104		 */
105		_detectBrowser: function () {
106			const ua = navigator.userAgent;
107			if ( ua.indexOf( 'Chrome' ) > -1 ) {
108				return 'chrome';
109			}
110			if ( ua.indexOf( 'Firefox' ) > -1 ) {
111				return 'firefox';
112			}
113			if ( ua.indexOf( 'Safari' ) > -1 ) {
114				return 'safari';
115			}
116			if ( ua.indexOf( 'Edge' ) > -1 ) {
117				return 'edge';
118			}
119			return 'unknown';
120		},
121
122		/**
123		 * Send analytics event for Gutenberg block copy (non-blocking).
124		 *
125		 * @param {jQuery} block Block wrapper (.ctc-block).
126		 * @param {boolean} success Whether copy succeeded.
127		 * @param {string|null} errorReason Optional failure reason.
128		 */
129		_sendBlockAnalytics: function ( block, success, errorReason ) {
130			if ( ! block || ! block.length ) {
131				return;
132			}
133			const analytics = block.attr( 'data-ctc-analytics' );
134			const source   = block.attr( 'data-ctc-source' );
135			if ( ! analytics || source !== 'gutenberg-block' ) {
136				return;
137			}
138			if ( typeof window.ctcBlockAnalytics === 'undefined' || ! window.ctcBlockAnalytics.eventsUrl ) {
139				return;
140			}
141			const event = {
142				success: !! success,
143				error_reason: errorReason || null,
144				source: 'gutenberg-block',
145				device: this._detectDevice(),
146				browser: this._detectBrowser(),
147				metadata: {
148					source: 'gutenberg-block',
149					block_type: block.attr( 'data-ctc-block-type' ) || null,
150					post_id: window.ctcBlockAnalytics.postId || null,
151					post_type: window.ctcBlockAnalytics.postType || null,
152					page_url: window.location.href,
153				},
154			};
155			const send = () => {
156				fetch( window.ctcBlockAnalytics.eventsUrl, {
157					method: 'POST',
158					headers: { 'Content-Type': 'application/json' },
159					body: JSON.stringify( event ),
160				} ).catch( function ( err ) {
161					if ( typeof console !== 'undefined' && console.debug ) {
162						console.debug( 'CTC: Block analytics event failed:', err );
163					}
164				} );
165			};
166			if ( window.requestIdleCallback ) {
167				window.requestIdleCallback( send, { timeout: 500 } );
168			} else {
169				setTimeout( send, 0 );
170			}
171		},
172
173		/**
174		 * Do Copy to Clipboard
175		 */
176		doCopy: async function (event) {
177			event.preventDefault();
178
179			let btn             = $( this ),
180				btnText         = btn.find( '.ctc-button-text' ),
181				oldText         = btnText.text(),
182				copiedText      = btn.attr( 'data-copied' ) || 'Copied',
183				copyAsRaw       = btn.attr( 'copy-as-raw' ) || '',
184				block           = btn.parents( '.ctc-block' ),
185				textarea        = block.find( '.ctc-copy-content' ),
186				content         = textarea.val(),
187				selectionTarget = textarea.attr( 'selection-target' ) || '';
188
189			let copySuccess = false;
190
191			// Copy as selection.
192			if ( selectionTarget ) {
193				const source = $( selectionTarget );
194				if ( ! source.length ) {
195					return;
196				}
197				copySuccess = await CTCCore.copySelection( source );
198			} else {
199				if ( ! copyAsRaw ) {
200					// Convert the <br/> tags into new line.
201					content = content.replace( /<br\s*[\/]?>/gi, "\n" );
202
203					// Convert the <div> tags into new line.
204					content = content.replace( /<div\s*[\/]?>/gi, "\n" );
205
206					// Convert the <p> tags into new line.
207					content = content.replace( /<p\s*[\/]?>/gi, "\n\n" );
208
209					// Convert the <li> tags into new line.
210					content = content.replace( /<li\s*[\/]?>/gi, "\n" );
211
212					// Remove all tags.
213					content = content.replace( /(<([^>]+)>)/ig, '' );
214
215					// Remove white spaces.
216					content = content.replace( new RegExp( "/^\s+$/" ), "" );
217				}
218
219				// Remove first and last new line.
220				content = content.trim();
221
222				// Copy using CTC CopyEngine.
223				copySuccess = await CTCCore.copyToClipboard( content );
224			}
225
226			if ( btn.hasClass( 'ctc-block-copy-icon' ) ) {
227				// Copied!
228				btn.addClass( 'copied' );
229				setTimeout(
230					function () {
231						btn.removeClass( 'copied' );
232					},
233					1000
234				);
235			} else {
236				// Copied!
237				btnText.text( copiedText );
238				block.addClass( 'copied' );
239				setTimeout(
240					function () {
241						btnText.text( oldText );
242						block.removeClass( 'copied' );
243					},
244					1000
245				);
246			}
247
248			// Block analytics (non-blocking).
249			CTCCore._sendBlockAnalytics( block, copySuccess, copySuccess ? null : 'copy_failed' );
250		}
251	};
252
253	/**
254	 * Initialization
255	 */
256	$(
257		function () {
258			CTCCore.init();
259		}
260	);
261
262})( jQuery );

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.