hoodcms 5.0.14 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/css/login.css +1 -1
  2. package/dist/js/admin/ContentController.d.ts +30 -0
  3. package/dist/js/admin/ContentController.js +188 -0
  4. package/dist/js/admin/ContentTypeController.d.ts +15 -0
  5. package/dist/js/admin/ContentTypeController.js +140 -0
  6. package/dist/js/admin/HomeController.d.ts +17 -0
  7. package/dist/js/admin/HomeController.js +111 -0
  8. package/dist/js/admin/LogsController.d.ts +6 -0
  9. package/dist/js/admin/LogsController.js +14 -0
  10. package/dist/js/admin/MediaController.d.ts +7 -0
  11. package/dist/js/admin/MediaController.js +29 -0
  12. package/dist/js/admin/PropertyController.d.ts +18 -0
  13. package/dist/js/admin/PropertyController.js +118 -0
  14. package/dist/js/admin/PropertyImporter.d.ts +31 -0
  15. package/dist/js/admin/PropertyImporter.js +95 -0
  16. package/dist/js/admin/ThemesController.d.ts +8 -0
  17. package/dist/js/admin/ThemesController.js +37 -0
  18. package/dist/js/admin/UsersController.d.ts +17 -0
  19. package/dist/js/admin/UsersController.js +176 -0
  20. package/dist/js/admin.js +23 -5
  21. package/dist/js/app/PropertyService.d.ts +46 -0
  22. package/{src/ts/app/PropertyController.ts → dist/js/app/PropertyService.js} +44 -76
  23. package/dist/js/app.js +23 -5
  24. package/dist/js/app.property.js +24 -0
  25. package/dist/js/core/DataList.js +25 -3
  26. package/dist/js/core/HoodApi.d.ts +17 -7
  27. package/dist/js/core/HoodApi.js +71 -10
  28. package/dist/js/core/Validator.js +1 -1
  29. package/dist/js/index.d.ts +10 -1
  30. package/dist/js/index.js +12 -1
  31. package/dist/js/login.js +1 -1
  32. package/images/hood-small.png +0 -0
  33. package/images/hood.png +0 -0
  34. package/package.json +108 -108
  35. package/src/css/admin.css +0 -3
  36. package/src/css/admin.css.map +1 -1
  37. package/src/css/app.css +0 -3
  38. package/src/css/app.css.map +1 -1
  39. package/src/css/login.css +165 -0
  40. package/src/css/login.css.map +1 -1
  41. package/src/html/auth0/login.html +100 -0
  42. package/src/html/auth0/passwordless-email.html +184 -0
  43. package/src/js/admin.js +43455 -1820
  44. package/src/js/admin.js.map +1 -1
  45. package/src/js/app.js +41910 -906
  46. package/src/js/app.js.map +1 -1
  47. package/src/js/app.property.js +1169 -0
  48. package/src/js/app.property.js.map +1 -0
  49. package/src/js/login.js +1 -1
  50. package/src/scss/core/_images.scss +48 -48
  51. package/src/scss/login.scss +1 -0
  52. package/src/ts/admin.ts +3 -0
  53. package/src/ts/app/PropertyService.ts +202 -0
  54. package/src/ts/app.property.ts +20 -0
  55. package/src/ts/app.ts +3 -81
  56. package/src/ts/core/DataList.ts +27 -4
  57. package/src/ts/core/HoodApi.ts +96 -14
  58. package/src/ts/core/Validator.ts +1 -1
  59. package/src/ts/index.ts +14 -1
  60. package/temp.txt +1 -0
  61. package/dist/js/core/BaseSite.d.ts +0 -6
  62. package/dist/js/core/BaseSite.js +0 -14
  63. package/src/ts/core/BaseSite.ts +0 -21
