├── .gitignore
├── .npmignore
├── .travis.yml
├── .vs
├── ProjectSettings.json
├── VSWorkspaceState.json
├── config
│ └── applicationhost.config
├── ng4-gridstack
│ └── v15
│ │ └── .suo
└── slnx.sqlite
├── .yo-rc.json
├── LICENSE
├── README.md
├── gulpfile.js
├── package-lock.json
├── package.json
├── src
├── grid-stack-item.component.ts
├── grid-stack-item.model.ts
├── grid-stack-options.model.ts
├── grid-stack.component.spec.ts
├── grid-stack.component.ts
├── grid-stack.directive.ts
├── grid-stack.pipe.ts
├── grid-stack.service.ts
├── index.ts
├── package.json
├── tsconfig.es5.json
└── tsconfig.spec.json
├── tools
└── gulp
│ └── inline-resources.js
├── tsconfig.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 |
5 | # TypeScript
6 | src/*.js
7 | src/*.map
8 | src/*.d.ts
9 |
10 | # JetBrains
11 | .idea
12 | .project
13 | .settings
14 | .idea/*
15 | *.iml
16 |
17 | # VS Code
18 | .vscode/*
19 |
20 | # Windows
21 | Thumbs.db
22 | Desktop.ini
23 |
24 | # Mac
25 | .DS_Store
26 | **/.DS_Store
27 |
28 | # Ngc generated files
29 | **/*.ngfactory.ts
30 |
31 | # Build files
32 | dist/*
33 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 | docs/*
5 | # DO NOT IGNORE TYPESCRIPT FILES FOR NPM
6 | # TypeScript
7 | # *.js
8 | # *.map
9 | # *.d.ts
10 |
11 | # JetBrains
12 | .idea
13 | .project
14 | .settings
15 | .idea/*
16 | *.iml
17 |
18 | # VS Code
19 | .vscode/*
20 |
21 | # Windows
22 | Thumbs.db
23 | Desktop.ini
24 |
25 | # Mac
26 | .DS_Store
27 | **/.DS_Store
28 |
29 | # Ngc generated files
30 | **/*.ngfactory.ts
31 |
32 | # Library files
33 | build/*
34 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - '4.2.1'
5 |
--------------------------------------------------------------------------------
/.vs/ProjectSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "CurrentProjectSetting": null
3 | }
--------------------------------------------------------------------------------
/.vs/VSWorkspaceState.json:
--------------------------------------------------------------------------------
1 | {
2 | "ExpandedNodes": [
3 | "",
4 | "\\src"
5 | ],
6 | "SelectedNode": "\\src\\grid-stack.component.ts",
7 | "PreviewInSolutionExplorer": false
8 | }
--------------------------------------------------------------------------------
/.vs/config/applicationhost.config:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
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 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
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 |
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 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
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 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
--------------------------------------------------------------------------------
/.vs/ng4-gridstack/v15/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ramyothman/ng4-gridstack/c6c83a49f8b279bab3066a570e38a8e322b5e98b/.vs/ng4-gridstack/v15/.suo
--------------------------------------------------------------------------------
/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ramyothman/ng4-gridstack/c6c83a49f8b279bab3066a570e38a8e322b5e98b/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-angular2-library": {
3 | "promptValues": {
4 | "gitRepositoryUrl": "https://github.com/ramyothman/ng4-gridstack"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ramy Othman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ng4-gridstack
2 |
3 | ## Installation
4 |
5 | To install this library, run:
6 |
7 | ```bash
8 | $ npm install ng4-gridstack --save
9 | ```
10 |
11 | ## Consuming your library
12 |
13 | Once you have published your library to npm, you can import your library in any Angular application by running:
14 |
15 | ```bash
16 | $ npm install ng4-gridstack
17 | ```
18 |
19 | Then add reference to the gridstask.js and lodash to your index.html for how to do it check their site at
20 | - https://github.com/gridstack/gridstack.js
21 |
22 | and then from your Angular `AppModule`:
23 |
24 | ```typescript
25 | import { BrowserModule } from '@angular/platform-browser';
26 | import { NgModule } from '@angular/core';
27 |
28 | import { AppComponent } from './app.component';
29 |
30 | // Import your library
31 | import { GridStackModule } from 'ng4-gridstack';
32 |
33 | @NgModule({
34 | declarations: [
35 | AppComponent
36 | ],
37 | imports: [
38 | BrowserModule,
39 |
40 | // Specify your library as an import
41 | GridStackModule
42 | ],
43 | providers: [],
44 | bootstrap: [AppComponent]
45 | })
46 | export class AppModule { }
47 | ```
48 |
49 | Once your library is imported, you can use its components, directives and pipes in your Angular application:
50 |
51 | ```xml
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | If you want to dynamically generate widgets:
62 |
63 | ```xml
64 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
74 |
75 |
76 | ```
77 | ```typescript
78 | import { Component, OnInit, ViewChildren, QueryList, ViewChild, ChangeDetectorRef } from '@angular/core';
79 | import { GridStackItem, GridStackOptions, GridStackItemComponent, GridStackComponent} from 'ng4-gridstack'
80 |
81 | @Component({
82 | selector: 'app-grid-stack',
83 | templateUrl: './app-grid-stack.component.html'
84 | })
85 | export class DashboardComponent implements OnInit {
86 | @ViewChildren(GridStackItemComponent) items: QueryList;
87 | @ViewChild('gridStackMain') gridStackMain: GridStackComponent;
88 | area: GridStackOptions = new GridStackOptions();
89 | widgets: GridStackItem[] = [];
90 |
91 | constructor(private cd: ChangeDetectorRef) {
92 |
93 | }
94 |
95 | AddWidget(widgetType: DashboardWidgetTypeEnum) {
96 | var widget = new GridStackItem();
97 |
98 | widget.width = 6;
99 | widget.height = 4;
100 | widget.x = 0;
101 | widget.y = 0;
102 | this.widgets.push(widget);
103 | this.cd.detectChanges();
104 | var arr = this.items.toArray();
105 | this.gridStackMain.AddWidget(arr[this.items.length - 1]);
106 | }
107 | }
108 | ```
109 |
110 | ## Development
111 |
112 | To generate all `*.js`, `*.d.ts` and `*.metadata.json` files:
113 |
114 | ```bash
115 | $ npm run build
116 | ```
117 |
118 | To lint all `*.ts` files:
119 |
120 | ```bash
121 | $ npm run lint
122 | ```
123 | ## Credit
124 |
125 | I was looking for integrating cleanly the amazing gridstack.js (https://github.com/gridstack/gridstack.js) library with angular 4 and found this thread on stack overflow
126 | https://stackoverflow.com/questions/39901473/wrap-gridstack-js-into-angular-2-component
127 | Credit Goes to Answers from those users
128 | https://stackoverflow.com/users/3758236/user3758236
129 | https://stackoverflow.com/users/3112339/etchelon
130 |
131 | ## License
132 |
133 | MIT © [Ramy Othman](mailto:ramy.mostafa@gmail.com)
134 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var gulp = require('gulp'),
3 | path = require('path'),
4 | ngc = require('@angular/compiler-cli/src/main').main,
5 | rollup = require('gulp-rollup'),
6 | rename = require('gulp-rename'),
7 | del = require('del'),
8 | runSequence = require('run-sequence'),
9 | inlineResources = require('./tools/gulp/inline-resources');
10 |
11 | const rootFolder = path.join(__dirname);
12 | const srcFolder = path.join(rootFolder, 'src');
13 | const tmpFolder = path.join(rootFolder, '.tmp');
14 | const buildFolder = path.join(rootFolder, 'build');
15 | const distFolder = path.join(rootFolder, 'dist');
16 |
17 | /**
18 | * 1. Delete /dist folder
19 | */
20 | gulp.task('clean:dist', function () {
21 |
22 | // Delete contents but not dist folder to avoid broken npm links
23 | // when dist directory is removed while npm link references it.
24 | return deleteFolders([distFolder + '/**', '!' + distFolder]);
25 | });
26 |
27 | /**
28 | * 2. Clone the /src folder into /.tmp. If an npm link inside /src has been made,
29 | * then it's likely that a node_modules folder exists. Ignore this folder
30 | * when copying to /.tmp.
31 | */
32 | gulp.task('copy:source', function () {
33 | return gulp.src([`${srcFolder}/**/*`, `!${srcFolder}/node_modules`])
34 | .pipe(gulp.dest(tmpFolder));
35 | });
36 |
37 | /**
38 | * 3. Inline template (.html) and style (.css) files into the the component .ts files.
39 | * We do this on the /.tmp folder to avoid editing the original /src files
40 | */
41 | gulp.task('inline-resources', function () {
42 | return Promise.resolve()
43 | .then(() => inlineResources(tmpFolder));
44 | });
45 |
46 |
47 | /**
48 | * 4. Run the Angular compiler, ngc, on the /.tmp folder. This will output all
49 | * compiled modules to the /build folder.
50 | */
51 | gulp.task('ngc', function () {
52 | return ngc({
53 | project: `${tmpFolder}/tsconfig.es5.json`
54 | })
55 | .then((exitCode) => {
56 | if (exitCode === 1) {
57 | // This error is caught in the 'compile' task by the runSequence method callback
58 | // so that when ngc fails to compile, the whole compile process stops running
59 | throw new Error('ngc compilation failed');
60 | }
61 | });
62 | });
63 |
64 | /**
65 | * 5. Run rollup inside the /build folder to generate our Flat ES module and place the
66 | * generated file into the /dist folder
67 | */
68 | gulp.task('rollup:fesm', function () {
69 | return gulp.src(`${buildFolder}/**/*.js`)
70 | // transform the files here.
71 | .pipe(rollup({
72 |
73 | // Bundle's entry point
74 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#entry
75 | entry: `${buildFolder}/index.js`,
76 |
77 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
78 | // accessed by Rollup or produced by plugins further down the chain.
79 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
80 | // when subdirectories are used in the `src` directory.
81 | allowRealFiles: true,
82 |
83 | // A list of IDs of modules that should remain external to the bundle
84 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#external
85 | external: [
86 | '@angular/core',
87 | '@angular/common'
88 | ],
89 |
90 | // Format of generated bundle
91 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#format
92 | format: 'es'
93 | }))
94 | .pipe(gulp.dest(distFolder));
95 | });
96 |
97 | /**
98 | * 6. Run rollup inside the /build folder to generate our UMD module and place the
99 | * generated file into the /dist folder
100 | */
101 | gulp.task('rollup:umd', function () {
102 | return gulp.src(`${buildFolder}/**/*.js`)
103 | // transform the files here.
104 | .pipe(rollup({
105 |
106 | // Bundle's entry point
107 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#entry
108 | entry: `${buildFolder}/index.js`,
109 |
110 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
111 | // accessed by Rollup or produced by plugins further down the chain.
112 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
113 | // when subdirectories are used in the `src` directory.
114 | allowRealFiles: true,
115 |
116 | // A list of IDs of modules that should remain external to the bundle
117 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#external
118 | external: [
119 | '@angular/core',
120 | '@angular/common'
121 | ],
122 |
123 | // Format of generated bundle
124 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#format
125 | format: 'umd',
126 |
127 | // Export mode to use
128 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#exports
129 | exports: 'named',
130 |
131 | // The name to use for the module for UMD/IIFE bundles
132 | // (required for bundles with exports)
133 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#modulename
134 | moduleName: 'ng4-gridstackstack',
135 |
136 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#globals
137 | globals: {
138 | typescript: 'ts'
139 | }
140 |
141 | }))
142 | .pipe(rename('ng4-gridstackstack.umd.js'))
143 | .pipe(gulp.dest(distFolder));
144 | });
145 |
146 | /**
147 | * 7. Copy all the files from /build to /dist, except .js files. We ignore all .js from /build
148 | * because with don't need individual modules anymore, just the Flat ES module generated
149 | * on step 5.
150 | */
151 | gulp.task('copy:build', function () {
152 | return gulp.src([`${buildFolder}/**/*`, `!${buildFolder}/**/*.js`])
153 | .pipe(gulp.dest(distFolder));
154 | });
155 |
156 | /**
157 | * 8. Copy package.json from /src to /dist
158 | */
159 | gulp.task('copy:manifest', function () {
160 | return gulp.src([`${srcFolder}/package.json`])
161 | .pipe(gulp.dest(distFolder));
162 | });
163 |
164 | /**
165 | * 9. Copy README.md from / to /dist
166 | */
167 | gulp.task('copy:readme', function () {
168 | return gulp.src([path.join(rootFolder, 'README.MD')])
169 | .pipe(gulp.dest(distFolder));
170 | });
171 |
172 | /**
173 | * 10. Delete /.tmp folder
174 | */
175 | gulp.task('clean:tmp', function () {
176 | return deleteFolders([tmpFolder]);
177 | });
178 |
179 | /**
180 | * 11. Delete /build folder
181 | */
182 | gulp.task('clean:build', function () {
183 | return deleteFolders([buildFolder]);
184 | });
185 |
186 | gulp.task('compile', function () {
187 | runSequence(
188 | 'clean:dist',
189 | 'copy:source',
190 | 'inline-resources',
191 | 'ngc',
192 | 'rollup:fesm',
193 | 'rollup:umd',
194 | 'copy:build',
195 | 'copy:manifest',
196 | 'copy:readme',
197 | 'clean:build',
198 | 'clean:tmp',
199 | function (err) {
200 | if (err) {
201 | console.log('ERROR:', err.message);
202 | deleteFolders([distFolder, tmpFolder, buildFolder]);
203 | } else {
204 | console.log('Compilation finished succesfully');
205 | }
206 | });
207 | });
208 |
209 | /**
210 | * Watch for any change in the /src folder and compile files
211 | */
212 | gulp.task('watch', function () {
213 | gulp.watch(`${srcFolder}/**/*`, ['compile']);
214 | });
215 |
216 | gulp.task('clean', ['clean:dist', 'clean:tmp', 'clean:build']);
217 |
218 | gulp.task('build', ['clean', 'compile']);
219 | gulp.task('build:watch', ['build', 'watch']);
220 | gulp.task('default', ['build:watch']);
221 |
222 | /**
223 | * Deletes the specified folder
224 | */
225 | function deleteFolders(folders) {
226 | return del(folders);
227 | }
228 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng4-gridstack",
3 | "version": "0.3.40",
4 | "scripts": {
5 | "build": "gulp build",
6 | "build:watch": "gulp",
7 | "docs": "npm run docs:build",
8 | "docs:build": "compodoc -p tsconfig.json -n ng4-gridstack -d docs --hideGenerator",
9 | "docs:serve": "npm run docs:build -- -s",
10 | "docs:watch": "npm run docs:build -- -s -w",
11 | "lint": "tslint --type-check --project tsconfig.json src/**/*.ts",
12 | "test": "tsc && karma start"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/ramyothman/ng4-gridstack"
17 | },
18 | "author": {
19 | "name": "Ramy Othman",
20 | "email": "ramy.mostafa@gmail.com"
21 | },
22 | "keywords": [
23 | "angular"
24 | ],
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/ramyothman/ng4-gridstack/issues"
28 | },
29 | "devDependencies": {
30 | "@angular/common": "^4.0.0",
31 | "@angular/compiler": "^4.0.0",
32 | "@angular/compiler-cli": "^4.0.0",
33 | "@angular/core": "^4.0.0",
34 | "@angular/platform-browser": "^4.0.0",
35 | "@angular/platform-browser-dynamic": "^4.0.0",
36 | "@compodoc/compodoc": "^1.0.0-beta.10",
37 | "@types/jasmine": "2.5.38",
38 | "@types/node": "~6.0.60",
39 | "codelyzer": "~2.0.0",
40 | "core-js": "^2.4.1",
41 | "del": "^2.2.2",
42 | "gulp": "^3.9.1",
43 | "gulp-rename": "^1.2.2",
44 | "gulp-rollup": "^2.11.0",
45 | "jasmine-core": "~2.5.2",
46 | "jasmine-spec-reporter": "~3.2.0",
47 | "karma": "~1.4.1",
48 | "karma-chrome-launcher": "~2.0.0",
49 | "karma-cli": "~1.0.1",
50 | "karma-coverage-istanbul-reporter": "^0.2.0",
51 | "karma-jasmine": "~1.1.0",
52 | "karma-jasmine-html-reporter": "^0.2.2",
53 | "node-sass": "^4.5.2",
54 | "node-sass-tilde-importer": "^1.0.0",
55 | "node-watch": "^0.5.2",
56 | "protractor": "~5.1.0",
57 | "rollup": "^0.41.6",
58 | "run-sequence": "^1.2.2",
59 | "rxjs": "^5.1.0",
60 | "ts-node": "~2.0.0",
61 | "tslint": "~4.5.0",
62 | "typescript": "~2.2.0",
63 | "zone.js": "^0.8.4"
64 | },
65 | "engines": {
66 | "node": ">=6.0.0"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/grid-stack-item.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, HostBinding, Input, Output, OnInit, ComponentRef, ElementRef, ViewChild, Renderer, EventEmitter, OnDestroy, AfterViewInit, ViewContainerRef } from '@angular/core';
2 | import { GridStackItem } from './grid-stack-item.model'
3 | declare var jQuery: any;
4 | declare var _: any;
5 |
6 | @Component({
7 | selector: 'grid-stack-item',
8 | template: ``
12 | })
13 | export class GridStackItemComponent implements OnInit, OnDestroy, AfterViewInit {
14 | @ViewChild("contentPlaceholder", { read: ViewContainerRef }) contentPlaceholder: ViewContainerRef;
15 | @Input() contentTemplate: string;
16 | @Input() option: GridStackItem;
17 | @Output() onGridConfigurationChanged = new EventEmitter();
18 |
19 | contentComponentRef: ComponentRef = null;
20 | jGridRef: any = null;
21 | public jWidgetRef: any = null;
22 |
23 | constructor(private el: ElementRef, private renderer: Renderer) {
24 | this.jWidgetRef = el.nativeElement;
25 | }
26 | get nativeElement(): HTMLElement {
27 | return this.el.nativeElement;
28 | }
29 | ngOnInit() {
30 | this.RenderWidget(null);
31 | }
32 |
33 | UpdateWidget(item: GridStackItem) {
34 |
35 | }
36 | RenderWidget(item: GridStackItem) {
37 | let renderer = this.renderer;
38 | if (item != null)
39 | this.option = item;
40 |
41 | this.renderer.setElementAttribute(this.nativeElement, "style", "margin-left:" + this.option.marginWidth + ";");
42 | this.renderer.setElementAttribute(this.nativeElement, "data-gs-x", String(this.option.x));
43 | this.renderer.setElementAttribute(this.nativeElement, "data-gs-y", String(this.option.y));
44 | this.renderer.setElementAttribute(this.nativeElement, "data-gs-width", String(this.option.width));
45 | this.renderer.setElementAttribute(this.nativeElement, "data-gs-height", String(this.option.height));
46 | if (this.option.minWidth) {
47 | renderer.setElementAttribute(this.nativeElement, "data-gs-min-width", String(this.option.minWidth));
48 | }
49 | if (this.option.noResize != null && this.option.noResize == true) {
50 | renderer.setElementAttribute(this.nativeElement, "data-gs-no-resize", "yes");
51 | }
52 |
53 | }
54 |
55 | update(x: number, y: number, width: number, height: number): void {
56 | // console.log("here");
57 | if (x === this.option.x && y === this.option.y && width === this.option.width && height === this.option.height)
58 | return;
59 | if (this.option != null) {
60 | this.option.x = x;
61 | this.option.y = y;
62 | this.option.width = width;
63 | this.option.height = height;
64 |
65 | var optionNew = GridStackItem.Clone(this.option);
66 | this.onGridConfigurationChanged.emit(optionNew);
67 | }
68 | }
69 |
70 | ngAfterViewInit(): void {
71 | //if (!!this.contentTemplate) {
72 | // this.componentService.getDynamicComponentFactory({
73 | // selector: `grid-stack-item-${Date.now()}`,
74 | // template: this.contentTemplate
75 | // })
76 | // .then(factory => {
77 | // this.contentComponentRef = this.contentPlaceholder.createComponent(factory);
78 | // })
79 | //}
80 | }
81 |
82 | ngOnDestroy(): void {
83 | if (this.contentComponentRef !== null)
84 | this.contentComponentRef.destroy();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/grid-stack-item.model.ts:
--------------------------------------------------------------------------------
1 |
2 | export class GridStackItem {
3 | x: number = 0;
4 | y: number = 0;
5 | height: number = 1;
6 | width: number = 1;
7 | maxHeight: number;
8 | minHeight: number;
9 | maxWidth: number;
10 | minWidth: number;
11 | noResize: boolean = false;
12 | noMove: boolean;
13 | autoPosition: boolean = false;
14 | marginWidth: string = "10px";
15 | locked: boolean;
16 | el: any;
17 | customId: string;
18 | static Clone(widget: GridStackItem) {
19 | var result = new GridStackItem();
20 |
21 | result.autoPosition = widget.autoPosition;
22 | result.customId = widget.customId;
23 | result.el = widget.el;
24 | result.height = widget.height;
25 | result.locked = widget.locked;
26 | result.maxHeight = widget.maxHeight;
27 | result.maxWidth = widget.maxWidth;
28 | result.minHeight = widget.minHeight;
29 | result.minWidth = widget.minWidth;
30 | result.noMove = widget.noMove;
31 | result.noResize = widget.noResize;
32 | result.width = widget.width;
33 | result.x = widget.x;
34 | result.y = widget.y;
35 |
36 | return result;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/grid-stack-options.model.ts:
--------------------------------------------------------------------------------
1 | export class GridStackOptions {
2 | acceptWidgets: boolean;
3 | alwaysShowResizeHandle: boolean;
4 | animate: boolean;
5 | auto: boolean;
6 | cellHeight: string; //default is 60 could be an integer (px) a string (ex: '10em', '100px', '10rem') 0 or null 'auto' - height will be calculated from cell width.
7 | ddPlugin: boolean;
8 | disableDrag: boolean;
9 | disableResize: boolean;
10 | draggable: boolean;
11 | handle: string; //default: '.grid-stack-item-content'
12 | handleClass: string; //draggable handle class (e.g. 'grid-stack-item-content'). If set handle is ignored (default: null)
13 | height: number; //maximum rows amount. Default is 0 which means no maximum rows
14 | float: boolean; // enable floating widgets (default: false)
15 | itemClass: string; //widget class (default: 'grid-stack-item')
16 | minWidth: string; //minimal width.If window width is less, grid will be shown in one - column mode (default: 768)
17 | disableOneColumnMode: boolean; //disables the onColumnMode when the window width is less than minWidth (default: 'false')
18 | oneColumnModeClass: string; //class set on grid when in one column mode (default: 'grid-stack-one-column-mode')
19 | placeholderClass: string; //class for placeholder (default: 'grid-stack-placeholder')
20 | placeholderText: string; //placeholder default content (default: '')
21 | resizable: boolean; //allows to override jQuery UI resizable options. (default: {autoHide: true, handles: 'se'})
22 | removable: boolean; //if true widgets could be removed by dragging outside of the grid. It could also be a jQuery selector string, in this case widgets will be removed by dropping them there (default: false)
23 | removeTimeout: number; // time in milliseconds before widget is being removed while dragging outside of the grid. (default: 2000)
24 | rtl: string; //if true turns grid to RTL. Possible values are true, false, 'auto' (default: 'auto') See example
25 | staticGrid: boolean; //makes grid static (default false). If true widgets are not movable/resizable. You don't even need jQueryUI draggable/resizable. A CSS class grid-stack-static is also added to the container.
26 | verticalMargin: number; //vertical gap size (default: 20). Can be: an integer (px) a string (ex: '2em', '20px', '2rem')
27 | width: number; //amount of columns (default: 12). Setting non-default value must be supported by equivalent change in CSS
28 | }
29 |
--------------------------------------------------------------------------------
/src/grid-stack.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 | import { By } from '@angular/platform-browser';
3 | import { DebugElement } from '@angular/core';
4 |
5 | import { SampleComponent } from './sample.component';
6 |
7 | describe('SampleComponent', () => {
8 |
9 | let comp: SampleComponent;
10 | let fixture: ComponentFixture;
11 | let de: DebugElement;
12 | let el: HTMLElement;
13 |
14 | beforeEach(() => {
15 | TestBed.configureTestingModule({
16 | declarations: [ SampleComponent ], // declare the test component
17 | });
18 |
19 | fixture = TestBed.createComponent(SampleComponent);
20 |
21 | comp = fixture.componentInstance; // BannerComponent test instance
22 |
23 | // query for the title by CSS element selector
24 | de = fixture.debugElement.query(By.css('h1'));
25 | el = de.nativeElement;
26 | });
27 |
28 | it('Should be false', () => {
29 | expect(false).toBe(true);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/src/grid-stack.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, QueryList, Input, ContentChildren, ElementRef, Renderer, AfterContentInit } from '@angular/core';
2 | import { GridStackOptions } from './grid-stack-options.model';
3 | import { GridStackItem } from './grid-stack-item.model';
4 | import { GridStackItemComponent } from './grid-stack-item.component';
5 | declare var jQuery: any;
6 | declare var _: any;
7 |
8 | @Component({
9 | selector: 'grid-stack',
10 | template: ``,
11 | styles: [":host { display: block; }"]
12 | })
13 | export class GridStackComponent implements AfterContentInit {
14 |
15 | @Input() options: GridStackOptions = new GridStackOptions();
16 | @ContentChildren(GridStackItemComponent) items: QueryList;
17 | private gridStack: any = null;
18 | private grid: any = null;
19 | private defaultOptions = {
20 | cellHeight: '60px',
21 | width: 12,
22 | height: 0,
23 | animate: true,
24 | float: false,
25 | resizable: true
26 | };
27 |
28 | constructor(private el: ElementRef, private renderer: Renderer) {
29 | }
30 |
31 | public makeWidget(item: GridStackItemComponent) {
32 | item.jGridRef = this.grid;
33 | if (item.option != null && item.option.noResize != null && item.option.noResize) {
34 | return;
35 | }
36 |
37 | this.grid.resizable(item.nativeElement, true);
38 | this.grid.move(item.nativeElement, item.option.x, item.option.y);
39 | this.grid.resize(item.nativeElement, item.option.width, item.option.height);
40 | };
41 |
42 | public updateWidget(item: GridStackItemComponent) {
43 | this.grid.resizable(item.nativeElement, true);
44 | this.grid.move(item.nativeElement, item.option.x, item.option.y);
45 | this.grid.resize(item.nativeElement, item.option.width, item.option.height);
46 | }
47 |
48 | public AddWidget(item: GridStackItemComponent) {
49 | item.jGridRef = this.grid;
50 | if (item.option != null && item.option.noResize != null && item.option.noResize) {
51 | return;
52 | }
53 |
54 | this.grid.resizable(item.nativeElement, true);
55 | this.grid.move(item.nativeElement, item.option.x, item.option.y);
56 | this.grid.resize(item.nativeElement, item.option.width, item.option.height);
57 | }
58 |
59 | public RemoveWidget(item: GridStackItemComponent) {
60 | this.grid.removeWidget(item.nativeElement, false);
61 | }
62 |
63 | ngAfterContentInit(): void {
64 | const that = this;
65 | let nativeElement = this.el.nativeElement;
66 | if (this.options == null) {
67 | this.options = new GridStackOptions();
68 | }
69 |
70 | for (const key of Object.keys(this.defaultOptions)) {
71 | if (!this.options.hasOwnProperty(key)) {
72 | this.options = this.defaultOptions[key];
73 | }
74 | }
75 |
76 | this.renderer.setElementAttribute(nativeElement, 'data-gs-width', String(this.options.width));
77 | this.renderer.setElementAttribute(nativeElement, 'data-gs-height', String(this.options.height));
78 |
79 | this.gridStack = jQuery(nativeElement).gridstack(this.options);
80 | this.grid = this.gridStack.data('gridstack');
81 |
82 | this.gridStack.on('change', (e: any, items: any) => {
83 | _.each(items, (item: any) => this.widgetChanged(item));
84 | });
85 |
86 | // Initialize widgets
87 | this.items.forEach(item => that.makeWidget(item));
88 | }
89 |
90 | private widgetChanged(change: GridStackItem): void {
91 | const jWidget = change.el;
92 | const gridStackItem = this.items.find(item => item.jWidgetRef !== null ? item.jWidgetRef === jWidget[0] : false);
93 | if (!gridStackItem) {
94 | return;
95 | }
96 |
97 | gridStackItem.update(change.x, change.y, change.width, change.height);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/grid-stack.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef } from '@angular/core';
2 |
3 | @Directive({
4 | selector: '[gridStackDirective]'
5 | })
6 | export class GridStackDirective {
7 |
8 | constructor(private el: ElementRef) {
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/grid-stack.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, PipeTransform, Pipe } from '@angular/core';
2 |
3 | /**
4 | * Transforms any input value
5 | */
6 | @Pipe({
7 | name: 'gridStackPipe'
8 | })
9 | @Injectable()
10 | export class GridStackPipe implements PipeTransform {
11 | transform(value: any, args: any[] = null): string {
12 | return value;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/grid-stack.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | @Injectable()
4 | export class GridStackService {
5 |
6 | constructor() {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ModuleWithProviders } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { GridStackComponent } from './grid-stack.component';
4 | import { GridStackItemComponent } from './grid-stack-item.component';
5 | import { GridStackDirective } from './grid-stack.directive';
6 | import { GridStackPipe } from './grid-stack.pipe';
7 | import { GridStackService } from './grid-stack.service';
8 |
9 | import { GridStackOptions } from './grid-stack-options.model';
10 | import { GridStackItem } from './grid-stack-item.model';
11 | export * from './grid-stack.component';
12 | export * from './grid-stack-item.component';
13 | export * from './grid-stack.directive';
14 | export * from './grid-stack.pipe';
15 | export * from './grid-stack.service';
16 | export * from './grid-stack-options.model';
17 | export * from './grid-stack-item.model';
18 |
19 | @NgModule({
20 | imports: [
21 | CommonModule
22 | ],
23 | declarations: [
24 | GridStackComponent,
25 | GridStackItemComponent,
26 | GridStackDirective,
27 | GridStackPipe
28 | ],
29 | exports: [
30 | GridStackComponent,
31 | GridStackItemComponent,
32 | GridStackDirective,
33 | GridStackPipe
34 | ]
35 | })
36 | export class GridStackModule {
37 | static forRoot(): ModuleWithProviders {
38 | return {
39 | ngModule: GridStackModule,
40 | providers: [GridStackService]
41 | };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng4-gridstack",
3 | "version": "0.3.40",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/ramyothman/ng4-gridstack"
7 | },
8 | "author": {
9 | "name": "Ramy Othman",
10 | "email": "ramy.mostafa@gmail.com"
11 | },
12 | "keywords": [
13 | "angular"
14 | ],
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/ramyothman/ng4-gridstack/issues"
18 | },
19 | "main": "ng4-gridstack.umd.js",
20 | "module": "ng4-gridstack.js",
21 | "jsnext:main": "ng4-gridstack.js",
22 | "typings": "ng4-gridstack.d.ts",
23 | "peerDependencies": {
24 | "@angular/core": "^4.0.0",
25 | "rxjs": "^5.1.0",
26 | "zone.js": "^0.8.4"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/tsconfig.es5.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "module": "es2015",
5 | "target": "es5",
6 | "baseUrl": ".",
7 | "stripInternal": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "moduleResolution": "node",
11 | "outDir": "../build",
12 | "rootDir": ".",
13 | "lib": [
14 | "es2016",
15 | "dom"
16 | ],
17 | "skipLibCheck": true,
18 | "types": []
19 | },
20 | "angularCompilerOptions": {
21 | "annotateForClosureCompiler": true,
22 | "strictMetadataEmit": true,
23 | "skipTemplateCodegen": true,
24 | "flatModuleOutFile": "ng4-gridstack.js",
25 | "flatModuleId": "ng4-gridstack"
26 | },
27 | "files": [
28 | "./index.ts"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.es5.json",
3 | "compilerOptions": {
4 | "emitDecoratorMetadata": true,
5 | "experimentalDecorators": true,
6 | "outDir": "../out-tsc/spec",
7 | "module": "commonjs",
8 | "target": "es6",
9 | "baseUrl": "",
10 | "types": [
11 | "jest",
12 | "node"
13 | ]
14 | },
15 | "files": [
16 | "**/*.spec.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/tools/gulp/inline-resources.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // https://github.com/filipesilva/angular-quickstart-lib/blob/master/inline-resources.js
3 | 'use strict';
4 |
5 | const fs = require('fs');
6 | const path = require('path');
7 | const glob = require('glob');
8 | const sass = require('node-sass');
9 | const tildeImporter = require('node-sass-tilde-importer');
10 |
11 | /**
12 | * Simple Promiseify function that takes a Node API and return a version that supports promises.
13 | * We use promises instead of synchronized functions to make the process less I/O bound and
14 | * faster. It also simplifies the code.
15 | */
16 | function promiseify(fn) {
17 | return function () {
18 | const args = [].slice.call(arguments, 0);
19 | return new Promise((resolve, reject) => {
20 | fn.apply(this, args.concat([function (err, value) {
21 | if (err) {
22 | reject(err);
23 | } else {
24 | resolve(value);
25 | }
26 | }]));
27 | });
28 | };
29 | }
30 |
31 | const readFile = promiseify(fs.readFile);
32 | const writeFile = promiseify(fs.writeFile);
33 |
34 | /**
35 | * Inline resources in a tsc/ngc compilation.
36 | * @param projectPath {string} Path to the project.
37 | */
38 | function inlineResources(projectPath) {
39 |
40 | // Match only TypeScript files in projectPath.
41 | const files = glob.sync('**/*.ts', {cwd: projectPath});
42 |
43 | // For each file, inline the templates and styles under it and write the new file.
44 | return Promise.all(files.map(filePath => {
45 | const fullFilePath = path.join(projectPath, filePath);
46 | return readFile(fullFilePath, 'utf-8')
47 | .then(content => inlineResourcesFromString(content, url => {
48 | // Resolve the template url.
49 | return path.join(path.dirname(fullFilePath), url);
50 | }))
51 | .then(content => writeFile(fullFilePath, content))
52 | .catch(err => {
53 | console.error('An error occured: ', err);
54 | });
55 | }));
56 | }
57 |
58 | /**
59 | * Inline resources from a string content.
60 | * @param content {string} The source file's content.
61 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
62 | * @returns {string} The content with resources inlined.
63 | */
64 | function inlineResourcesFromString(content, urlResolver) {
65 | // Curry through the inlining functions.
66 | return [
67 | inlineTemplate,
68 | inlineStyle,
69 | removeModuleId
70 | ].reduce((content, fn) => fn(content, urlResolver), content);
71 | }
72 |
73 | /**
74 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
75 | * replace with `template: ...` (with the content of the file included).
76 | * @param content {string} The source file's content.
77 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
78 | * @return {string} The content with all templates inlined.
79 | */
80 | function inlineTemplate(content, urlResolver) {
81 | return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function (m, templateUrl) {
82 | const templateFile = urlResolver(templateUrl);
83 | const templateContent = fs.readFileSync(templateFile, 'utf-8');
84 | const shortenedTemplate = templateContent
85 | .replace(/([\n\r]\s*)+/gm, ' ')
86 | .replace(/"/g, '\\"');
87 | return `template: "${shortenedTemplate}"`;
88 | });
89 | }
90 |
91 |
92 | /**
93 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
94 | * replace with `styles: [...]` (with the content of the file included).
95 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
96 | * @param content {string} The source file's content.
97 | * @return {string} The content with all styles inlined.
98 | */
99 | function inlineStyle(content, urlResolver) {
100 | return content.replace(/styleUrls\s*:\s*(\[[\s\S]*?\])/gm, function (m, styleUrls) {
101 | const urls = eval(styleUrls);
102 | return 'styles: ['
103 | + urls.map(styleUrl => {
104 | const styleFile = urlResolver(styleUrl);
105 | const originContent = fs.readFileSync(styleFile, 'utf-8');
106 | const styleContent = styleFile.endsWith('.scss') ? buildSass(originContent, styleFile) : originContent;
107 | const shortenedStyle = styleContent
108 | .replace(/([\n\r]\s*)+/gm, ' ')
109 | .replace(/"/g, '\\"');
110 | return `"${shortenedStyle}"`;
111 | })
112 | .join(',\n')
113 | + ']';
114 | });
115 | }
116 |
117 | /**
118 | * build sass content to css
119 | * @param content {string} the css content
120 | * @param sourceFile {string} the scss file sourceFile
121 | * @return {string} the generated css, empty string if error occured
122 | */
123 | function buildSass(content, sourceFile) {
124 | try {
125 | const result = sass.renderSync({
126 | data: content,
127 | file: sourceFile,
128 | importer: tildeImporter
129 | });
130 | return result.css.toString()
131 | } catch (e) {
132 | console.error('\x1b[41m');
133 | console.error('at ' + sourceFile + ':' + e.line + ":" + e.column);
134 | console.error(e.formatted);
135 | console.error('\x1b[0m');
136 | return "";
137 | }
138 | }
139 |
140 | /**
141 | * Remove every mention of `moduleId: module.id`.
142 | * @param content {string} The source file's content.
143 | * @returns {string} The content with all moduleId: mentions removed.
144 | */
145 | function removeModuleId(content) {
146 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
147 | }
148 |
149 | module.exports = inlineResources;
150 | module.exports.inlineResourcesFromString = inlineResourcesFromString;
151 |
152 | // Run inlineResources if module is being called directly from the CLI with arguments.
153 | if (require.main === module && process.argv.length > 2) {
154 | console.log('Inlining resources from project:', process.argv[2]);
155 | return inlineResources(process.argv[2]);
156 | }
157 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src",
4 | "experimentalDecorators": true,
5 | "moduleResolution": "node",
6 | "rootDir": "./src",
7 | "target": "es5",
8 | "lib": [
9 | "es2016",
10 | "dom"
11 | ],
12 | "skipLibCheck": true,
13 | "types": []
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "class-name": true,
7 | "comment-format": [
8 | true,
9 | "check-space"
10 | ],
11 | "curly": true,
12 | "eofline": true,
13 | "forin": true,
14 | "indent": [
15 | true,
16 | "spaces"
17 | ],
18 | "label-position": true,
19 | "max-line-length": [
20 | true,
21 | 140
22 | ],
23 | "member-access": false,
24 | "member-ordering": [
25 | true,
26 | "static-before-instance",
27 | "variables-before-functions"
28 | ],
29 | "no-arg": true,
30 | "no-bitwise": true,
31 | "no-console": [
32 | true,
33 | "debug",
34 | "info",
35 | "time",
36 | "timeEnd",
37 | "trace"
38 | ],
39 | "no-construct": true,
40 | "no-debugger": true,
41 | "no-duplicate-variable": true,
42 | "no-empty": false,
43 | "no-eval": true,
44 | "no-inferrable-types": true,
45 | "no-shadowed-variable": true,
46 | "no-string-literal": false,
47 | "no-switch-case-fall-through": true,
48 | "no-trailing-whitespace": true,
49 | "no-unused-expression": true,
50 | "no-unused-variable": true,
51 | "no-use-before-declare": true,
52 | "no-var-keyword": true,
53 | "object-literal-sort-keys": false,
54 | "one-line": [
55 | true,
56 | "check-open-brace",
57 | "check-catch",
58 | "check-else",
59 | "check-whitespace"
60 | ],
61 | "quotemark": [
62 | true,
63 | "single"
64 | ],
65 | "radix": true,
66 | "semicolon": [
67 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ],
92 | "directive-selector": [true, "attribute", "", "camelCase"],
93 | "component-selector": [true, "element", "", "kebab-case"],
94 | "use-input-property-decorator": true,
95 | "use-output-property-decorator": true,
96 | "use-host-property-decorator": true,
97 | "no-input-rename": true,
98 | "no-output-rename": true,
99 | "use-life-cycle-interface": true,
100 | "use-pipe-transform-interface": true,
101 | "component-class-suffix": true,
102 | "directive-class-suffix": true
103 | }
104 | }
105 |
--------------------------------------------------------------------------------