@qbix/q.js 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,8 +6,8 @@ Size: ~40KB (Minified + GZipped), [compare to other frameworks](https://gist.git
6
6
  How to use: copy contents of `dist` into your project, and then include it like this:
7
7
  | File Type | Code to Use |
8
8
  |------------|-------------|
9
- |`.html` files| `<script type="module">import { Q } from 'https://unpkg.com/@qbixplatform/q.js@1.0.16/dist/Q.js</script>`|
10
- |`.js` or `.ts` files|`import Q from 'https://unpkg.com/@qbixplatform/q.js@1.0.17/dist/Q.js';`
9
+ |`.html` files| `<script type="module" src="https://unpkg.com/@qbix/q.js@1.0.2/dist/Q.min.js">`|
10
+ |`.js` or `.ts` files|`import Q from 'https://unpkg.com/@qbix/q.js@1.0.2/dist/Q.min.js';`
11
11
  |<img src="https://github.com/user-attachments/assets/ba3df93e-0cd8-4189-93fc-11947b63b684" alt="Description" width="100" height="87"> | Full documentation here: https://qbix.com/platform/guide/javascript |
12
12
 
13
13
  This is part of the much larger full-stack [Qbix Platform](https://github.com/Qbix/Platform) that contains many pre-built reusable tools, plugins, and requires PHP and Node.js on the back-end. If you want to build an entire full-stack social network like Facebook you're well-advised to go with that. But if you just want to use the lightweight front-end core, with your own back-end and other frameworks, then start with this framework here.
package/dist/Q.js CHANGED
@@ -3173,8 +3173,12 @@ Q.currentScript = function (stackLevels) {
3173
3173
  console.warn("parseSrc: could not parse src", src);
3174
3174
  return null;
3175
3175
  }
3176
+ var src = parts[1] + parts[2].split(/[?#]/)[0];
3177
+ if (!root._Q_currentScript_src) {
3178
+ root._Q_currentScript_src = src;
3179
+ }
3176
3180
  return {
3177
- src: parts[1] + parts[2].split(/[?#]/)[0], // clean URL (no query/hash)
3181
+ src: src, // clean URL (no query/hash)
3178
3182
  srcWithQuerystring: parts[1] + parts[2], // keep full URL
3179
3183
  path: parts[1], // directory path
3180
3184
  file: parts[2].split(/[?#]/)[0] // filename only
@@ -3192,8 +3196,22 @@ Q.currentScript = function (stackLevels) {
3192
3196
  * @return {Object} object with properties "src", "path" and "file"
3193
3197
  */
3194
3198
  Q.currentScriptPath = function (subpath, stackLevels) {
3195
- return Q.currentScript(stackLevels).src.split('/').slice(0, -1).join('/')
3196
- + (subpath ? '/' + subpath : '');
3199
+ var cs = Q.currentScript(stackLevels);
3200
+ var src = (cs && cs.src)
3201
+ || root._Q_currentScript_src
3202
+ || (document.currentScript && document.currentScript.src);
3203
+ if (!src) {
3204
+ // last resort: most recently added script with a src
3205
+ var scripts = document.getElementsByTagName('script');
3206
+ for (var i = scripts.length - 1; i >= 0; --i) {
3207
+ if (scripts[i].src) { src = scripts[i].src; break; }
3208
+ }
3209
+ }
3210
+ if (!src) {
3211
+ return Q.info && Q.info.baseUrl ? Q.info.baseUrl : '';
3212
+ }
3213
+ return src.split('/').slice(0, -1).join('/')
3214
+ + (subpath ? '/' + subpath : '');
3197
3215
  };
3198
3216
  var currentScriptPath = Q.currentScriptPath();
3199
3217
 
@@ -4018,6 +4036,180 @@ Q.getter.REQUESTING = 1;
4018
4036
  Q.getter.WAITING = 2;
4019
4037
  Q.getter.THROTTLING = 3;
4020
4038
 
4039
+ /**
4040
+ * Used for handling callbacks, whether they come as functions,
4041
+ * strings referring to functions (if evaluated), arrays or hashes.
4042
+ * @static
4043
+ * @method handle
4044
+ * @param {Mixed} callables
4045
+ * The callables to call
4046
+ * Can be a function, array of functions, object of functions, Q.Event or URL
4047
+ * If it is a url, simply follow it with options, callback
4048
+ * @param {Function} callback
4049
+ * You can pass a function here if callables is a URL
4050
+ * @param {Object} context
4051
+ * The context in which to call them
4052
+ * @param {Array} args
4053
+ * An array of arguments to pass to them
4054
+ * @param {Object} options
4055
+ * If callables is a url, these are the options to pass to Q.loadUrl, if any. Also can include:
4056
+ * @param {boolean} [options.dontReload=false] if this is true and callback is a url matching current url, it is not reloaded
4057
+ * @param {boolean} [options.loadUsingAjax=true] if this is true and callback is a url, it is loaded using Q.loadUrl
4058
+ * @param {Function} [options.externalLoader] when using loadUsingAjax, you can set this to a function to suppress loading of external websites with Q.handle.
4059
+ * Note: this will still not supress loading of external websites done with other means, such as window.location
4060
+ * @param {Object} [options.fields] optional fields to pass with any method other than "get"
4061
+ * @param {String|Function} [options.callback] if a string, adds a '&Q.callback='+encodeURIComponent(callback) to the querystring. If a function, this is the callback.
4062
+ * @param {String} [options.loadExtras="session"] if "all", asks the server to load the extra scripts, stylesheets, etc. that are loaded on first page load, can also be "response", "initial", "session" or "initial,session"
4063
+ * @param {String} [options.target] the name of a window or iframe to use as the target. In this case callables is treated as a url.
4064
+ * @param {String|Array} [options.slotNames] a comma-separated list of slot names, or an array of slot names
4065
+ * @param {boolean} [options.quiet] defaults to false. If true, allows visual indications that the request is going to take place.
4066
+ * @param {Function} [options.handleException] pass a function here to handle thrown exceptions instead of rethrowing them
4067
+ * @return {number}
4068
+ * The number of handlers executed
4069
+ */
4070
+ Q.handle = function _Q_handle(callables, /* callback, */ context, args, options) {
4071
+ try {
4072
+ if (!callables) {
4073
+ return 0;
4074
+ }
4075
+ if (!context) context = root;
4076
+ if (!args) args = [];
4077
+ var i=0, count=0, k, result;
4078
+ if (callables === location) callables = location.href;
4079
+ switch (Q.typeOf(callables)) {
4080
+ case 'function':
4081
+ result = callables.apply(context, args);
4082
+ if (result === false) return false;
4083
+ return 1;
4084
+ case 'array':
4085
+ for (i=0; i<callables.length; ++i) {
4086
+ result = Q.handle(callables[i], context, args);
4087
+ if (result === false) return false;
4088
+ count += result;
4089
+ }
4090
+ return count;
4091
+ case 'Q.Event':
4092
+ return callables.handle.apply(context, args);
4093
+ case 'object':
4094
+ for (k in callables) {
4095
+ result = Q.handle(callables[k], context, args);
4096
+ if (result === false) return false;
4097
+ count += result;
4098
+ }
4099
+ return count;
4100
+ case 'string':
4101
+ var o = Q.extend({}, Q.handle.options, options);
4102
+ if (!callables.isUrl()
4103
+ && (callables[0] != '#')
4104
+ && (!o.target || o.target.toLowerCase() === '_self')) {
4105
+ // Assume this is not a URL.
4106
+ // Try to evaluate the expression, and execute the resulting function
4107
+ var c = Q.getObject(callables, context) || Q.getObject(callables);
4108
+ return Q.handle(c, context, args);
4109
+ }
4110
+ // Assume callables is a URL
4111
+ if (o.dontReload && Q.info && Q.info.url === callables) {
4112
+ return 0;
4113
+ }
4114
+ var callback = null;
4115
+ if (typeof arguments[1] === 'function') {
4116
+ // Some syntactic sugar: (url, callback) omitting context, args, options
4117
+ callback = arguments[1];
4118
+ o = Q.handle.options;
4119
+ } else if (arguments[1] && (arguments[3] === undefined)) {
4120
+ // Some more syntactic sugar: (url, options, callback) omitting context, args, options
4121
+ o = Q.extend({}, Q.handle.options, arguments[1]);
4122
+ if (typeof arguments[2] === 'function') {
4123
+ callback = arguments[2];
4124
+ }
4125
+ } else {
4126
+ o = Q.extend({}, Q.handle.options, options);
4127
+ if (o.callback) {
4128
+ callback = o.callback;
4129
+ }
4130
+ }
4131
+ var baseUrl = Q.baseUrl();
4132
+ var sameDomain = callables.sameDomain(baseUrl);
4133
+ if (callables[0] === '#') {
4134
+ root.location.hash = callables;
4135
+ } else if (o.loadUsingAjax && sameDomain
4136
+ && (!o.target || o.target === true || o.target === '_self')) {
4137
+ if (callables.search(baseUrl) === 0) {
4138
+ // Use AJAX to refresh the page whenever the request is for a local page
4139
+ Q.loadUrl(callables, Q.extend({
4140
+ // shouldn't need to re-load responseExtras, they're the same across sessions
4141
+ loadExtras: 'session',
4142
+ ignoreHistory: false,
4143
+ onActivate: function () {
4144
+ if (callback) callback();
4145
+ }
4146
+ }, o)).then(function (a) {
4147
+
4148
+ }, function (err) {
4149
+ if (o && o.handleException) {
4150
+ return o.handleException(err);
4151
+ }
4152
+ });
4153
+ } else if (o.externalLoader) {
4154
+ o.externalLoader.apply(this, arguments);
4155
+ } else {
4156
+ root.location = callables;
4157
+ }
4158
+ } else {
4159
+ if (Q.typeOf(o.fields) === 'object') {
4160
+ var method = 'POST';
4161
+ if (o.method) {
4162
+ switch (o.method.toUpperCase()) {
4163
+ case "GET":
4164
+ case "POST":
4165
+ method = o.method;
4166
+ break;
4167
+ default:
4168
+ method = 'POST'; // sadly HTML forms don't support other methods
4169
+ break;
4170
+ }
4171
+ }
4172
+ Q.formPost(callables, o.fields, method, {onLoad: o.callback, target: o.target});
4173
+ } else {
4174
+ if (Q.info && callables === baseUrl) {
4175
+ callables+= '/';
4176
+ }
4177
+ if (!o.target || o.target === true || o.target === '_self') {
4178
+ if (root.location.href == callables) {
4179
+ root.location.reload(true);
4180
+ } else {
4181
+ root.location = callables;
4182
+ }
4183
+ } else {
4184
+ root.open(callables, o.target);
4185
+ }
4186
+ }
4187
+ }
4188
+ Q.handle.onUrl.handle(callables, o);
4189
+ return 1;
4190
+ default:
4191
+ return 0;
4192
+ }
4193
+ } catch (exception) {
4194
+ if (options && options.handleException) {
4195
+ return options.handleException(exception);
4196
+ }
4197
+ throw exception;
4198
+ }
4199
+ };
4200
+ Q.handle.options = {
4201
+ loadUsingAjax: true,
4202
+ externalLoader: null,
4203
+ dontReload: false
4204
+ };
4205
+ Q.handle.onUrl = new Q.Event(function () {
4206
+ var elements = document.getElementsByClassName('Q_error_message');
4207
+ Q.each(elements, function () {
4208
+ Q.removeElement(this, true);
4209
+ });
4210
+ Q.Visual.stopHints();
4211
+ }, "Q");
4212
+
4021
4213
  /**
4022
4214
  * Custom exception constructor
4023
4215
  * @class Q.Exception
@@ -10657,180 +10849,6 @@ Q.loadUrl.request = function (url, slotNames, callback, options) {
10657
10849
 
10658
10850
  Q.loadUrl.loading = {};
10659
10851
 
10660
- /**
10661
- * Used for handling callbacks, whether they come as functions,
10662
- * strings referring to functions (if evaluated), arrays or hashes.
10663
- * @static
10664
- * @method handle
10665
- * @param {Mixed} callables
10666
- * The callables to call
10667
- * Can be a function, array of functions, object of functions, Q.Event or URL
10668
- * If it is a url, simply follow it with options, callback
10669
- * @param {Function} callback
10670
- * You can pass a function here if callables is a URL
10671
- * @param {Object} context
10672
- * The context in which to call them
10673
- * @param {Array} args
10674
- * An array of arguments to pass to them
10675
- * @param {Object} options
10676
- * If callables is a url, these are the options to pass to Q.loadUrl, if any. Also can include:
10677
- * @param {boolean} [options.dontReload=false] if this is true and callback is a url matching current url, it is not reloaded
10678
- * @param {boolean} [options.loadUsingAjax=true] if this is true and callback is a url, it is loaded using Q.loadUrl
10679
- * @param {Function} [options.externalLoader] when using loadUsingAjax, you can set this to a function to suppress loading of external websites with Q.handle.
10680
- * Note: this will still not supress loading of external websites done with other means, such as window.location
10681
- * @param {Object} [options.fields] optional fields to pass with any method other than "get"
10682
- * @param {String|Function} [options.callback] if a string, adds a '&Q.callback='+encodeURIComponent(callback) to the querystring. If a function, this is the callback.
10683
- * @param {String} [options.loadExtras="session"] if "all", asks the server to load the extra scripts, stylesheets, etc. that are loaded on first page load, can also be "response", "initial", "session" or "initial,session"
10684
- * @param {String} [options.target] the name of a window or iframe to use as the target. In this case callables is treated as a url.
10685
- * @param {String|Array} [options.slotNames] a comma-separated list of slot names, or an array of slot names
10686
- * @param {boolean} [options.quiet] defaults to false. If true, allows visual indications that the request is going to take place.
10687
- * @param {Function} [options.handleException] pass a function here to handle thrown exceptions instead of rethrowing them
10688
- * @return {number}
10689
- * The number of handlers executed
10690
- */
10691
- Q.handle = function _Q_handle(callables, /* callback, */ context, args, options) {
10692
- try {
10693
- if (!callables) {
10694
- return 0;
10695
- }
10696
- if (!context) context = root;
10697
- if (!args) args = [];
10698
- var i=0, count=0, k, result;
10699
- if (callables === location) callables = location.href;
10700
- switch (Q.typeOf(callables)) {
10701
- case 'function':
10702
- result = callables.apply(context, args);
10703
- if (result === false) return false;
10704
- return 1;
10705
- case 'array':
10706
- for (i=0; i<callables.length; ++i) {
10707
- result = Q.handle(callables[i], context, args);
10708
- if (result === false) return false;
10709
- count += result;
10710
- }
10711
- return count;
10712
- case 'Q.Event':
10713
- return callables.handle.apply(context, args);
10714
- case 'object':
10715
- for (k in callables) {
10716
- result = Q.handle(callables[k], context, args);
10717
- if (result === false) return false;
10718
- count += result;
10719
- }
10720
- return count;
10721
- case 'string':
10722
- var o = Q.extend({}, Q.handle.options, options);
10723
- if (!callables.isUrl()
10724
- && (callables[0] != '#')
10725
- && (!o.target || o.target.toLowerCase() === '_self')) {
10726
- // Assume this is not a URL.
10727
- // Try to evaluate the expression, and execute the resulting function
10728
- var c = Q.getObject(callables, context) || Q.getObject(callables);
10729
- return Q.handle(c, context, args);
10730
- }
10731
- // Assume callables is a URL
10732
- if (o.dontReload && Q.info && Q.info.url === callables) {
10733
- return 0;
10734
- }
10735
- var callback = null;
10736
- if (typeof arguments[1] === 'function') {
10737
- // Some syntactic sugar: (url, callback) omitting context, args, options
10738
- callback = arguments[1];
10739
- o = Q.handle.options;
10740
- } else if (arguments[1] && (arguments[3] === undefined)) {
10741
- // Some more syntactic sugar: (url, options, callback) omitting context, args, options
10742
- o = Q.extend({}, Q.handle.options, arguments[1]);
10743
- if (typeof arguments[2] === 'function') {
10744
- callback = arguments[2];
10745
- }
10746
- } else {
10747
- o = Q.extend({}, Q.handle.options, options);
10748
- if (o.callback) {
10749
- callback = o.callback;
10750
- }
10751
- }
10752
- var baseUrl = Q.baseUrl();
10753
- var sameDomain = callables.sameDomain(baseUrl);
10754
- if (callables[0] === '#') {
10755
- root.location.hash = callables;
10756
- } else if (o.loadUsingAjax && sameDomain
10757
- && (!o.target || o.target === true || o.target === '_self')) {
10758
- if (callables.search(baseUrl) === 0) {
10759
- // Use AJAX to refresh the page whenever the request is for a local page
10760
- Q.loadUrl(callables, Q.extend({
10761
- // shouldn't need to re-load responseExtras, they're the same across sessions
10762
- loadExtras: 'session',
10763
- ignoreHistory: false,
10764
- onActivate: function () {
10765
- if (callback) callback();
10766
- }
10767
- }, o)).then(function (a) {
10768
-
10769
- }, function (err) {
10770
- if (o && o.handleException) {
10771
- return o.handleException(err);
10772
- }
10773
- });
10774
- } else if (o.externalLoader) {
10775
- o.externalLoader.apply(this, arguments);
10776
- } else {
10777
- root.location = callables;
10778
- }
10779
- } else {
10780
- if (Q.typeOf(o.fields) === 'object') {
10781
- var method = 'POST';
10782
- if (o.method) {
10783
- switch (o.method.toUpperCase()) {
10784
- case "GET":
10785
- case "POST":
10786
- method = o.method;
10787
- break;
10788
- default:
10789
- method = 'POST'; // sadly HTML forms don't support other methods
10790
- break;
10791
- }
10792
- }
10793
- Q.formPost(callables, o.fields, method, {onLoad: o.callback, target: o.target});
10794
- } else {
10795
- if (Q.info && callables === baseUrl) {
10796
- callables+= '/';
10797
- }
10798
- if (!o.target || o.target === true || o.target === '_self') {
10799
- if (root.location.href == callables) {
10800
- root.location.reload(true);
10801
- } else {
10802
- root.location = callables;
10803
- }
10804
- } else {
10805
- root.open(callables, o.target);
10806
- }
10807
- }
10808
- }
10809
- Q.handle.onUrl.handle(callables, o);
10810
- return 1;
10811
- default:
10812
- return 0;
10813
- }
10814
- } catch (exception) {
10815
- if (options && options.handleException) {
10816
- return options.handleException(exception);
10817
- }
10818
- throw exception;
10819
- }
10820
- };
10821
- Q.handle.options = {
10822
- loadUsingAjax: true,
10823
- externalLoader: null,
10824
- dontReload: false
10825
- };
10826
- Q.handle.onUrl = new Q.Event(function () {
10827
- var elements = document.getElementsByClassName('Q_error_message');
10828
- Q.each(elements, function () {
10829
- Q.removeElement(this, true);
10830
- });
10831
- Q.Visual.stopHints();
10832
- }, "Q");
10833
-
10834
10852
  /**
10835
10853
  * Displays a duration
10836
10854
  * @static