@@ -0,0 +1,202 @@
1
+ /// <reference types="google.maps" />
2
+
3
+ import { Alerts } from "../core/Alerts";
4
+ import { DataList } from "../core/DataList";
5
+
6
+ declare global {
7
+ namespace google.maps {
8
+ interface Marker {
9
+ info: string;
10
+ }
11
+ }
12
+ }
13
+
14
+ export interface PropertyServiceOptions {
15
+
16
+ listElementId?: string;
17
+ mapListElementId?: string;
18
+ mapElementId?: string;
19
+
20
+ /**
21
+ * Called before the data is fetched.
22
+ */
23
+ onListLoad?: (sender?: HTMLElement) => void;
24
+
25
+ /**
26
+ * Called before the fetched HTML is rendered to the list. Must return the data back to datalist to render.
27
+ */
28
+ onListRender?: (html: string, sender?: HTMLElement) => string;
29
+ /**
30
+ * Called before the data is fetched.
31
+ */
32
+ onMapLoad?: (data: string, sender?: HTMLElement) => void;
33
+
34
+ /**
35
+ * Called before the fetched HTML is rendered to the list. Must return the data back to datalist to render.
36
+ */
37
+ onMapRender?: (sender?: HTMLElement) => string;
38
+
39
+ }
40
+
41
+ export class PropertyService {
42
+ options: PropertyServiceOptions = {
43
+ listElementId: 'property-list',
44
+ mapListElementId: 'property-map-list',
45
+ mapElementId: 'property-map'
46
+ };
47
+
48
+ constructor(options?: PropertyServiceOptions) {
49
+
50
+ this.options = { ...this.options, ...options };
51
+
52
+ this.initList();
53
+ }
54
+
55
+ element: HTMLElement;
56
+ list: DataList;
57
+ mapListElement: HTMLElement;
58
+ mapList: DataList;
59
+ map: google.maps.Map = null;
60
+ center: google.maps.LatLngLiteral = { lat: 30, lng: -110 };
61
+ mapElement: HTMLElement;
62
+ markers: any[];
63
+
64
+ initList() {
65
+
66
+ this.element = document.getElementById(this.options.listElementId);
67
+ if (!this.element) {
68
+ return;
69
+ }
70
+
71
+ this.list = new DataList(this.element, {
72
+ onLoad: function (this: PropertyService, sender: HTMLElement = null) {
73
+
74
+ if (this.options.onListLoad) {
75
+ this.options.onListLoad(sender);
76
+ }
77
+
78
+ }.bind(this),
79
+ onComplete: function (this: PropertyService, data: string, sender: HTMLElement = null) {
80
+
81
+ if (this.options.onListRender) {
82
+ this.options.onListRender(data, sender);
83
+ }
84
+ Alerts.log('Finished loading property list.', 'info');
85
+
86
+ }.bind(this)
87
+ });
88
+
89
+ }
90
+
91
+ initMapList() {
92
+
93
+ this.mapListElement = document.getElementById(this.options.mapListElementId);
94
+ if (!this.mapElement) {
95
+ return;
96
+ }
97
+
98
+ this.mapList = new DataList(this.mapListElement, {
99
+ onComplete: function (this: PropertyService, data: string, sender: HTMLElement = null) {
100
+
101
+ if (this.options.onMapLoad) {
102
+ this.options.onMapLoad(data, sender);
103
+ }
104
+ Alerts.log('Finished loading map list.', 'info');
105
+ this.reloadMarkers();
106
+
107
+ }.bind(this)
108
+ });
109
+ }
110
+
111
+ initMap() {
112
+
113
+ this.mapElement = document.getElementById(this.options.mapElementId);
114
+ if (!this.mapElement) {
115
+ return;
116
+ }
117
+
118
+ this.center = { lat: +this.mapElement.dataset.lat, lng: +this.mapElement.dataset.long };
119
+
120
+ this.map = new google.maps.Map(this.mapElement, {
121
+ zoom: +this.mapElement.dataset.zoom || 15,
122
+ center: this.center,
123
+ scrollwheel: false
124
+ });
125
+
126
+ $(window).resize(function (this: PropertyService) {
127
+ google.maps.event.trigger(this.map, 'resize');
128
+ }.bind(this));
129
+
130
+ google.maps.event.trigger(this.map, 'resize');
131
+
132
+ this.initMapList();
133
+
134
+ }
135
+
136
+ reloadMarkers() {
137
+
138
+ var infowindow: google.maps.InfoWindow = null;
139
+
140
+ if (!this.mapElement) {
141
+ return;
142
+ }
143
+
144
+ var map = this.map;
145
+
146
+ if (this.markers) {
147
+ for (var i = 0; i < this.markers.length; i++) {
148
+ this.markers[i].setMap(null);
149
+ }
150
+ }
151
+
152
+ this.markers = [];
153
+
154
+ var locations = $("#property-map-locations").data('locations');
155
+
156
+ locations.map(function (this: PropertyService, location: any, i: number) {
157
+
158
+ let marker = new google.maps.Marker({
159
+ position: new google.maps.LatLng(+location.Latitude, +location.Longitude),
160
+ map: this.map,
161
+ optimized: true // makes SVG icons work in IE
162
+ });
163
+
164
+ if (this.mapElement.dataset.marker) {
165
+ marker.setIcon(this.mapElement.dataset.marker);
166
+ }
167
+
168
+ marker.info = `<div class="card border-0" style="max-width:300px">
169
+ <div style="background-image:url(${location.ImageUrl})" class="rounded img-full img img-wide"></div>
170
+ <div class="card-body border-0">
171
+ <p style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
172
+ <strong>${location.Address1}, ${location.Postcode}</strong>
173
+ </p>
174
+ <p>${location.Description}</p>
175
+ <a href="${location.MarkerUrl}" class="btn btn-block btn-primary">Find out more...</a>
176
+ </div>
177
+ </div>`;
178
+
179
+ marker.addListener("click", () => {
180
+ if (infowindow) {
181
+ infowindow.close();
182
+ }
183
+ infowindow = new google.maps.InfoWindow({
184
+ content: marker.info
185
+ });
186
+ infowindow.open({
187
+ anchor: marker,
188
+ map,
189
+ shouldFocus: false,
190
+ });
191
+ });
192
+
193
+ this.markers.push(marker);
194
+
195
+ }.bind(this));
196
+
197
+
198
+ if (this.options.onMapRender) {
199
+ this.options.onMapRender();
200
+ }
201
+ }
202
+ }
@@ -0,0 +1,20 @@
1
+ /// <reference types="google.maps" />
2
+
3
+ import { HoodApi, PropertyService } from ".";
4
+
5
+ export class App extends HoodApi {
6
+ property: PropertyService;
7
+
8
+ constructor() {
9
+ super();
10
+
11
+ // Setup defaults with HoodApi default initialise function.
12
+ this.initialise();
13
+
14
+ // Initialise the property controllers.
15
+ this.property = new PropertyService();
16
+ }
17
+
18
+ }
19
+
20
+ window.hood = new App();
package/src/ts/app.ts CHANGED
@@ -1,91 +1,13 @@
1
1
  /// <reference types="google.maps" />
