├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── libraries
│ ├── Maven__net_sf_jopt_simple_jopt_simple_4_6.xml
│ ├── Maven__org_apache_commons_commons_math3_3_2.xml
│ ├── Maven__org_jetbrains_annotations_13_0.xml
│ ├── Maven__org_jetbrains_kotlin_kotlin_stdlib_1_2_30.xml
│ └── Maven__org_openjdk_jmh_jmh_core_1_20.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── uiDesigner.xml
├── vcs.xml
└── workspace.xml
├── README.md
├── benchmarks.iml
├── commands.txt
├── pom.xml
├── report
├── benchmarks.baseline.json
├── benchmarks.json
├── jquery.dynatable.css
├── jquery.dynatable.js
├── report.html
├── report.js
└── report_java.html
├── src
└── main
│ ├── java
│ └── org
│ │ └── kotlinacademy
│ │ └── PrimitivesJavaBenchmark.java
│ └── kotlin
│ └── org
│ └── kotlinacademy
│ ├── DataModel.kt
│ ├── InlineFilterBenchmark.kt
│ ├── InlineRepeatBenchmark.kt
│ ├── PrimitiveArraysBenchmark.kt
│ └── SequencesBenchmark.kt
└── zdf-win.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | target/**
2 | results/**
3 | *.bat
4 | *.log
5 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | kotlin-benchmarks
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__net_sf_jopt_simple_jopt_simple_4_6.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_commons_commons_math3_3_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_2_30.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_openjdk_jmh_jmh_core_1_20.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | SizedBenchmark
123 | 20
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 | 1523817444179
316 |
317 |
318 | 1523817444179
319 |
320 |
321 | 1523820308375
322 |
323 |
324 |
325 | 1523820308375
326 |
327 |
328 | 1523821555455
329 |
330 |
331 |
332 | 1523821555455
333 |
334 |
335 | 1524858388196
336 |
337 |
338 |
339 | 1524858388196
340 |
341 |
342 | 1524865225391
343 |
344 |
345 |
346 | 1524865225391
347 |
348 |
349 | 1524865280151
350 |
351 |
352 |
353 | 1524865280151
354 |
355 |
356 | 1524867253354
357 |
358 |
359 |
360 | 1524867253354
361 |
362 |
363 | 1524929131087
364 |
365 |
366 |
367 | 1524929131087
368 |
369 |
370 | 1525259623527
371 |
372 |
373 |
374 | 1525259623527
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Based on kotlin-benchmarks [kotlin-benchmarks](https://github.com/JetBrains/kotlin-benchmarks)
2 |
3 | A set of JMH benchmarks for various Kotlin language constructions and standard library functions.
4 |
5 | Build:
6 | ```
7 | mvn clean package
8 | ```
9 |
10 | Note: need clean package every time, otherwise removed benchmarks will be hanging around.
11 |
12 | Run:
13 | ```
14 | java -jar target/benchmarks.jar
15 | ```
16 |
17 | Also see commands.txt for more pre-configured commands.
18 |
19 | # Last results:
20 |
21 | | Benchmark | Mode | Cnt | Score | Error | Units |
22 | | ----------------------------------------------- | ---- | --- | --------------- | ---------- | ----- |
23 | | InlineFilterBenchmark.filterInline | avgt | 200 | 38175.602 ± | 577.725 | ns/op |
24 | | InlineFilterBenchmark.filterNoninline | avgt | 200 | 41211.566 ± | 318.711 | ns/op |
25 | | InlineRepeatBenchmark.repeatInline | avgt | 200 | 0.306 ± | 0.003 | ns/op |
26 | | InlineRepeatBenchmark.repeatNoninline | avgt | 200 | 156214223.616 ± | 444202.273 | ns/op |
27 | | PrimitiveArraysBenchmark.averageOnIntArray | avgt | 200 | 1198961.660 ± | 2420.378 | ns/op |
28 | | PrimitiveArraysBenchmark.averageOnIntList | avgt | 200 | 1439895.837 ± | 17428.123 | ns/op |
29 | | PrimitivesJavaBenchmark.objectCount10000 | avgt | 200 | 47454.720 ± | 85.221 | ns/op |
30 | | PrimitivesJavaBenchmark.objectCount1_000_000 | avgt | 200 | 4905603.432 ± | 15968.358 | ns/op |
31 | | PrimitivesJavaBenchmark.primitiveCount10_000 | avgt | 200 | 3164.642 ± | 3.780 | ns/op |
32 | | PrimitivesJavaBenchmark.primitiveCount1_000_000 | avgt | 200 | 316594.815 ± | 406.338 | ns/op |
33 | | SequancesBenchmark.productsListProcessing | avgt | 200 | 712434.095 ± | 3863.956 | ns/op |
34 | | SequancesBenchmark.productsSequenceProcessing | avgt | 200 | 572012.022 ± | 10992.150 | ns/op |
35 | | SequancesBenchmark.simpleListProcessing | avgt | 200 | 15190.734 ± | 61.496 | ns/op |
36 | | SequancesBenchmark.simpleSequenceProcessing | avgt | 200 | 3514.539 ± | 3.970 | ns/op |
37 | | SequancesBenchmark.singleStepListProcessing | avgt | 200 | 33811.473 ± | 278.746 | ns/op |
38 | | SequancesBenchmark.singleStepSequenceProcessing | avgt | 200 | 35929.193 ± | 326.405 | ns/op |
39 | | SequancesBenchmark.threeStepListProcessing | avgt | 200 | 83307.285 ± | 206.103 | ns/op |
40 | | SequancesBenchmark.threeStepSequenceProcessing | avgt | 200 | 6928.032 ± | 39.900 | ns/op |
41 | | SequancesBenchmark.twoStepListProcessing | avgt | 200 | 81095.456 ± | 210.257 | ns/op |
42 | | SequancesBenchmark.twoStepSequenceProcessing | avgt | 200 | 55685.351 ± | 359.406 | ns/op |
43 |
44 |
--------------------------------------------------------------------------------
/benchmarks.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/commands.txt:
--------------------------------------------------------------------------------
1 | java -jar target/benchmarks.jar -help
2 |
3 | ---- Measure ----
4 | // 18 hrs
5 | java -jar target/benchmarks.jar -wi 20 -i 20 -f 4 -tu ns -bm avgt -rf text -rff results/benchmarks-8.txt -o log.txt
6 |
7 | // 5 hrs
8 | java -jar target/benchmarks.jar -wi 20 -i 10 -f 2 -tu ns -bm avgt -rf text -rff results/benchmarks-8.txt -o log.txt
9 |
10 | // 2 hrs
11 | java -jar target/benchmarks.jar -wi 20 -i 10 -f 1 -tu ns -bm avgt -rf text -rff results/benchmarks-8.txt -o log.txt
12 |
13 | ---- Fast check ----
14 | java -jar target/benchmarks.jar -wi 0 -i 1 -f 1 -tu ns -bm avgt
15 |
16 | ---- Baseline ----
17 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt -rf json -rff report/benchmarks.json ".*Baseline.*"
18 |
19 | ---- Analyse ----
20 |
21 |
22 | java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ms ".*Inline.*"
23 | java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ms ".*Inline.*"
24 | java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -jar target/benchmarks.jar -wi 1 -i 5 -f 1 -tu us -bm avgt -prof comp ".*Inline.*calculateInline.*"
25 | java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+PrintCompilation -XX:+LogCompilation -XX:+PrintAssembly -jar target/benchmarks.jar -wi 1 -i 5 -f 1 -tu us -bm avgt -prof comp ".*Inline.*calculateInline.*"
26 |
27 | javap -c target/classes/org/jetbrains/... > temp.asm
28 |
29 | -- yourkit ---
30 | -agentpath:/Applications/YourKit\ 2013.app/bin/mac/libyjpagent.jnilib
31 | java -agentpath:/Applications/YourKit\ 2013.app/bin/mac/libyjpagent.jnilib -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt "Class.*Stream.*filterAndMapSeq.*" -p size="1000" -prof stack
32 |
33 | ---- TEMP ----
34 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt ".*IntList.*"
35 | java -jar target/benchmarks.jar -wi 1 -i 5 -f 1 -tu us -bm avgt -prof comp ".*Inline.*calculateInline.*"
36 | java -jar target/benchmarks.jar -wi 1 -i 5 -f 1 -tu us -bm avgt ".*Inline.*calculateInline.*"
37 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ms ".*IntList.*"
38 | java -jar target/benchmarks.jar -wi 20 -i 20 -f 1 -tu ms -rf text -rff results/benchmarks-8-tiny.txt
39 |
40 | java -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu us -p size="10000" "stringConcatNullable"
41 | java6 -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu us -p size="10000" "stringConcatNullable"
42 | java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu us -p size="10000" "stringConcatNullable"
43 |
44 |
45 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt ".*Baseline.*consume.*" -rf text -rff results/benchmarks-8-consume.txt
46 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt ".*JavaStream.*" -rf text -rff results/benchmarks-8-java-stream.txt
47 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu ns -bm avgt "\.ClassStream.*" -p size="1000"
48 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu us -bm avgt "Class.*Stream.*filterAndMap.*" -p size="1000"
49 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu us -bm avgt "Class" -p size="100000" -rf text -rff results/benchmarks-8-class-100000.txt
50 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu us -bm avgt "Class" -p size="1000" -rf text -rff results/benchmarks-8-class.txt
51 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu us -bm avgt "Class" -p size="100" -rf text -rff results/benchmarks-8-class-100.txt
52 |
53 | java -jar target/benchmarks.jar -wi 10 -i 5 -f 1 -tu us -bm avgt -p size="100000" -rf text -rff results/benchmarks-8-100000.txt
54 |
55 |
56 | java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ms -bm avgt -p size="1000000" ".*OSR.*"
57 | java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -jar target/benchmarks.jar -wi 1 -i 5 -f 1 -tu us -bm avgt ".*OSR.*"
58 |
59 | /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/bin/java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ns -bm avgt -p size="1000" -rf text -rff results/benchmark-8-inline.txt ".*OSR.*"
60 |
61 | -- LINUX ---
62 | /usr/java64/jdk1.8.0_11/bin/java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ns -bm avgt -prof perfasm -rf text -rff results/benchmark-8-asm.txt
63 |
64 | /usr/java64/jdk1.8.0_11/bin/java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ns -bm avgt -prof perfasm -rf text -rff results/benchmark-8-inline-asm.txt ".*Inline.*calculateInline"
65 | /usr/java64/jdk1.8.0_20/bin/java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ns -bm avgt -prof perfasm ".*Inline.*calculateInline" > log_20
66 | /usr/java64/jdk1.8.0_11/bin/java -jar target/benchmarks.jar -wi 5 -i 5 -f 1 -tu ns -bm avgt -prof perfasm ".*Inline.*calculateInline" > log_11
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.jetbrains.kotlin
7 | benchmarks
8 | 1.2.31
9 | jar
10 |
11 | Kotlin benchmarks
12 |
13 |
14 | 1.2.30
15 | UTF-8
16 | 1.20
17 | default
18 |
19 | 1.8
20 | benchmarks
21 |
22 |
23 |
28 |
29 |
30 |
31 | sonatype-oss
32 | Sonatype OSS
33 | http://oss.sonatype.org/content/repositories/snapshots
34 |
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 | sonatype.oss.snapshots
43 | Sonatype OSS Snapshot Repository
44 | http://oss.sonatype.org/content/repositories/snapshots
45 |
46 | false
47 |
48 |
49 | true
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.openjdk.jmh
57 | jmh-core
58 | ${jmh.version}
59 |
60 |
64 |
65 | org.jetbrains.kotlin
66 | kotlin-stdlib
67 | ${kotlin.version}
68 |
69 |
70 |
71 |
72 |
73 | 3.0.4
74 |
75 |
76 |
77 |
78 |
79 |
82 |
83 |
84 | kotlin-maven-plugin
85 | org.jetbrains.kotlin
86 |
89 | ${kotlin.version}
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | process-sources
100 | generate-sources
101 |
102 | compile
103 |
104 |
105 |
106 | ${project.basedir}/src/main/kotlin
107 |
108 |
109 |
110 |
111 |
112 |
113 |
116 |
117 |
118 | org.codehaus.mojo
119 | exec-maven-plugin
120 | 1.2.1
121 |
122 |
123 | generate-resources
124 |
125 | java
126 |
127 |
128 | true
129 | org.openjdk.jmh.generators.bytecode.JmhBytecodeGenerator
130 |
131 | ${project.basedir}/target/classes/
132 | ${project.basedir}/target/generated-sources/jmh/
133 | ${project.basedir}/target/classes/
134 | ${jmh.generator}
135 |
136 |
137 |
138 |
139 |
140 |
141 | org.openjdk.jmh
142 | jmh-generator-bytecode
143 | ${jmh.version}
144 |
145 |
146 |
147 |
148 |
151 |
152 |
153 | org.codehaus.mojo
154 | build-helper-maven-plugin
155 | 1.8
156 |
157 |
158 | add-source
159 | process-resources
160 |
161 | add-source
162 |
163 |
164 |
165 | ${project.basedir}/target/generated-sources/jmh
166 |
167 |
168 |
169 |
170 |
171 |
172 |
175 |
176 |
177 | org.apache.maven.plugins
178 | maven-compiler-plugin
179 | 3.1
180 |
181 | ${javac.target}
182 | ${javac.target}
183 | ${javac.target}
184 | -proc:none
185 |
186 |
187 |
188 | compile-sources
189 | process-sources
190 |
191 | compile
192 |
193 |
194 |
195 | compile-all
196 | compile
197 |
198 | compile
199 |
200 |
201 |
202 |
203 |
204 |
207 |
208 |
209 | org.apache.maven.plugins
210 | maven-shade-plugin
211 | 2.2
212 |
213 |
214 | package
215 |
216 | shade
217 |
218 |
219 | ${uberjar.name}
220 |
221 |
223 | org.openjdk.jmh.Main
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/report/jquery.dynatable.css:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Dynatable plugin 0.3.1
3 | *
4 | * Copyright (c) 2014 Steve Schwartz (JangoSteve)
5 | *
6 | * Dual licensed under the AGPL and Proprietary licenses:
7 | * http://www.dynatable.com/license/
8 | *
9 | * Date: Tue Jan 02 2014
10 | */
11 | .dynatable-search {
12 | float: right;
13 | margin-bottom: 10px;
14 | }
15 |
16 | .improvement {
17 | color: #71AF5A;
18 | }
19 | .regression {
20 | color: brown;
21 | }
22 | .defeat {
23 | color: red;
24 | font-weight: bold;
25 | }
26 | .same {
27 | color: darkgrey;
28 | }
29 |
30 | .dynatable-pagination-links {
31 | float: right;
32 | }
33 |
34 | .dynatable-record-count {
35 | display: block;
36 | padding: 5px 0;
37 | }
38 |
39 | .dynatable-pagination-links span,
40 | .dynatable-pagination-links li {
41 | display: inline-block;
42 | }
43 |
44 | .dynatable-page-link,
45 | .dynatable-page-break {
46 | display: block;
47 | padding: 5px 7px;
48 | }
49 |
50 | .dynatable-page-link {
51 | cursor: pointer;
52 | }
53 |
54 | .dynatable-active-page,
55 | .dynatable-disabled-page {
56 | cursor: text;
57 | }
58 | .dynatable-active-page:hover,
59 | .dynatable-disabled-page:hover {
60 | text-decoration: none;
61 | }
62 |
63 | .dynatable-active-page {
64 | background: #71AF5A;
65 | border-radius: 5px;
66 | color: #fff;
67 | }
68 | .dynatable-active-page:hover {
69 | color: #fff;
70 | }
71 | .dynatable-disabled-page,
72 | .dynatable-disabled-page:hover {
73 | background: none;
74 | color: #999;
75 | }
76 |
--------------------------------------------------------------------------------
/report/jquery.dynatable.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Dynatable plugin 0.3.1
3 | *
4 | * Copyright (c) 2014 Steve Schwartz (JangoSteve)
5 | *
6 | * Dual licensed under the AGPL and Proprietary licenses:
7 | * http://www.dynatable.com/license/
8 | *
9 | * Date: Tue Jan 02 2014
10 | */
11 | //
12 |
13 | (function($) {
14 | var defaults,
15 | mergeSettings,
16 | dt,
17 | Model,
18 | modelPrototypes = {
19 | dom: Dom,
20 | domColumns: DomColumns,
21 | records: Records,
22 | recordsCount: RecordsCount,
23 | processingIndicator: ProcessingIndicator,
24 | state: State,
25 | sorts: Sorts,
26 | sortsHeaders: SortsHeaders,
27 | queries: Queries,
28 | inputsSearch: InputsSearch,
29 | paginationPage: PaginationPage,
30 | paginationPerPage: PaginationPerPage,
31 | paginationLinks: PaginationLinks
32 | },
33 | utility,
34 | build,
35 | processAll,
36 | initModel,
37 | defaultRowWriter,
38 | defaultCellWriter,
39 | defaultAttributeWriter,
40 | defaultAttributeReader;
41 |
42 | //-----------------------------------------------------------------
43 | // Cached plugin global defaults
44 | //-----------------------------------------------------------------
45 |
46 | defaults = {
47 | features: {
48 | paginate: true,
49 | sort: true,
50 | pushState: true,
51 | search: true,
52 | recordCount: true,
53 | perPageSelect: true
54 | },
55 | table: {
56 | defaultColumnIdStyle: 'camelCase',
57 | columns: null,
58 | headRowSelector: 'thead tr', // or e.g. tr:first-child
59 | bodyRowSelector: 'tbody tr',
60 | headRowClass: null
61 | },
62 | inputs: {
63 | queries: null,
64 | sorts: null,
65 | multisort: ['ctrlKey', 'shiftKey', 'metaKey'],
66 | page: null,
67 | queryEvent: 'blur change',
68 | recordCountTarget: null,
69 | recordCountPlacement: 'after',
70 | paginationLinkTarget: null,
71 | paginationLinkPlacement: 'after',
72 | paginationClass: 'dynatable-pagination-links',
73 | paginationLinkClass: 'dynatable-page-link',
74 | paginationPrevClass: 'dynatable-page-prev',
75 | paginationNextClass: 'dynatable-page-next',
76 | paginationActiveClass: 'dynatable-active-page',
77 | paginationDisabledClass: 'dynatable-disabled-page',
78 | paginationPrev: 'Previous',
79 | paginationNext: 'Next',
80 | paginationGap: [1,2,2,1],
81 | searchTarget: null,
82 | searchPlacement: 'before',
83 | perPageTarget: null,
84 | perPagePlacement: 'before',
85 | perPageText: 'Show: ',
86 | recordCountText: 'Showing ',
87 | processingText: 'Processing...'
88 | },
89 | dataset: {
90 | ajax: false,
91 | ajaxUrl: null,
92 | ajaxCache: null,
93 | ajaxOnLoad: false,
94 | ajaxMethod: 'GET',
95 | ajaxDataType: 'json',
96 | totalRecordCount: null,
97 | queries: {},
98 | queryRecordCount: null,
99 | page: null,
100 | perPageDefault: 10,
101 | perPageOptions: [10,20,50,100],
102 | sorts: {},
103 | sortsKeys: null,
104 | sortTypes: {},
105 | records: null
106 | },
107 | writers: {
108 | _rowWriter: defaultRowWriter,
109 | _cellWriter: defaultCellWriter,
110 | _attributeWriter: defaultAttributeWriter
111 | },
112 | readers: {
113 | _rowReader: null,
114 | _attributeReader: defaultAttributeReader
115 | },
116 | params: {
117 | dynatable: 'dynatable',
118 | queries: 'queries',
119 | sorts: 'sorts',
120 | page: 'page',
121 | perPage: 'perPage',
122 | offset: 'offset',
123 | records: 'records',
124 | record: null,
125 | queryRecordCount: 'queryRecordCount',
126 | totalRecordCount: 'totalRecordCount'
127 | }
128 | };
129 |
130 | //-----------------------------------------------------------------
131 | // Each dynatable instance inherits from this,
132 | // set properties specific to instance
133 | //-----------------------------------------------------------------
134 |
135 | dt = {
136 | init: function(element, options) {
137 | this.settings = mergeSettings(options);
138 | this.element = element;
139 | this.$element = $(element);
140 |
141 | // All the setup that doesn't require element or options
142 | build.call(this);
143 |
144 | return this;
145 | },
146 |
147 | process: function(skipPushState) {
148 | processAll.call(this, skipPushState);
149 | }
150 | };
151 |
152 | //-----------------------------------------------------------------
153 | // Cached plugin global functions
154 | //-----------------------------------------------------------------
155 |
156 | mergeSettings = function(options) {
157 | var newOptions = $.extend(true, {}, defaults, options);
158 |
159 | // TODO: figure out a better way to do this.
160 | // Doing `extend(true)` causes any elements that are arrays
161 | // to merge the default and options arrays instead of overriding the defaults.
162 | if (options) {
163 | if (options.inputs) {
164 | if (options.inputs.multisort) {
165 | newOptions.inputs.multisort = options.inputs.multisort;
166 | }
167 | if (options.inputs.paginationGap) {
168 | newOptions.inputs.paginationGap = options.inputs.paginationGap;
169 | }
170 | }
171 | if (options.dataset && options.dataset.perPageOptions) {
172 | newOptions.dataset.perPageOptions = options.dataset.perPageOptions;
173 | }
174 | }
175 |
176 | return newOptions;
177 | };
178 |
179 | build = function() {
180 | this.$element.trigger('dynatable:preinit', this);
181 |
182 | for (model in modelPrototypes) {
183 | if (modelPrototypes.hasOwnProperty(model)) {
184 | var modelInstance = this[model] = new modelPrototypes[model](this, this.settings);
185 | if (modelInstance.initOnLoad()) {
186 | modelInstance.init();
187 | }
188 | }
189 | }
190 |
191 | this.$element.trigger('dynatable:init', this);
192 |
193 | if (!this.settings.dataset.ajax || (this.settings.dataset.ajax && this.settings.dataset.ajaxOnLoad) || this.settings.features.paginate) {
194 | this.process();
195 | }
196 | };
197 |
198 | processAll = function(skipPushState) {
199 | var data = {};
200 |
201 | this.$element.trigger('dynatable:beforeProcess', data);
202 |
203 | if (!$.isEmptyObject(this.settings.dataset.queries)) { data[this.settings.params.queries] = this.settings.dataset.queries; }
204 | // TODO: Wrap this in a try/rescue block to hide the processing indicator and indicate something went wrong if error
205 | this.processingIndicator.show();
206 |
207 | if (this.settings.features.sort && !$.isEmptyObject(this.settings.dataset.sorts)) { data[this.settings.params.sorts] = this.settings.dataset.sorts; }
208 | if (this.settings.features.paginate && this.settings.dataset.page) {
209 | var page = this.settings.dataset.page,
210 | perPage = this.settings.dataset.perPage;
211 | data[this.settings.params.page] = page;
212 | data[this.settings.params.perPage] = perPage;
213 | data[this.settings.params.offset] = (page - 1) * perPage;
214 | }
215 | if (this.settings.dataset.ajaxData) { $.extend(data, this.settings.dataset.ajaxData); }
216 |
217 | // If ajax, sends query to ajaxUrl with queries and sorts serialized and appended in ajax data
218 | // otherwise, executes queries and sorts on in-page data
219 | if (this.settings.dataset.ajax) {
220 | var _this = this;
221 | var options = {
222 | type: _this.settings.dataset.ajaxMethod,
223 | dataType: _this.settings.dataset.ajaxDataType,
224 | data: data,
225 | error: function(xhr, error) {
226 | },
227 | success: function(response) {
228 | _this.$element.trigger('dynatable:ajax:success', response);
229 | // Merge ajax results and meta-data into dynatables cached data
230 | _this.records.updateFromJson(response);
231 | // update table with new records
232 | _this.dom.update();
233 |
234 | if (!skipPushState && _this.state.initOnLoad()) {
235 | _this.state.push(data);
236 | }
237 | },
238 | complete: function() {
239 | _this.processingIndicator.hide();
240 | }
241 | };
242 | // Do not pass url to `ajax` options if blank
243 | if (this.settings.dataset.ajaxUrl) {
244 | options.url = this.settings.dataset.ajaxUrl;
245 |
246 | // If ajaxUrl is blank, then we're using the current page URL,
247 | // we need to strip out any query, sort, or page data controlled by dynatable
248 | // that may have been in URL when page loaded, so that it doesn't conflict with
249 | // what's passed in with the data ajax parameter
250 | } else {
251 | options.url = utility.refreshQueryString(window.location.href, {}, this.settings);
252 | }
253 | if (this.settings.dataset.ajaxCache !== null) { options.cache = this.settings.dataset.ajaxCache; }
254 |
255 | $.ajax(options);
256 | } else {
257 | this.records.resetOriginal();
258 | this.queries.run();
259 | if (this.settings.features.sort) {
260 | this.records.sort();
261 | }
262 | if (this.settings.features.paginate) {
263 | this.records.paginate();
264 | }
265 | this.dom.update();
266 | this.processingIndicator.hide();
267 |
268 | if (!skipPushState && this.state.initOnLoad()) {
269 | this.state.push(data);
270 | }
271 | }
272 | this.$element.trigger('dynatable:afterProcess', data);
273 | };
274 |
275 | function defaultRowWriter(rowIndex, record, columns, cellWriter) {
276 | var tr = '';
277 |
278 | // grab the record's attribute for each column
279 | for (var i = 0, len = columns.length; i < len; i++) {
280 | tr += cellWriter(columns[i], record);
281 | }
282 |
283 | if (record._class == undefined)
284 | return '
' + tr + '
';
285 | return '' + tr + '
';
286 | };
287 |
288 | function defaultCellWriter(column, record) {
289 | var html = column.attributeWriter(record);
290 | var _class = record[column.id + "_class"];
291 | var td = '' + html + ' | ';
313 | };
314 |
315 | function defaultAttributeWriter(record) {
316 | // `this` is the column object in settings.columns
317 | // TODO: automatically convert common types, such as arrays and objects, to string
318 | return record[this.id];
319 | };
320 |
321 | function defaultAttributeReader(cell, record) {
322 | return $(cell).html();
323 | };
324 |
325 | //-----------------------------------------------------------------
326 | // Dynatable object model prototype
327 | // (all object models get these default functions)
328 | //-----------------------------------------------------------------
329 |
330 | Model = {
331 | initOnLoad: function() {
332 | return true;
333 | },
334 |
335 | init: function() {}
336 | };
337 |
338 | for (model in modelPrototypes) {
339 | if (modelPrototypes.hasOwnProperty(model)) {
340 | var modelPrototype = modelPrototypes[model];
341 | modelPrototype.prototype = Model;
342 | }
343 | }
344 |
345 | //-----------------------------------------------------------------
346 | // Dynatable object models
347 | //-----------------------------------------------------------------
348 |
349 | function Dom(obj, settings) {
350 | var _this = this;
351 |
352 | // update table contents with new records array
353 | // from query (whether ajax or not)
354 | this.update = function() {
355 | var rows = '',
356 | columns = settings.table.columns,
357 | rowWriter = settings.writers._rowWriter,
358 | cellWriter = settings.writers._cellWriter;
359 |
360 | obj.$element.trigger('dynatable:beforeUpdate', rows);
361 |
362 | // loop through records
363 | for (var i = 0, len = settings.dataset.records.length; i < len; i++) {
364 | var record = settings.dataset.records[i],
365 | tr = rowWriter(i, record, columns, cellWriter);
366 | rows += tr;
367 | }
368 |
369 | // Appended dynatable interactive elements
370 | if (settings.features.recordCount) {
371 | $('#dynatable-record-count-' + obj.element.id).replaceWith(obj.recordsCount.create());
372 | }
373 | if (settings.features.paginate) {
374 | $('#dynatable-pagination-links-' + obj.element.id).replaceWith(obj.paginationLinks.create());
375 | if (settings.features.perPageSelect) {
376 | $('#dynatable-per-page-' + obj.element.id).val(parseInt(settings.dataset.perPage));
377 | }
378 | }
379 |
380 | // Sort headers functionality
381 | if (settings.features.sort && columns) {
382 | obj.sortsHeaders.removeAllArrows();
383 | for (var i = 0, len = columns.length; i < len; i++) {
384 | var column = columns[i],
385 | sortedByColumn = utility.allMatch(settings.dataset.sorts, column.sorts, function(sorts, sort) { return sort in sorts; }),
386 | value = settings.dataset.sorts[column.sorts[0]];
387 |
388 | if (sortedByColumn) {
389 | obj.$element.find('[data-dynatable-column="' + column.id + '"]').find('.dynatable-sort-header').each(function(){
390 | if (value == 1) {
391 | obj.sortsHeaders.appendArrowUp($(this));
392 | } else {
393 | obj.sortsHeaders.appendArrowDown($(this));
394 | }
395 | });
396 | }
397 | }
398 | }
399 |
400 | // Query search functionality
401 | if (settings.inputs.queries || settings.features.search) {
402 | var allQueries = settings.inputs.queries || $();
403 | if (settings.features.search) {
404 | allQueries = allQueries.add('#dynatable-query-search-' + obj.element.id);
405 | }
406 |
407 | allQueries.each(function() {
408 | var $this = $(this),
409 | q = settings.dataset.queries[$this.data('dynatable-query')];
410 | $this.val(q || '');
411 | });
412 | }
413 |
414 | obj.$element.find(settings.table.bodyRowSelector).remove();
415 | obj.$element.append(rows);
416 |
417 | obj.$element.trigger('dynatable:afterUpdate', rows);
418 | };
419 | };
420 |
421 | function DomColumns(obj, settings) {
422 | var _this = this;
423 |
424 | this.initOnLoad = function() {
425 | return obj.$element.is('table');
426 | };
427 |
428 | this.init = function() {
429 | settings.table.columns = [];
430 | this.getFromTable();
431 | };
432 |
433 | // initialize table[columns] array
434 | this.getFromTable = function() {
435 | var $columns = obj.$element.find(settings.table.headRowSelector).children('th,td');
436 | if ($columns.length) {
437 | $columns.each(function(index){
438 | _this.add($(this), index, true);
439 | });
440 | } else {
441 | return $.error("Couldn't find any columns headers in '" + settings.table.headRowSelector + " th,td'. If your header row is different, specify the selector in the table: headRowSelector option.");
442 | }
443 | };
444 |
445 | this.add = function($column, position, skipAppend, skipUpdate) {
446 | var columns = settings.table.columns,
447 | label = $column.text(),
448 | id = $column.data('dynatable-column') || utility.normalizeText(label, settings.table.defaultColumnIdStyle),
449 | dataSorts = $column.data('dynatable-sorts'),
450 | sorts = dataSorts ? $.map(dataSorts.split(','), function(text) { return $.trim(text); }) : [id];
451 |
452 | // If the column id is blank, generate an id for it
453 | if ( !id ) {
454 | this.generate($column);
455 | id = $column.data('dynatable-column');
456 | }
457 | // Add column data to plugin instance
458 | columns.splice(position, 0, {
459 | index: position,
460 | label: label,
461 | id: id,
462 | attributeWriter: settings.writers[id] || settings.writers._attributeWriter,
463 | attributeReader: settings.readers[id] || settings.readers._attributeReader,
464 | sorts: sorts,
465 | hidden: $column.css('display') === 'none',
466 | textAlign: $column.css('text-align')
467 | });
468 |
469 | // Modify header cell
470 | $column
471 | .attr('data-dynatable-column', id)
472 | .addClass('dynatable-head');
473 | if (settings.table.headRowClass) { $column.addClass(settings.table.headRowClass); }
474 |
475 | // Append column header to table
476 | if (!skipAppend) {
477 | var domPosition = position + 1,
478 | $sibling = obj.$element.find(settings.table.headRowSelector)
479 | .children('th:nth-child(' + domPosition + '),td:nth-child(' + domPosition + ')').first(),
480 | columnsAfter = columns.slice(position + 1, columns.length);
481 |
482 | if ($sibling.length) {
483 | $sibling.before($column);
484 | // sibling column doesn't yet exist (maybe this is the last column in the header row)
485 | } else {
486 | obj.$element.find(settings.table.headRowSelector).append($column);
487 | }
488 |
489 | obj.sortsHeaders.attachOne($column.get());
490 |
491 | // increment the index of all columns after this one that was just inserted
492 | if (columnsAfter.length) {
493 | for (var i = 0, len = columnsAfter.length; i < len; i++) {
494 | columnsAfter[i].index += 1;
495 | }
496 | }
497 |
498 | if (!skipUpdate) {
499 | obj.dom.update();
500 | }
501 | }
502 |
503 | return dt;
504 | };
505 |
506 | this.remove = function(columnIndexOrId) {
507 | var columns = settings.table.columns,
508 | length = columns.length;
509 |
510 | if (typeof(columnIndexOrId) === "number") {
511 | var column = columns[columnIndexOrId];
512 | this.removeFromTable(column.id);
513 | this.removeFromArray(columnIndexOrId);
514 | } else {
515 | // Traverse columns array in reverse order so that subsequent indices
516 | // don't get messed up when we delete an item from the array in an iteration
517 | for (var i = columns.length - 1; i >= 0; i--) {
518 | var column = columns[i];
519 |
520 | if (column.id === columnIndexOrId) {
521 | this.removeFromTable(columnIndexOrId);
522 | this.removeFromArray(i);
523 | }
524 | }
525 | }
526 |
527 | obj.dom.update();
528 | };
529 |
530 | this.removeFromTable = function(columnId) {
531 | obj.$element.find(settings.table.headRowSelector).children('[data-dynatable-column="' + columnId + '"]').first()
532 | .remove();
533 | };
534 |
535 | this.removeFromArray = function(index) {
536 | var columns = settings.table.columns,
537 | adjustColumns;
538 | columns.splice(index, 1);
539 | adjustColumns = columns.slice(index, columns.length);
540 | for (var i = 0, len = adjustColumns.length; i < len; i++) {
541 | adjustColumns[i].index -= 1;
542 | }
543 | };
544 |
545 | this.generate = function($cell) {
546 | var cell = $cell === undefined ? $(' | ') : $cell;
547 | return this.attachGeneratedAttributes(cell);
548 | };
549 |
550 | this.attachGeneratedAttributes = function($cell) {
551 | // Use increment to create unique column name that is the same each time the page is reloaded,
552 | // in order to avoid errors with mismatched attribute names when loading cached `dataset.records` array
553 | var increment = obj.$element.find(settings.table.headRowSelector).children('th[data-dynatable-generated]').length;
554 | return $cell
555 | .attr('data-dynatable-column', 'dynatable-generated-' + increment) //+ utility.randomHash(),
556 | .attr('data-dynatable-no-sort', 'true')
557 | .attr('data-dynatable-generated', increment);
558 | };
559 | };
560 |
561 | function Records(obj, settings) {
562 | var _this = this;
563 |
564 | this.initOnLoad = function() {
565 | return !settings.dataset.ajax;
566 | };
567 |
568 | this.init = function() {
569 | if (settings.dataset.records === null) {
570 | settings.dataset.records = this.getFromTable();
571 |
572 | if (!settings.dataset.queryRecordCount) {
573 | settings.dataset.queryRecordCount = this.count();
574 | }
575 |
576 | if (!settings.dataset.totalRecordCount){
577 | settings.dataset.totalRecordCount = settings.dataset.queryRecordCount;
578 | }
579 | }
580 |
581 | // Create cache of original full recordset (unpaginated and unqueried)
582 | settings.dataset.originalRecords = $.extend(true, [], settings.dataset.records);
583 | };
584 |
585 | // merge ajax response json with cached data including
586 | // meta-data and records
587 | this.updateFromJson = function(data) {
588 | var records;
589 | if (settings.params.records === "_root") {
590 | records = data;
591 | } else if (settings.params.records in data) {
592 | records = data[settings.params.records];
593 | }
594 | if (settings.params.record) {
595 | var len = records.length - 1;
596 | for (var i = 0; i < len; i++) {
597 | records[i] = records[i][settings.params.record];
598 | }
599 | }
600 | if (settings.params.queryRecordCount in data) {
601 | settings.dataset.queryRecordCount = data[settings.params.queryRecordCount];
602 | }
603 | if (settings.params.totalRecordCount in data) {
604 | settings.dataset.totalRecordCount = data[settings.params.totalRecordCount];
605 | }
606 | settings.dataset.records = records;
607 | };
608 |
609 | // For really advanced sorting,
610 | // see http://james.padolsey.com/javascript/sorting-elements-with-jquery/
611 | this.sort = function() {
612 | var sort = [].sort,
613 | sorts = settings.dataset.sorts,
614 | sortsKeys = settings.dataset.sortsKeys,
615 | sortTypes = settings.dataset.sortTypes;
616 |
617 | var sortFunction = function(a, b) {
618 | var comparison;
619 | if ($.isEmptyObject(sorts)) {
620 | comparison = obj.sorts.functions['originalPlacement'](a, b);
621 | } else {
622 | for (var i = 0, len = sortsKeys.length; i < len; i++) {
623 | var attr = sortsKeys[i],
624 | direction = sorts[attr],
625 | sortType = sortTypes[attr] || obj.sorts.guessType(a, b, attr);
626 | comparison = obj.sorts.functions[sortType](a, b, attr, direction);
627 | // Don't need to sort any further unless this sort is a tie between a and b,
628 | // so break the for loop unless tied
629 | if (comparison !== 0) { break; }
630 | }
631 | }
632 | return comparison;
633 | }
634 |
635 | return sort.call(settings.dataset.records, sortFunction);
636 | };
637 |
638 | this.paginate = function() {
639 | var bounds = this.pageBounds(),
640 | first = bounds[0], last = bounds[1];
641 | settings.dataset.records = settings.dataset.records.slice(first, last);
642 | };
643 |
644 | this.resetOriginal = function() {
645 | settings.dataset.records = settings.dataset.originalRecords || [];
646 | };
647 |
648 | this.pageBounds = function() {
649 | var page = settings.dataset.page || 1,
650 | first = (page - 1) * settings.dataset.perPage,
651 | last = Math.min(first + settings.dataset.perPage, settings.dataset.queryRecordCount);
652 | return [first,last];
653 | };
654 |
655 | // get initial recordset to populate table
656 | // if ajax, call ajaxUrl
657 | // otherwise, initialize from in-table records
658 | this.getFromTable = function() {
659 | var records = [],
660 | columns = settings.table.columns,
661 | tableRecords = obj.$element.find(settings.table.bodyRowSelector);
662 |
663 | tableRecords.each(function(index){
664 | var record = {};
665 | record['dynatable-original-index'] = index;
666 | $(this).find('th,td').each(function(index) {
667 | if (columns[index] === undefined) {
668 | // Header cell didn't exist for this column, so let's generate and append
669 | // a new header cell with a randomly generated name (so we can store and
670 | // retrieve the contents of this column for each record)
671 | obj.domColumns.add(obj.domColumns.generate(), columns.length, false, true); // don't skipAppend, do skipUpdate
672 | }
673 | var value = columns[index].attributeReader(this, record),
674 | attr = columns[index].id;
675 |
676 | // If value from table is HTML, let's get and cache the text equivalent for
677 | // the default string sorting, since it rarely makes sense for sort headers
678 | // to sort based on HTML tags.
679 | if (typeof(value) === "string" && value.match(/\s*\<.+\>/)) {
680 | if (! record['dynatable-sortable-text']) {
681 | record['dynatable-sortable-text'] = {};
682 | }
683 | record['dynatable-sortable-text'][attr] = $.trim($('').html(value).text());
684 | }
685 |
686 | record[attr] = value;
687 | });
688 | // Allow configuration function which alters record based on attributes of
689 | // table row (e.g. from html5 data- attributes)
690 | if (typeof(settings.readers._rowReader) === "function") {
691 | settings.readers._rowReader(index, this, record);
692 | }
693 | records.push(record);
694 | });
695 | return records; // 1st row is header
696 | };
697 |
698 | // count records from table
699 | this.count = function() {
700 | return settings.dataset.records.length;
701 | };
702 | };
703 |
704 | function RecordsCount(obj, settings) {
705 | this.initOnLoad = function() {
706 | return settings.features.recordCount;
707 | };
708 |
709 | this.init = function() {
710 | this.attach();
711 | };
712 |
713 | this.create = function() {
714 | var recordsShown = obj.records.count(),
715 | recordsQueryCount = settings.dataset.queryRecordCount,
716 | recordsTotal = settings.dataset.totalRecordCount,
717 | text = settings.inputs.recordCountText,
718 | collection_name = settings.params.records;
719 |
720 | if (recordsShown < recordsQueryCount && settings.features.paginate) {
721 | var bounds = obj.records.pageBounds();
722 | text += "" + (bounds[0] + 1) + " to " + bounds[1] + " of ";
723 | } else if (recordsShown === recordsQueryCount && settings.features.paginate) {
724 | text += recordsShown + " of ";
725 | }
726 | text += recordsQueryCount + " " + collection_name;
727 | if (recordsQueryCount < recordsTotal) {
728 | text += " (filtered from " + recordsTotal + " total records)";
729 | }
730 |
731 | return $('', {
732 | id: 'dynatable-record-count-' + obj.element.id,
733 | 'class': 'dynatable-record-count',
734 | html: text
735 | });
736 | };
737 |
738 | this.attach = function() {
739 | var $target = settings.inputs.recordCountTarget ? $(settings.inputs.recordCountTarget) : obj.$element;
740 | $target[settings.inputs.recordCountPlacement](this.create());
741 | };
742 | };
743 |
744 | function ProcessingIndicator(obj, settings) {
745 | this.init = function() {
746 | this.attach();
747 | };
748 |
749 | this.create = function() {
750 | var $processing = $('', {
751 | html: '' + settings.inputs.processingText + '',
752 | id: 'dynatable-processing-' + obj.element.id,
753 | 'class': 'dynatable-processing',
754 | style: 'position: absolute; display: none;'
755 | });
756 |
757 | return $processing;
758 | };
759 |
760 | this.position = function() {
761 | var $processing = $('#dynatable-processing-' + obj.element.id),
762 | $span = $processing.children('span'),
763 | spanHeight = $span.outerHeight(),
764 | spanWidth = $span.outerWidth(),
765 | $covered = obj.$element,
766 | offset = $covered.offset(),
767 | height = $covered.outerHeight(), width = $covered.outerWidth();
768 |
769 | $processing
770 | .offset({left: offset.left, top: offset.top})
771 | .width(width)
772 | .height(height)
773 | $span
774 | .offset({left: offset.left + ( (width - spanWidth) / 2 ), top: offset.top + ( (height - spanHeight) / 2 )});
775 |
776 | return $processing;
777 | };
778 |
779 | this.attach = function() {
780 | obj.$element.before(this.create());
781 | };
782 |
783 | this.show = function() {
784 | $('#dynatable-processing-' + obj.element.id).show();
785 | this.position();
786 | };
787 |
788 | this.hide = function() {
789 | $('#dynatable-processing-' + obj.element.id).hide();
790 | };
791 | };
792 |
793 | function State(obj, settings) {
794 | this.initOnLoad = function() {
795 | // Check if pushState option is true, and if browser supports it
796 | return settings.features.pushState && history.pushState;
797 | };
798 |
799 | this.init = function() {
800 | window.onpopstate = function(event) {
801 | if (event.state && event.state.dynatable) {
802 | obj.state.pop(event);
803 | }
804 | }
805 | };
806 |
807 | this.push = function(data) {
808 | var urlString = window.location.search,
809 | urlOptions,
810 | path,
811 | params,
812 | hash,
813 | newParams,
814 | cacheStr,
815 | cache,
816 | // replaceState on initial load, then pushState after that
817 | firstPush = !(window.history.state && window.history.state.dynatable),
818 | pushFunction = firstPush ? 'replaceState' : 'pushState';
819 |
820 | if (urlString && /^\?/.test(urlString)) { urlString = urlString.substring(1); }
821 | $.extend(urlOptions, data);
822 |
823 | params = utility.refreshQueryString(urlString, data, settings);
824 | if (params) { params = '?' + params; }
825 | hash = window.location.hash;
826 | path = window.location.pathname;
827 |
828 | obj.$element.trigger('dynatable:push', data);
829 |
830 | cache = { dynatable: { dataset: settings.dataset } };
831 | if (!firstPush) { cache.dynatable.scrollTop = $(window).scrollTop(); }
832 | cacheStr = JSON.stringify(cache);
833 |
834 | // Mozilla has a 640k char limit on what can be stored in pushState.
835 | // See "limit" in https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history#The_pushState().C2.A0method
836 | // and "dataStr.length" in http://wine.git.sourceforge.net/git/gitweb.cgi?p=wine/wine-gecko;a=patch;h=43a11bdddc5fc1ff102278a120be66a7b90afe28
837 | //
838 | // Likewise, other browsers may have varying (undocumented) limits.
839 | // Also, Firefox's limit can be changed in about:config as browser.history.maxStateObjectSize
840 | // Since we don't know what the actual limit will be in any given situation, we'll just try caching and rescue
841 | // any exceptions by retrying pushState without caching the records.
842 | //
843 | // I have absolutely no idea why perPageOptions suddenly becomes an array-like object instead of an array,
844 | // but just recently, this started throwing an error if I don't convert it:
845 | // 'Uncaught Error: DATA_CLONE_ERR: DOM Exception 25'
846 | cache.dynatable.dataset.perPageOptions = $.makeArray(cache.dynatable.dataset.perPageOptions);
847 |
848 | try {
849 | window.history[pushFunction](cache, "Dynatable state", path + params + hash);
850 | } catch(error) {
851 | // Make cached records = null, so that `pop` will rerun process to retrieve records
852 | cache.dynatable.dataset.records = null;
853 | window.history[pushFunction](cache, "Dynatable state", path + params + hash);
854 | }
855 | };
856 |
857 | this.pop = function(event) {
858 | var data = event.state.dynatable;
859 | settings.dataset = data.dataset;
860 |
861 | if (data.scrollTop) { $(window).scrollTop(data.scrollTop); }
862 |
863 | // If dataset.records is cached from pushState
864 | if ( data.dataset.records ) {
865 | obj.dom.update();
866 | } else {
867 | obj.process(true);
868 | }
869 | };
870 | };
871 |
872 | function Sorts(obj, settings) {
873 | this.initOnLoad = function() {
874 | return settings.features.sort;
875 | };
876 |
877 | this.init = function() {
878 | var sortsUrl = window.location.search.match(new RegExp(settings.params.sorts + '[^&=]*=[^&]*', 'g'));
879 | settings.dataset.sorts = sortsUrl ? utility.deserialize(sortsUrl)[settings.params.sorts] : {};
880 | settings.dataset.sortsKeys = sortsUrl ? utility.keysFromObject(settings.dataset.sorts) : [];
881 | };
882 |
883 | this.add = function(attr, direction) {
884 | var sortsKeys = settings.dataset.sortsKeys,
885 | index = $.inArray(attr, sortsKeys);
886 | settings.dataset.sorts[attr] = direction;
887 | if (index === -1) { sortsKeys.push(attr); }
888 | return dt;
889 | };
890 |
891 | this.remove = function(attr) {
892 | var sortsKeys = settings.dataset.sortsKeys,
893 | index = $.inArray(attr, sortsKeys);
894 | delete settings.dataset.sorts[attr];
895 | if (index !== -1) { sortsKeys.splice(index, 1); }
896 | return dt;
897 | };
898 |
899 | this.clear = function() {
900 | settings.dataset.sorts = {};
901 | settings.dataset.sortsKeys.length = 0;
902 | };
903 |
904 | // Try to intelligently guess which sort function to use
905 | // based on the type of attribute values.
906 | // Consider using something more robust than `typeof` (http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/)
907 | this.guessType = function(a, b, attr) {
908 | var types = {
909 | string: 'string',
910 | number: 'number',
911 | 'boolean': 'number',
912 | object: 'number' // dates and null values are also objects, this works...
913 | },
914 | attrType = a[attr] ? typeof(a[attr]) : typeof(b[attr]),
915 | type = types[attrType] || 'number';
916 | return type;
917 | };
918 |
919 | // Built-in sort functions
920 | // (the most common use-cases I could think of)
921 | this.functions = {
922 | number: function(a, b, attr, direction) {
923 | return a[attr] === b[attr] ? 0 : (direction > 0 ? a[attr] - b[attr] : b[attr] - a[attr]);
924 | },
925 | string: function(a, b, attr, direction) {
926 | var aAttr = (a['dynatable-sortable-text'] && a['dynatable-sortable-text'][attr]) ? a['dynatable-sortable-text'][attr] : a[attr],
927 | bAttr = (b['dynatable-sortable-text'] && b['dynatable-sortable-text'][attr]) ? b['dynatable-sortable-text'][attr] : b[attr],
928 | comparison;
929 | aAttr = aAttr.toLowerCase();
930 | bAttr = bAttr.toLowerCase();
931 | comparison = aAttr === bAttr ? 0 : (direction > 0 ? aAttr > bAttr : bAttr > aAttr);
932 | // force false boolean value to -1, true to 1, and tie to 0
933 | return comparison === false ? -1 : (comparison - 0);
934 | },
935 | originalPlacement: function(a, b) {
936 | return a['dynatable-original-index'] - b['dynatable-original-index'];
937 | }
938 | };
939 | };
940 |
941 | // turn table headers into links which add sort to sorts array
942 | function SortsHeaders(obj, settings) {
943 | var _this = this;
944 |
945 | this.initOnLoad = function() {
946 | return settings.features.sort;
947 | };
948 |
949 | this.init = function() {
950 | this.attach();
951 | };
952 |
953 | this.create = function(cell) {
954 | var $cell = $(cell),
955 | $link = $('', {
956 | 'class': 'dynatable-sort-header',
957 | href: '#',
958 | html: $cell.html()
959 | }),
960 | id = $cell.data('dynatable-column'),
961 | column = utility.findObjectInArray(settings.table.columns, {id: id});
962 |
963 | $link.bind('click', function(e) {
964 | _this.toggleSort(e, $link, column);
965 | obj.process();
966 |
967 | e.preventDefault();
968 | });
969 |
970 | if (this.sortedByColumn($link, column)) {
971 | if (this.sortedByColumnValue(column) == 1) {
972 | this.appendArrowUp($link);
973 | } else {
974 | this.appendArrowDown($link);
975 | }
976 | }
977 |
978 | return $link;
979 | };
980 |
981 | this.removeAll = function() {
982 | obj.$element.find(settings.table.headRowSelector).children('th,td').each(function(){
983 | _this.removeAllArrows();
984 | _this.removeOne(this);
985 | });
986 | };
987 |
988 | this.removeOne = function(cell) {
989 | var $cell = $(cell),
990 | $link = $cell.find('.dynatable-sort-header');
991 | if ($link.length) {
992 | var html = $link.html();
993 | $link.remove();
994 | $cell.html($cell.html() + html);
995 | }
996 | };
997 |
998 | this.attach = function() {
999 | obj.$element.find(settings.table.headRowSelector).children('th,td').each(function(){
1000 | _this.attachOne(this);
1001 | });
1002 | };
1003 |
1004 | this.attachOne = function(cell) {
1005 | var $cell = $(cell);
1006 | if (!$cell.data('dynatable-no-sort')) {
1007 | $cell.html(this.create(cell));
1008 | }
1009 | };
1010 |
1011 | this.appendArrowUp = function($link) {
1012 | this.removeArrow($link);
1013 | $link.append(" ▲");
1014 | };
1015 |
1016 | this.appendArrowDown = function($link) {
1017 | this.removeArrow($link);
1018 | $link.append(" ▼");
1019 | };
1020 |
1021 | this.removeArrow = function($link) {
1022 | // Not sure why `parent()` is needed, the arrow should be inside the link from `append()` above
1023 | $link.find('.dynatable-arrow').remove();
1024 | };
1025 |
1026 | this.removeAllArrows = function() {
1027 | obj.$element.find('.dynatable-arrow').remove();
1028 | };
1029 |
1030 | this.toggleSort = function(e, $link, column) {
1031 | var sortedByColumn = this.sortedByColumn($link, column),
1032 | value = this.sortedByColumnValue(column);
1033 | // Clear existing sorts unless this is a multisort event
1034 | if (!settings.inputs.multisort || !utility.anyMatch(e, settings.inputs.multisort, function(evt, key) { return e[key]; })) {
1035 | this.removeAllArrows();
1036 | obj.sorts.clear();
1037 | }
1038 |
1039 | // If sorts for this column are already set
1040 | if (sortedByColumn) {
1041 | // If ascending, then make descending
1042 | if (value == 1) {
1043 | for (var i = 0, len = column.sorts.length; i < len; i++) {
1044 | obj.sorts.add(column.sorts[i], -1);
1045 | }
1046 | this.appendArrowDown($link);
1047 | // If descending, remove sort
1048 | } else {
1049 | for (var i = 0, len = column.sorts.length; i < len; i++) {
1050 | obj.sorts.remove(column.sorts[i]);
1051 | }
1052 | this.removeArrow($link);
1053 | }
1054 | // Otherwise, if not already set, set to ascending
1055 | } else {
1056 | for (var i = 0, len = column.sorts.length; i < len; i++) {
1057 | obj.sorts.add(column.sorts[i], 1);
1058 | }
1059 | this.appendArrowUp($link);
1060 | }
1061 | };
1062 |
1063 | this.sortedByColumn = function($link, column) {
1064 | return utility.allMatch(settings.dataset.sorts, column.sorts, function(sorts, sort) { return sort in sorts; });
1065 | };
1066 |
1067 | this.sortedByColumnValue = function(column) {
1068 | return settings.dataset.sorts[column.sorts[0]];
1069 | };
1070 | };
1071 |
1072 | function Queries(obj, settings) {
1073 | var _this = this;
1074 |
1075 | this.initOnLoad = function() {
1076 | return settings.inputs.queries || settings.features.search;
1077 | };
1078 |
1079 | this.init = function() {
1080 | var queriesUrl = window.location.search.match(new RegExp(settings.params.queries + '[^&=]*=[^&]*', 'g'));
1081 |
1082 | settings.dataset.queries = queriesUrl ? utility.deserialize(queriesUrl)[settings.params.queries] : {};
1083 | if (settings.dataset.queries === "") { settings.dataset.queries = {}; }
1084 |
1085 | if (settings.inputs.queries) {
1086 | this.setupInputs();
1087 | }
1088 | };
1089 |
1090 | this.add = function(name, value) {
1091 | // reset to first page since query will change records
1092 | if (settings.features.paginate) {
1093 | settings.dataset.page = 1;
1094 | }
1095 | settings.dataset.queries[name] = value;
1096 | return dt;
1097 | };
1098 |
1099 | this.remove = function(name) {
1100 | delete settings.dataset.queries[name];
1101 | return dt;
1102 | };
1103 |
1104 | this.run = function() {
1105 | for (query in settings.dataset.queries) {
1106 | if (settings.dataset.queries.hasOwnProperty(query)) {
1107 | var value = settings.dataset.queries[query];
1108 | if (_this.functions[query] === undefined) {
1109 | // Try to lazily evaluate query from column names if not explicitly defined
1110 | var queryColumn = utility.findObjectInArray(settings.table.columns, {id: query});
1111 | if (queryColumn) {
1112 | _this.functions[query] = function(record, queryValue) {
1113 | return record[query] == queryValue;
1114 | };
1115 | } else {
1116 | $.error("Query named '" + query + "' called, but not defined in queries.functions");
1117 | continue; // to skip to next query
1118 | }
1119 | }
1120 | // collect all records that return true for query
1121 | settings.dataset.records = $.map(settings.dataset.records, function(record) {
1122 | return _this.functions[query](record, value) ? record : null;
1123 | });
1124 | }
1125 | }
1126 | settings.dataset.queryRecordCount = obj.records.count();
1127 | };
1128 |
1129 | // Shortcut for performing simple query from built-in search
1130 | this.runSearch = function(q) {
1131 | var origQueries = $.extend({}, settings.dataset.queries);
1132 | if (q) {
1133 | this.add('search', q);
1134 | } else {
1135 | this.remove('search');
1136 | }
1137 | if (!utility.objectsEqual(settings.dataset.queries, origQueries)) {
1138 | obj.process();
1139 | }
1140 | };
1141 |
1142 | this.setupInputs = function() {
1143 | settings.inputs.queries.each(function() {
1144 | var $this = $(this),
1145 | event = $this.data('dynatable-query-event') || settings.inputs.queryEvent,
1146 | query = $this.data('dynatable-query') || $this.attr('name') || this.id,
1147 | queryFunction = function(e) {
1148 | var q = $(this).val();
1149 | if (q === "") { q = undefined; }
1150 | if (q === settings.dataset.queries[query]) { return false; }
1151 | if (q) {
1152 | _this.add(query, q);
1153 | } else {
1154 | _this.remove(query);
1155 | }
1156 | obj.process();
1157 | e.preventDefault();
1158 | };
1159 |
1160 | $this
1161 | .attr('data-dynatable-query', query)
1162 | .bind(event, queryFunction)
1163 | .bind('keypress', function(e) {
1164 | if (e.which == 13) {
1165 | queryFunction.call(this, e);
1166 | }
1167 | });
1168 |
1169 | if (settings.dataset.queries[query]) { $this.val(decodeURIComponent(settings.dataset.queries[query])); }
1170 | });
1171 | };
1172 |
1173 | // Query functions for in-page querying
1174 | // each function should take a record and a value as input
1175 | // and output true of false as to whether the record is a match or not
1176 | this.functions = {
1177 | search: function(record, queryValue) {
1178 | var queryValues = queryValue.split(';');
1179 | // Loop through each attribute of record
1180 | for (var index = 0; index < queryValues.length; index++) {
1181 | var matches = false;
1182 | for (attr in record) {
1183 | if (record.hasOwnProperty(attr)) {
1184 | var attrValue = record[attr];
1185 | var query = queryValues[index];
1186 | if (typeof attrValue === 'string') {
1187 | if (attrValue.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
1188 | matches = true;
1189 | break;
1190 | }
1191 | } else if (typeof attrValue === 'number') {
1192 | if (attrValue == Number(query)) {
1193 | matches = true;
1194 | break;
1195 | }
1196 | }
1197 | }
1198 | }
1199 | if (!matches) return false;
1200 | }
1201 | return true;
1202 | }
1203 | };
1204 | };
1205 |
1206 | function InputsSearch(obj, settings) {
1207 | var _this = this;
1208 |
1209 | this.initOnLoad = function() {
1210 | return settings.features.search;
1211 | };
1212 |
1213 | this.init = function() {
1214 | this.attach();
1215 | };
1216 |
1217 | this.create = function() {
1218 | var $search = $('', {
1219 | type: 'search',
1220 | id: 'dynatable-query-search-' + obj.element.id,
1221 | 'data-dynatable-query': 'search',
1222 | value: settings.dataset.queries.search
1223 | }),
1224 | $searchSpan = $('', {
1225 | id: 'dynatable-search-' + obj.element.id,
1226 | 'class': 'dynatable-search',
1227 | text: 'Search: '
1228 | }).append($search);
1229 |
1230 | $search
1231 | .bind(settings.inputs.queryEvent, function() {
1232 | obj.queries.runSearch($(this).val());
1233 | })
1234 | .bind('keypress', function(e) {
1235 | if (e.which == 13) {
1236 | obj.queries.runSearch($(this).val());
1237 | e.preventDefault();
1238 | }
1239 | });
1240 | return $searchSpan;
1241 | };
1242 |
1243 | this.attach = function() {
1244 | var $target = settings.inputs.searchTarget ? $(settings.inputs.searchTarget) : obj.$element;
1245 | $target[settings.inputs.searchPlacement](this.create());
1246 | };
1247 | };
1248 |
1249 | // provide a public function for selecting page
1250 | function PaginationPage(obj, settings) {
1251 | this.initOnLoad = function() {
1252 | return settings.features.paginate;
1253 | };
1254 |
1255 | this.init = function() {
1256 | var pageUrl = window.location.search.match(new RegExp(settings.params.page + '=([^&]*)'));
1257 | // If page is present in URL parameters and pushState is enabled
1258 | // (meaning that it'd be possible for dynatable to have put the
1259 | // page parameter in the URL)
1260 | if (pageUrl && settings.features.pushState) {
1261 | this.set(pageUrl[1]);
1262 | } else {
1263 | this.set(1);
1264 | }
1265 | };
1266 |
1267 | this.set = function(page) {
1268 | settings.dataset.page = parseInt(page, 10);
1269 | }
1270 | };
1271 |
1272 | function PaginationPerPage(obj, settings) {
1273 | var _this = this;
1274 |
1275 | this.initOnLoad = function() {
1276 | return settings.features.paginate;
1277 | };
1278 |
1279 | this.init = function() {
1280 | var perPageUrl = window.location.search.match(new RegExp(settings.params.perPage + '=([^&]*)'));
1281 |
1282 | // If perPage is present in URL parameters and pushState is enabled
1283 | // (meaning that it'd be possible for dynatable to have put the
1284 | // perPage parameter in the URL)
1285 | if (perPageUrl && settings.features.pushState) {
1286 | // Don't reset page to 1 on init, since it might override page
1287 | // set on init from URL
1288 | this.set(perPageUrl[1], true);
1289 | } else {
1290 | this.set(settings.dataset.perPageDefault, true);
1291 | }
1292 |
1293 | if (settings.features.perPageSelect) {
1294 | this.attach();
1295 | }
1296 | };
1297 |
1298 | this.create = function() {
1299 | var $select = $('