@cable8mm/jquery-infinite-with-template 1.0.3 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +14 -0
- package/.github/workflows/publish.yml +24 -0
- package/.github/workflows/static.yml +49 -0
- package/.github/workflows/test.yml +33 -0
- package/.vscode/settings.json +4 -0
- package/AGENTS.md +216 -0
- package/README.md +281 -166
- package/examples/data_sources.json +84 -0
- package/examples/generate +55 -11
- package/examples/index.html +3 -3
- package/jest.config.js +8 -0
- package/jquery.infiniteScrollWithTemplate.d.ts +65 -0
- package/jquery.infiniteScrollWithTemplate.js +96 -11
- package/jquery.infiniteScrollWithTemplate.min.js +1 -1
- package/package.json +20 -2
- package/scripts/prepare-dist.js +72 -0
- package/tests/jquery.infiniteScrollWithTemplate.test.js +310 -0
- package/tests/setup.js +16 -0
- package/examples/data_sources.ajax +0 -84
- /package/{LICENSE → LICENSE.md} +0 -0
package/README.md
CHANGED
|
@@ -1,219 +1,334 @@
|
|
|
1
|
-
jQuery Infinite With Template Plugin
|
|
2
|
-
======================
|
|
1
|
+
# ⚡ jQuery Infinite With Template Plugin
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@cable8mm/jquery-infinite-with-template)
|
|
4
|
+
[](https://bundlephobia.com/package/@cable8mm/jquery-infinite-with-template)
|
|
5
|
+
[](https://www.npmjs.com/package/@cable8mm/jquery-infinite-with-template)
|
|
6
|
+
[](https://www.jsdelivr.com/package/npm/@cable8mm/jquery-infinite-with-template)
|
|
7
|
+
[](https://www.npmjs.com/package/@cable8mm/jquery-infinite-with-template)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://github.com/cable8mm/jquery-infinite-with-template)
|
|
10
|
+
[](https://github.com/cable8mm/jquery-infinite-with-template/issues)
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
> 🚀 **AJAX-powered infinite scroll with template rendering for jQuery**
|
|
7
13
|
|
|
8
|
-
|
|
14
|
+
If you like jQuery until now, this little library will help you implement infinite scroll with ease.
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
## ✨ Features
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
- ⚡ **Zero Dependencies** (except jQuery & jsRender)
|
|
19
|
+
- 🎨 **Template Rendering** with jsRender
|
|
20
|
+
- 🔄 **Dual Loading Modes** - Scroll or Click
|
|
21
|
+
- 🎯 **TypeScript Support** out of the box
|
|
22
|
+
- 🛡️ **Error Handling** with callbacks
|
|
23
|
+
- ⚙️ **Highly Configurable** with 12+ options
|
|
24
|
+
- 🚀 **Performance Optimized** with DocumentFragment
|
|
25
|
+
- 📦 **Lightweight** - Only ~3KB minified
|
|
26
|
+
- ✅ **Well Tested** - 16 unit tests included
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
### npm
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npm i @cable8mm/jquery-infinite-with-template
|
|
34
|
+
```
|
|
14
35
|
|
|
15
|
-
|
|
36
|
+
### CDN
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
```html
|
|
39
|
+
<script
|
|
40
|
+
src="https://cdn.jsdelivr.net/npm/@cable8mm/jquery-infinite-with-template@1.0.4/jquery.infiniteScrollWithTemplate.min.js"
|
|
41
|
+
integrity="sha256-bX3iyCp0T50YmDRgpUl1tY/LGlpPGsKR4TqUkpcq6WA="
|
|
42
|
+
crossorigin="anonymous"
|
|
43
|
+
></script>
|
|
18
44
|
```
|
|
19
45
|
|
|
20
|
-
|
|
46
|
+
### ESM
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<script type="module">
|
|
50
|
+
import @cable8mm/jquery-infinite-with-template from https://cdn.jsdelivr.net/npm/@cable8mm/jquery-infinite-with-template@1.0.4/+esm
|
|
51
|
+
</script>
|
|
52
|
+
```
|
|
21
53
|
|
|
22
|
-
|
|
54
|
+
## 🎬 Demo
|
|
23
55
|
|
|
24
|
-
|
|
56
|
+
### Online Demo
|
|
57
|
+
|
|
58
|
+
You can test the plugin directly in your browser:
|
|
59
|
+
|
|
60
|
+
👉 **[https://www.palgle.com/jquery-infinite-with-template/examples/index.html](https://www.palgle.com/jquery-infinite-with-template/examples/index.html)**
|
|
61
|
+
|
|
62
|
+
### Quick Start
|
|
63
|
+
|
|
64
|
+
#### Using npm run dev (Recommended)
|
|
25
65
|
|
|
26
66
|
```bash
|
|
27
|
-
#
|
|
28
|
-
|
|
67
|
+
# Install dependencies (one-time)
|
|
68
|
+
npm install
|
|
69
|
+
|
|
70
|
+
# Run development server with auto-open
|
|
71
|
+
npm run dev
|
|
29
72
|
```
|
|
30
73
|
|
|
31
|
-
|
|
74
|
+
**Note:** This will start the server at `http://127.0.0.1:8080/examples/index.html` and automatically open it in your browser.
|
|
32
75
|
|
|
33
|
-
|
|
76
|
+
Visit [http://127.0.0.1:8080/examples/index.html](http://127.0.0.1:8080/examples/index.html) in your browser.
|
|
34
77
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
alert("zero alert");
|
|
45
|
-
},
|
|
46
|
-
});
|
|
78
|
+
### Regenerate Demo Data
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Using PHP CLI
|
|
82
|
+
php examples/generate > examples/data_sources.json
|
|
83
|
+
|
|
84
|
+
# Or if you have the generate script in examples directory
|
|
85
|
+
cd examples
|
|
86
|
+
php generate > data_sources.json
|
|
47
87
|
```
|
|
48
88
|
|
|
49
|
-
|
|
89
|
+
## 🚀 Usage
|
|
90
|
+
|
|
91
|
+
### Basic Example
|
|
92
|
+
|
|
93
|
+
**HTML:**
|
|
50
94
|
|
|
51
95
|
```html
|
|
52
96
|
<div id="result"></div>
|
|
53
97
|
|
|
54
98
|
<script id="test-tmpl" type="text/x-jsrender">
|
|
55
|
-
|
|
99
|
+
<div class="item">
|
|
100
|
+
<h3>{{:title}}</h3>
|
|
101
|
+
<p>ID: {{:id}}</p>
|
|
102
|
+
</div>
|
|
56
103
|
</script>
|
|
57
104
|
```
|
|
58
105
|
|
|
59
|
-
|
|
106
|
+
**JavaScript:**
|
|
60
107
|
|
|
61
108
|
```javascript
|
|
109
|
+
$("#result").infiniteTemplate({
|
|
110
|
+
templateSelector: "#test-tmpl",
|
|
111
|
+
dataPath: "/api/posts",
|
|
112
|
+
query: "category=tech",
|
|
113
|
+
templateHelpers: {
|
|
114
|
+
userId: 123,
|
|
115
|
+
},
|
|
116
|
+
zeroCallback: function () {
|
|
117
|
+
console.log("No more posts!");
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Server Response (JSON):**
|
|
123
|
+
|
|
124
|
+
```json
|
|
62
125
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
},
|
|
76
|
-
...even more rows
|
|
126
|
+
"data": [
|
|
127
|
+
{
|
|
128
|
+
"id": 1,
|
|
129
|
+
"title": "Getting Started with jQuery",
|
|
130
|
+
"content": "..."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"id": 2,
|
|
134
|
+
"title": "Advanced JavaScript Patterns",
|
|
135
|
+
"content": "..."
|
|
136
|
+
}
|
|
137
|
+
]
|
|
77
138
|
}
|
|
78
139
|
```
|
|
79
140
|
|
|
80
|
-
|
|
141
|
+
### Click-to-Load Button
|
|
81
142
|
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<p>329. 865t05x9DMngrETccBuqrY7ts9Xt3R(word=ajax) [user:354]</p>
|
|
90
|
-
<p>84. D6mhKuRA06ONCE5HbswSwPjZvp0bUh(word=ajax) [user:354]</p>
|
|
91
|
-
<p>528. saWL46OBtTDGIBuZL9TkmfBvPXiRqM(word=ajax) [user:354]</p>
|
|
92
|
-
<p>522. PBe0jjP1Egy6NWpHzuA86JHupxNGvc(word=ajax) [user:354]</p>
|
|
93
|
-
<p>115. vBmfL7osq2VAKIktVznrC6QZzYpc1H(word=ajax) [user:354]</p>
|
|
94
|
-
<p>722. mti7aMut4TxAygKAdfGylml9QgJoDN(word=ajax) [user:354]</p>
|
|
95
|
-
<p>401. 06kgapSQylxWJOvFmDNLIcvpSPMB7V(word=ajax) [user:354]</p>
|
|
96
|
-
<p>245. UD0TP3bMU7J4mAlGqwo52F1I0rJIyR(word=ajax) [user:354]</p>
|
|
97
|
-
<p>985. 3xSyr0m68K3Ec6y8vJgIhYgSfgcGnG(word=ajax) [user:354]</p>
|
|
98
|
-
<p>78. DWpWRzx1x4Ibfh1Gn0Lk0F3aufu34d(word=ajax) [user:354]</p>
|
|
99
|
-
<p>573. iINBTozeMIeZguTU6lLB9j76zNZ4AK(word=ajax) [user:354]</p>
|
|
100
|
-
<p>946. OEuUblddtI9vqlyL89nDXizhvryn4e(word=ajax) [user:354]</p>
|
|
101
|
-
<p>756. wsBL8dxDf6UjTiNWNnnX4XAlAonHBM(word=ajax) [user:354]</p>
|
|
102
|
-
<p>66. q3irGi5lNUXccTDTDfl2jRlzVp04uk(word=ajax) [user:354]</p>
|
|
103
|
-
<p>20. vcq8sKN4RhCEoFLVW2vbX2eR14EKp8(word=ajax) [user:354]</p>
|
|
104
|
-
</div>
|
|
143
|
+
```javascript
|
|
144
|
+
$("#result").infiniteTemplate({
|
|
145
|
+
templateSelector: "#item-template",
|
|
146
|
+
dataPath: "/api/items",
|
|
147
|
+
loadSelector: "#load-more-btn", // Click this button to load more
|
|
148
|
+
loadAtStart: false, // Don't load automatically
|
|
149
|
+
});
|
|
105
150
|
```
|
|
106
151
|
|
|
107
|
-
|
|
152
|
+
### With Error Handling
|
|
108
153
|
|
|
109
|
-
|
|
154
|
+
```javascript
|
|
155
|
+
$("#result").infiniteTemplate({
|
|
156
|
+
templateSelector: "#item-template",
|
|
157
|
+
dataPath: "/api/items",
|
|
158
|
+
errorCallback: function (error) {
|
|
159
|
+
console.error("Failed to load:", error);
|
|
160
|
+
alert("Something went wrong. Please try again.");
|
|
161
|
+
},
|
|
162
|
+
loadingCallback: function () {
|
|
163
|
+
$("#loading").show();
|
|
164
|
+
},
|
|
165
|
+
loadedCallback: function () {
|
|
166
|
+
$("#loading").hide();
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
110
170
|
|
|
111
|
-
|
|
171
|
+
## 📋 Options
|
|
172
|
+
|
|
173
|
+
| Option | Type | Default | Description |
|
|
174
|
+
| -------------------- | ---------- | ------------ | ------------------------------------------------------------ |
|
|
175
|
+
| **templateSelector** | `string` | **required** | jsRender template selector (e.g., `"#my-template"`) |
|
|
176
|
+
| **dataPath** | `string` | **required** | URL to load data via AJAX |
|
|
177
|
+
| **key** | `string` | `"data"` | Key for data array in JSON response |
|
|
178
|
+
| **query** | `string` | `null` | Additional query parameters (e.g., `"category=1&sort=date"`) |
|
|
179
|
+
| **method** | `string` | `"GET"` | HTTP method (GET, POST, PUT, DELETE) |
|
|
180
|
+
| **templateHelpers** | `object` | `null` | Helper data merged with each item |
|
|
181
|
+
| **loadAtStart** | `boolean` | `true` | Load data on initialization |
|
|
182
|
+
| **loadSelector** | `string` | `null` | CSS selector for click-to-load button |
|
|
183
|
+
| **initialPage** | `number` | `1` | Initial page number |
|
|
184
|
+
| **preventCache** | `boolean` | `false` | Add timestamp to prevent caching |
|
|
185
|
+
| **scrollThreshold** | `number` | `2` | Multiplier for viewport height (lower = more sensitive) |
|
|
186
|
+
| **zeroCallback** | `function` | `null` | Called when no data returned on first page |
|
|
187
|
+
| **errorCallback** | `function` | `null` | Called on AJAX or JSON parse error |
|
|
188
|
+
| **loadingCallback** | `function` | `null` | Called when loading starts |
|
|
189
|
+
| **loadedCallback** | `function` | `null` | Called when loading completes (success or error) |
|
|
190
|
+
|
|
191
|
+
## 🎯 Real-World Examples
|
|
192
|
+
|
|
193
|
+
### Example 1: Blog Posts with Pagination
|
|
112
194
|
|
|
113
|
-
|
|
195
|
+
```javascript
|
|
196
|
+
$("#post-list").infiniteTemplate({
|
|
197
|
+
templateSelector: "#post-template",
|
|
198
|
+
dataPath: "/api/posts",
|
|
199
|
+
query: "status=published",
|
|
200
|
+
initialPage: 1,
|
|
201
|
+
scrollThreshold: 1.5,
|
|
202
|
+
templateHelpers: {
|
|
203
|
+
currentUser: window.currentUser,
|
|
204
|
+
},
|
|
205
|
+
loadingCallback: () => $("#spinner").show(),
|
|
206
|
+
loadedCallback: () => $("#spinner").hide(),
|
|
207
|
+
zeroCallback: () => $("#end-message").show(),
|
|
208
|
+
});
|
|
209
|
+
```
|
|
114
210
|
|
|
115
|
-
|
|
211
|
+
### Example 2: E-commerce Product Grid
|
|
116
212
|
|
|
117
|
-
|
|
213
|
+
```javascript
|
|
214
|
+
$("#product-grid").infiniteTemplate({
|
|
215
|
+
templateSelector: "#product-card",
|
|
216
|
+
dataPath: "/api/products",
|
|
217
|
+
query: "category=electronics&sort=price",
|
|
218
|
+
loadSelector: "#load-more-products",
|
|
219
|
+
loadAtStart: true,
|
|
220
|
+
templateHelpers: {
|
|
221
|
+
currency: "$",
|
|
222
|
+
discountRate: 0.1,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
```
|
|
118
226
|
|
|
119
|
-
|
|
227
|
+
### Example 3: Social Media Feed
|
|
120
228
|
|
|
121
|
-
|
|
229
|
+
```javascript
|
|
230
|
+
$("#feed").infiniteTemplate({
|
|
231
|
+
templateSelector: "#feed-item",
|
|
232
|
+
dataPath: "/api/feed",
|
|
233
|
+
method: "POST",
|
|
234
|
+
query: "filter=following",
|
|
235
|
+
initialPage: 3,
|
|
236
|
+
preventCache: true,
|
|
237
|
+
templateHelpers: {
|
|
238
|
+
currentUserId: Auth.id(),
|
|
239
|
+
likedPosts: Auth.likedPosts(),
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
```
|
|
122
243
|
|
|
123
|
-
|
|
244
|
+
### Example 4: Search Results
|
|
124
245
|
|
|
125
|
-
|
|
246
|
+
```javascript
|
|
247
|
+
$("#search-results").infiniteTemplate({
|
|
248
|
+
templateSelector: "#result-item",
|
|
249
|
+
dataPath: "/api/search",
|
|
250
|
+
query: `q=${encodeURIComponent(searchQuery)}`,
|
|
251
|
+
zeroCallback: () => {
|
|
252
|
+
$("#no-results").show();
|
|
253
|
+
},
|
|
254
|
+
errorCallback: (error) => {
|
|
255
|
+
console.error("Search failed:", error);
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
```
|
|
126
259
|
|
|
127
|
-
|
|
260
|
+
## 🏗️ Project Structure
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
jquery-infinite-with-template/
|
|
264
|
+
├── jquery.infiniteScrollWithTemplate.js # Main plugin (unminified)
|
|
265
|
+
├── jquery.infiniteScrollWithTemplate.min.js # Minified version
|
|
266
|
+
├── jquery.infiniteScrollWithTemplate.d.ts # TypeScript definitions
|
|
267
|
+
├── package.json
|
|
268
|
+
├── README.md
|
|
269
|
+
├── LICENSE
|
|
270
|
+
├── examples/
|
|
271
|
+
│ ├── index.html # Demo page
|
|
272
|
+
│ ├── data_sources.json # Demo data
|
|
273
|
+
│ └── generate # Data generator script
|
|
274
|
+
└── tests/
|
|
275
|
+
├── setup.js # Test configuration
|
|
276
|
+
└── jquery.infiniteScrollWithTemplate.test.js # 16 unit tests
|
|
277
|
+
```
|
|
128
278
|
|
|
129
|
-
|
|
279
|
+
## 🧪 Testing
|
|
130
280
|
|
|
131
|
-
|
|
281
|
+
```bash
|
|
282
|
+
# Install dependencies
|
|
283
|
+
npm install
|
|
132
284
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<x-adoption.rounded-card-list :selector="'adoption-rounded-card-list'">
|
|
137
|
-
@foreach($adoptions as $item)
|
|
138
|
-
<x-adoption.rounded-card :item="$item" />
|
|
139
|
-
@endforeach
|
|
140
|
-
</x-adoption.rounded-card-list>
|
|
141
|
-
<x-adoption.rounded-card-tmpl />
|
|
142
|
-
<script>
|
|
143
|
-
$("#adoption-rounded-card-list").infiniteTemplate({
|
|
144
|
-
templateSelector: "#adoption-rounded-card-tmpl",
|
|
145
|
-
dataPath: "/api/adoption",
|
|
146
|
-
initialPage: 3,
|
|
147
|
-
});
|
|
148
|
-
</script>
|
|
285
|
+
# Run tests
|
|
286
|
+
npm test
|
|
149
287
|
```
|
|
150
288
|
|
|
151
|
-
|
|
152
|
-
// https://m.holapet.com/place/pensions/region/1
|
|
153
|
-
|
|
154
|
-
<x-place.rounded-card-list :selector="'place-rounded-card-list'">
|
|
155
|
-
@foreach($region->placesRecent as $item)
|
|
156
|
-
<x-place.rounded-card :item="$item" />
|
|
157
|
-
@endforeach
|
|
158
|
-
</x-place.rounded-card-list>
|
|
159
|
-
<x-place.rounded-card-tmpl />
|
|
160
|
-
<script>
|
|
161
|
-
$("#place-rounded-card-list").infiniteTemplate({
|
|
162
|
-
templateSelector: "#place-rounded-card-tmpl",
|
|
163
|
-
dataPath: "/api/place/pensions/region/{{ $region->id }}",
|
|
164
|
-
initialPage: 3,
|
|
165
|
-
templateHelpers: {
|
|
166
|
-
minColumnCount: 1
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
</script>
|
|
170
|
-
```
|
|
289
|
+
**Test Coverage:**
|
|
171
290
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<script>
|
|
179
|
-
$("#user-list").infiniteTemplate({
|
|
180
|
-
templateSelector: "#user-tmpl",
|
|
181
|
-
dataPath: "/api/user",
|
|
182
|
-
query: "word={{ $word }}",
|
|
183
|
-
templateHelpers: {
|
|
184
|
-
authId : {{ Auth::id() ?? 0 }},
|
|
185
|
-
followeeIds: {!! Auth::user()->followee_ids->toJson() ?? 'false' !!}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
</script>
|
|
189
|
-
@endauth
|
|
190
|
-
@guest
|
|
191
|
-
<script>
|
|
192
|
-
$("#user-list").infiniteTemplate({
|
|
193
|
-
templateSelector: "#user-tmpl",
|
|
194
|
-
dataPath: "/api/user",
|
|
195
|
-
query: "word={{ $word }}",
|
|
196
|
-
});
|
|
197
|
-
</script>
|
|
198
|
-
@endguest
|
|
199
|
-
```
|
|
291
|
+
- ✅ Initialization & validation
|
|
292
|
+
- ✅ Data loading & rendering
|
|
293
|
+
- ✅ Callbacks (zero, error, loading, loaded)
|
|
294
|
+
- ✅ Scroll & click loading modes
|
|
295
|
+
- ✅ URL building & pagination
|
|
296
|
+
- ✅ Edge cases (empty data, JSON parsing)
|
|
200
297
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
298
|
+
## 🤝 Contributing
|
|
299
|
+
|
|
300
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
301
|
+
|
|
302
|
+
1. Fork the project
|
|
303
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
304
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
305
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
306
|
+
5. Open a Pull Request
|
|
307
|
+
|
|
308
|
+
## 📝 License
|
|
309
|
+
|
|
310
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
311
|
+
|
|
312
|
+
## 🙏 Credits
|
|
313
|
+
|
|
314
|
+
- **jsRender** - Template engine
|
|
315
|
+
- **jQuery** - DOM manipulation
|
|
316
|
+
|
|
317
|
+
## 💡 Tips for Getting Stars
|
|
318
|
+
|
|
319
|
+
- ⭐ Star this repo if you find it useful!
|
|
320
|
+
- 🐛 Report bugs and request features
|
|
321
|
+
- 📢 Share with your developer friends
|
|
322
|
+
- 💬 Leave feedback and suggestions
|
|
323
|
+
|
|
324
|
+
## 🔗 Links
|
|
325
|
+
|
|
326
|
+
- **GitHub**: [https://github.com/cable8mm/jquery-infinite-with-template](https://github.com/cable8mm/jquery-infinite-with-template)
|
|
327
|
+
- **NPM**: [https://www.npmjs.com/package/@cable8mm/jquery-infinite-with-template](https://www.npmjs.com/package/@cable8mm/jquery-infinite-with-template)
|
|
328
|
+
- **Issues**: [https://github.com/cable8mm/jquery-infinite-with-template/issues](https://github.com/cable8mm/jquery-infinite-with-template/issues)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
**Made with ❤️ by [Sam Lee](https://github.com/cable8mm)**
|
|
333
|
+
|
|
334
|
+
If this project helped you, please give it a ⭐️!
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"id": 886,
|
|
5
|
+
"title": "ZjLn9jCi1w8nsFSye6A2q9cuu78U88(word=None)"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": 91,
|
|
9
|
+
"title": "VVTFOrWminUAi8E3whuFiyi76sf6L3(word=None)"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": 654,
|
|
13
|
+
"title": "Roc3yFmOHpm4Koj8hhuRr5fBNAUcxZ(word=None)"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": 788,
|
|
17
|
+
"title": "zR7rzbUz81pPYFxvm3NBDFGCUqB0cy(word=None)"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": 7,
|
|
21
|
+
"title": "1OHxyIMH9DahoskhqVbCFINH3aVysn(word=None)"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": 915,
|
|
25
|
+
"title": "9kX2B97YL0onvcE4nRETuACESX9YIM(word=None)"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": 125,
|
|
29
|
+
"title": "jc5fTJ5Y1QzYOtQy6XhiMlRxq05KAc(word=None)"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": 362,
|
|
33
|
+
"title": "rsoNXzq590AQzf6Hp0Gi8rHQfaz9KI(word=None)"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": 101,
|
|
37
|
+
"title": "1msDlWisPm0Q9oUofPdhgjOHuZtlep(word=None)"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": 206,
|
|
41
|
+
"title": "nev0CvpOKc1E0zUuvTrgMUluSowoz5(word=None)"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": 544,
|
|
45
|
+
"title": "aIMdZ9LAf5SDl9hmeFIqzCMgU2joOx(word=None)"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": 415,
|
|
49
|
+
"title": "ikYBbV7nA4S2LPCWk2TYXQ4H5Vp7ia(word=None)"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": 717,
|
|
53
|
+
"title": "H6u32LKXqbgU8rx7UTjsALjKfUPZru(word=None)"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": 536,
|
|
57
|
+
"title": "JuyIiHNlLn0H97APMtB5ng72GAVzBr(word=None)"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": 554,
|
|
61
|
+
"title": "e8cbqBh9ifoEI2nFqyryDBwE87Boy2(word=None)"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": 111,
|
|
65
|
+
"title": "yCJNeoMlqkuNazccgeKwMoj2d9xC6v(word=None)"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": 134,
|
|
69
|
+
"title": "2qZpgg3lJ3djS5RG5IZzZjdtf7Y9IJ(word=None)"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": 523,
|
|
73
|
+
"title": "LC84RteVTWGuAgDDhknpb7jREpqdfY(word=None)"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": 946,
|
|
77
|
+
"title": "q0NnpnSWosOwbxIYQE3ZiMbuqJKG40(word=None)"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": 30,
|
|
81
|
+
"title": "sHc5R2u1W0T45AMxQRx73gAFbGHXk0(word=None)"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
package/examples/generate
CHANGED
|
@@ -2,36 +2,80 @@
|
|
|
2
2
|
<?php
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* jQuery Infinite With Template - Demo Data Generator
|
|
6
|
+
*
|
|
7
|
+
* @example ./generate > data_sources.json
|
|
8
|
+
* @description Generates random demo data for testing infinite scroll
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
// Enable error reporting for debugging
|
|
12
|
+
error_reporting(E_ALL);
|
|
13
|
+
ini_set('display_errors', 0);
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
// Set JSON header
|
|
16
|
+
header('Content-Type: application/json');
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
18
|
+
// Get query parameter (default to 'None' if not provided)
|
|
19
|
+
$query = isset($_GET['word']) ? $_GET['word'] : 'None';
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
// Generate response
|
|
22
|
+
$response = [
|
|
23
|
+
'data' => [],
|
|
24
|
+
'page' => isset($_GET['page']) ? (int)$_GET['page'] : 1,
|
|
25
|
+
'total' => 100 // Simulate total count
|
|
26
|
+
];
|
|
17
27
|
|
|
18
|
-
|
|
28
|
+
// Generate 20 items per page
|
|
29
|
+
$itemsPerPage = 30;
|
|
30
|
+
for ($i = 0; $i < $itemsPerPage; $i++) {
|
|
31
|
+
$response['data'][] = generateItem($query, $response['page'], $i);
|
|
32
|
+
}
|
|
19
33
|
|
|
20
|
-
|
|
34
|
+
// Output JSON
|
|
35
|
+
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generate a single fake item
|
|
39
|
+
*
|
|
40
|
+
* @param string $query Search query
|
|
41
|
+
* @param int $page Current page number
|
|
42
|
+
* @param int $index Item index within page
|
|
43
|
+
* @return array Generated item
|
|
44
|
+
*/
|
|
45
|
+
function generateItem($query, $page, $index)
|
|
21
46
|
{
|
|
47
|
+
static $usedIds = [];
|
|
48
|
+
|
|
49
|
+
// Generate unique ID
|
|
50
|
+
do {
|
|
51
|
+
$id = rand(1, 10000);
|
|
52
|
+
} while (in_array($id, $usedIds));
|
|
53
|
+
|
|
54
|
+
$usedIds[] = $id;
|
|
55
|
+
|
|
22
56
|
return [
|
|
23
|
-
'id' =>
|
|
24
|
-
'title' => generateRandomString(30)."(word=$query)",
|
|
57
|
+
'id' => $id,
|
|
58
|
+
'title' => generateRandomString(30) . "(word=$query, page=$page)",
|
|
59
|
+
'page' => $page,
|
|
60
|
+
'index' => $index
|
|
25
61
|
];
|
|
26
62
|
}
|
|
27
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Generate random string of specified length
|
|
66
|
+
*
|
|
67
|
+
* @param int $length String length
|
|
68
|
+
* @return string Random string
|
|
69
|
+
*/
|
|
28
70
|
function generateRandomString($length = 10)
|
|
29
71
|
{
|
|
30
72
|
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
31
73
|
$charactersLength = strlen($characters);
|
|
32
74
|
$randomString = '';
|
|
75
|
+
|
|
33
76
|
for ($i = 0; $i < $length; $i++) {
|
|
34
77
|
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
|
35
78
|
}
|
|
79
|
+
|
|
36
80
|
return $randomString;
|
|
37
81
|
}
|