2
2
 
3
- import { HoodApi } from "./core/HoodApi";
4
- import { PropertyController } from './app/PropertyController';
5
- import { Validator } from './core/Validator';
6
- import { Response } from './core/Response';
7
- import { Alerts } from './core/Alerts';
3
+ import { HoodApi } from ".";
8
4
 
9
5
  export class App extends HoodApi {
10
- propertyController: PropertyController;
11
6
 
12
7
  constructor() {
13
8
  super();
14
-
15
- // Hook up default handlers.
16
- this.handlers.initDefaultHandlers();
17
- this.initContactForms();
18
-
19
-
20
- // Admin Controllers
21
- this.propertyController = new PropertyController();
22
- }
23
-
24
- initGoogleMaps(tag: string = '.google-map') {
25
-
26
- $(tag).each(function () {
27
-
28
- var myLatLng = new google.maps.LatLng($(this).data('lat'), $(this).data('long'));
29
-
30
- console.log('Loading map at: ' + $(this).data('lat') + ', ' + $(this).data('long'));
31
-
32
- var map = new google.maps.Map(this, {
33
- zoom: $(this).data('zoom') || 15,
34
- center: myLatLng,
35
- scrollwheel: false
36
- });
37
-
38
- var marker = new google.maps.Marker({
39
- position: myLatLng,
40
- map: map,
41
- title: $(this).data('marker')
42
- });
43
-
44
- $(window).resize(function () {
45
- google.maps.event.trigger(map, 'resize');
46
- });
47
- google.maps.event.trigger(map, 'resize');
48
-
49
- });
50
-
51
- }
52
- /**
53
- * Initialisation function for contact forms on the site, will add validator, and submit/functionality to any forms matching the given tag selector string.
54
- * @param {string='.contact-form'} tag
55
- */
56
- initContactForms(tag: string = '.contact-form') {
57
-
58
- let $form = $(tag);
59
-
60
- $form.find('.thank-you').hide();
61
- $form.find('.form-content').show();
62
-
63
- let form: HTMLFormElement = $(tag)[0] as HTMLFormElement;
64
- new Validator(form, {
65
- onComplete: function (this: App, response: Response) {
66
-
67
- Response.process(response, 5000);
68
-
69
- if (response.success) {
70
-
71
- if ($form.attr('data-redirect'))
72
- window.location.href = $form.attr('data-redirect');
73
-
74
- if ($form.attr('data-alert-message'))
75
- Alerts.success($form.attr('data-alert-message'), "Success");
76
-
77
- $form.find('.form').hide();
78
- $form.find('.thank-you').show();
79
- } else {
80
- if ($form.attr('data-alert-error'))
81
- Alerts.error($form.attr('data-alert-error'), "Error");
82
- else
83
- Alerts.error("There was an error sending the message: " + response.errors, "Error");
84
- }
85
-
86
- }.bind(this)
87
- });
88
-
9
+ // Setup defaults with HoodApi default initialise function.
10
+ this.initialise();
89
11
  }
90
12
 
91
13
  }
@@ -46,7 +46,7 @@ export class DataList {
46
46
 
47
47
  this.element = element;
48
48
  this.element.hoodDataList = this;
49
- if (typeof(element) == 'undefined' || element == null) {
49
+ if (typeof (element) == 'undefined' || element == null) {
50
50
  Alerts.log('Could not DataList to element, element does not exist.', 'error');
51
51
  return;
52
52
  }
@@ -54,9 +54,32 @@ export class DataList {
54
54
  this.options = { ...this.options, ...options };
55
55
 
56
56
  if ($(this.element).hasClass('query')) {
57
- let pageUrl = $(this.element).data('url') + window.location.search;
58
- $(this.element).attr('data-url', pageUrl);
59
- $(this.element).data('url', pageUrl);
57
+
58
+ let r = new RegExp('^(?:[a-z]+:)?//', 'i');
59
+ let pageUrl: URL = null;
60
+ if (r.test(this.element.dataset.url)) {
61
+ pageUrl = new URL(this.element.dataset.url);
62
+ } else {
63
+ pageUrl = new URL(window.location.origin + this.element.dataset.url);
64
+ }
65
+ if ('URLSearchParams' in window) {
66
+ var searchParams = new URLSearchParams(window.location.search);
67
+ var urlParams = new URLSearchParams(pageUrl.search);
68
+ searchParams.forEach((value, key, parent) => {
69
+ urlParams.set(key, value);
70
+ });
71
+ if (urlParams.get("page") == "0") {
72
+ urlParams.set("page", "1");
73
+ }
74
+ pageUrl.search = urlParams.toString();
75
+ } else {
76
+ pageUrl.search = window.location.search;
77
+ }
78
+
79
+ let url = pageUrl.pathname + pageUrl.search;
80
+ $(this.element).attr('data-url', url);
81
+ $(this.element).data('url', url);
82
+
60
83
  }
61
84
 
62
85
  if (!$(this.element).hasClass('refresh-only')) {
@@ -1,8 +1,8 @@
1
- import { Alerts } from "./Alerts";
2
- import { ColorPickers } from "./ColorPicker";
3
- import { Editors } from "./Editors";
1
+ /// <reference types="google.maps" />
2
+
3
+ import { Response, Validator } from "..";
4
+ import { Alerts } from "./Alerts";
4
5
  import { Handlers } from "./Handlers";
5
- import { MediaModal } from "./Media";
6
6
  import { Uploader } from "./Uploader";
7
7
 
8
8
  declare global {
@@ -17,22 +17,104 @@ declare global {
17
17
  }
18
18
  }
19
19
 
20
- export class HoodApi implements Hood {
20
+ /**
21
+ * Base class for extending a Hood CMS website, ensure you call HoodApi.initialise() to setup loaders and contact form defaults.
22
+ */
23
+ export class HoodApi {
21
24
  alerts: Alerts = new Alerts();
22
- uploader: Uploader = new Uploader();
23
25
  handlers: Handlers = new Handlers();
24
- editors: Editors = new Editors();
25
- colorPickers: ColorPickers = new ColorPickers();
26
-
27
- private mediaModal: MediaModal = new MediaModal();
26
+ uploader: Uploader = new Uploader();
28
27
 
29
28
  constructor() {
30
- // Global Handlers
29
+ }
30
+
31
+ // Initialise Hood CMS site defaults, can be overridden or individual setup items can be called instead of the initialise function.
32
+ initialise() {
33
+ // Initialise loaders (default, adds loading to body tag)
31
34
  this.setupLoaders();
35
+
36
+ // Hook up default handlers.
37
+ this.handlers.initDefaultHandlers();
38
+
39
+ // Init hood contact forms.
40
+ this.initContactForms();
32
41
  }
33
42
 
43
+ /**
44
+ * Default Hood CMS loaders, can be used however, this simply adds a "loading" class to the body tag on show/hide.
45
+ */
34
46
  setupLoaders(): void {
35
- $('body').on('loader-show', function () { Alerts.success("Showing loader..."); })
36
- $('body').on('loader-hide', function () { Alerts.error("Hiding loader..."); })
47
+ $('body').on('loader-show', function () { document.body.classList.add('loading') })
48
+ $('body').on('loader-hide', function () { document.body.classList.remove('loading') })
37
49
  }
38
- }
50
+
51
+ /**
52
+ * Default initialisation function for Google Maps, should be called as the callback from the Google Maps API script tag.
53
+ */
54
+ initGoogleMaps(tag: string = '.google-map') {
55
+
56
+ $(tag).each(function () {
57
+
58
+ var myLatLng = new google.maps.LatLng($(this).data('lat'), $(this).data('long'));
59
+
60
+ console.log('Loading map at: ' + $(this).data('lat') + ', ' + $(this).data('long'));
61
+
62
+ var map = new google.maps.Map(this, {
63
+ zoom: $(this).data('zoom') || 15,
64
+ center: myLatLng,
65
+ scrollwheel: false
66
+ });
67
+
68
+ var marker = new google.maps.Marker({
69
+ position: myLatLng,
70
+ map: map,
71
+ title: $(this).data('marker')
72
+ });
73
+
74
+ $(window).on('resize', function () {
75
+ google.maps.event.trigger(map, 'resize');
76
+ });
77
+ google.maps.event.trigger(map, 'resize');
78
+
79
+ });
80
+
81
+ }
82
+
83
+ /**
84
+ * Initialisation function for contact forms on the site, will add validator, and submit/functionality to any forms matching the given tag selector string.
85
+ */
86
+ initContactForms(tag: string = '.contact-form') {
87
+
88
+ let $form = $(tag);
89
+
90
+ $form.find('.thank-you').hide();
91
+ $form.find('.form-content').show();
92
+
93
+ let form: HTMLFormElement = $(tag)[0] as HTMLFormElement;
94
+ new Validator(form, {
95
+ onComplete: function (this: HoodApi, response: Response) {
96
+ if (response.success) {
97
+
98
+ if ($form.attr('data-redirect'))
99
+ window.location.href = $form.attr('data-redirect');
100
+
101
+ if ($form.attr('data-alert-message'))
102
+ Alerts.success($form.attr('data-alert-message'));
103
+
104
+ $form.find('.form').hide();
105
+ $form.find('.thank-you').show();
106
+ } else {
107
+ if ($form.attr('data-alert-error'))
108
+ Alerts.error($form.attr('data-alert-error'));
109
+ else {
110
+ console.error(response.errors);
111
+ Alerts.error("There are errors on the form, please check your answers and try again.");
112
+ }
113
+ }
114
+
115
+ }.bind(this)
116
+ });
117
+
118
+ }
119
+
120
+ }
@@ -29,7 +29,7 @@ export interface ValidatorOptions {
29
29
  export class Validator {
30
30
  element: HTMLFormElement;
31
31
  options: ValidatorOptions = {
32
- errorAlert: 'There are errors, please check the form.',
32
+ errorAlert: 'There are errors on the form, please check your answers and try again.',
33
33
  useAjax: true
34
34
  };
35
35
 
package/src/ts/index.ts CHANGED
@@ -5,7 +5,6 @@ export * from './models/Property'
5
5
  export * from './models/Users'
6
6
 
7
7
  export * from './core/Alerts'
8
- export * from './core/BaseSite'
9
8
  export * from './core/ColorPicker'
10
9
  export * from './core/DataList'
11
10
  export * from './core/Editors'
@@ -24,3 +23,17 @@ export * from './core/Validator'
24
23
  export * from './extensions/jqueryExtensions'
25
24
  export * from './extensions/numberExtensions'
26
25
  export * from './extensions/stringExtensions'
26
+
27
+ // Extendables for admin area
28
+ export * from './admin/ContentController'
29
+ export * from './admin/ContentTypeController'
30
+ export * from './admin/HomeController'
31
+ export * from './admin/LogsController'
32
+ export * from './admin/MediaController'
33
+ export * from './admin/PropertyController'
34
+ export * from './admin/PropertyImporter'
35
+ export * from './admin/ThemesController'
36
+ export * from './admin/UsersController'
37
+
38
+ // Extendables for app
39
+ export * from './app/PropertyService'
package/temp.txt ADDED
@@ -0,0 +1 @@
1
+ 8^N2a43)Kd|.wdl,
@@ -1,6 +0,0 @@
1
- export declare class BaseSite {
2
- constructor();
3
- initialise(): void;
4
- onLoad(): void;
5
- onResize(): void;
6
- }
@@ -1,14 +0,0 @@
1
- export class BaseSite {
2
- constructor() {
3
- // Initialise
4
- this.initialise();
5
- $(window).on('load', this.onLoad.bind(this));
6
- $(window).on('resize', this.onResize.bind(this));
7
- }
8
- initialise() {
9
- }
10
- onLoad() {
11
- }
12
- onResize() {
13
- }
14
- }
@@ -1,21 +0,0 @@
1
- export class BaseSite {
2
-
3
- constructor() {
4
-
5
- // Initialise
6
- this.initialise();
7
-
8
- $(window).on('load', this.onLoad.bind(this));
9
- $(window).on('resize', this.onResize.bind(this));
10
-
11
- }
12
-
13
- initialise() {
14
- }
15
-
16
- onLoad() {
17
- }
18
-
19
- onResize() {
20
- }
21
- }