Socket
Socket
Sign inDemoInstall

jwidget

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jwidget - npm Package Compare versions

Comparing version 2.0.15 to 2.0.16

11

bindDisplay.d.ts

@@ -6,13 +6,6 @@ /// <reference types="jquery" />

* Watches boolean property modification and updates visibility of the DOM element.
* To make element invisible, sets "display: none" inline style. To make
* element visible, removes "display" inline style. Make sure that element is visible according to your CSS rules.
* Returns [[JW.UI.VisibleUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind element visibility to property value
* this.own(el.jwshow(checked));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="215" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwshow.html"></iframe>
*
* @param el DOM element.
* @param property Element visibility.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindDisplay(el: JQuery, property: Bindable<any>): Destroyable;

@@ -50,12 +50,5 @@ "use strict";

* Watches boolean property modification and updates visibility of the DOM element.
* To make element invisible, sets "display: none" inline style. To make
* element visible, removes "display" inline style. Make sure that element is visible according to your CSS rules.
* Returns [[JW.UI.VisibleUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind element visibility to property value
* this.own(el.jwshow(checked));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="215" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwshow.html"></iframe>
*
* @param el DOM element.
* @param property Element visibility.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -62,0 +55,0 @@ function bindDisplay(el, property) {

9

bindHtml.d.ts

@@ -6,11 +6,6 @@ /// <reference types="jquery" />

* Watches string property modification and updates inner HTML of the DOM element.
* Returns [[JW.UI.HtmlUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner HTML to html property value
* this.own(el.jwhtml(html));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwhtml.html"></iframe>
*
* @param el DOM element.
* @param property HTML value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindHtml(el: JQuery, property: Bindable<any>): Destroyable;

@@ -33,8 +33,2 @@ "use strict";

var Class_1 = require("./Class");
/**
* Result of [[JQuery.jwhtml|jwhtml]] method call. Destroy it to stop synchronization.
*
* Was used as a standalone class before jWidget 1.4.
* As of jWidget 1.4, [[JQuery.jwhtml|jwhtml]] is an easier alternative.
*/
var HtmlUpdater = /** @class */ (function (_super) {

@@ -61,10 +55,5 @@ __extends(HtmlUpdater, _super);

* Watches string property modification and updates inner HTML of the DOM element.
* Returns [[JW.UI.HtmlUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner HTML to html property value
* this.own(el.jwhtml(html));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwhtml.html"></iframe>
*
* @param el DOM element.
* @param property HTML value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -71,0 +60,0 @@ function bindHtml(el, property) {

@@ -8,35 +8,25 @@ /// <reference types="jquery" />

/**
* DOM element property management method.
*
* Returns a boolean property containing current checkbox state and starts watching for its modification.
* Destroy the result property to stop synchronization.
*
* // Watch checkbox state
* var property = this.own(el.jwprop("checked"));
*
* Only "checked" prop is supported.
* @param el DOM element.
* @param prop Element's property name.
* @returns Bound property. You must destroy it to stop the synchronization.
*/
export default function bindProp(el: JQuery, prop: string): DestroyableBindable<boolean>;
/**
* DOM element property management method.
*
* Binds specified property of the DOM element to boolean property and/or vice versa.
* Returns [[JW.UI.PropBinding]] instance. Destroy it to stop synchronization.
*
* // Bind element state to property
* this.own(el.jwprop("disabled", property));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="140" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwprop.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwprop("checked", this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="150" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwprop-two.html"></iframe>
*
* Watches boolean property modification and updates the specified property of the DOM element.
* @param el DOM element.
* @param prop Element's property name.
* @param property Property value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* @param property Property value to assign.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindProp(el: JQuery, prop: string, property: Bindable<any>): Destroyable;
/**
* Watches boolean property modification and updates the specified property of the DOM element and/or vice versa.
* @param el DOM element.
* @param prop Element's property name.
* @param property Property value to read and/or write.
* @param binding Binding direction.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindProp(el: JQuery, prop: string, property: IProperty<boolean>, binding: Binding): Destroyable;

@@ -8,43 +8,24 @@ /// <reference types="jquery" />

/**
* Radio group value management method.
*
* Returns a string property containing current radio group selection and starts watching for selection modification.
* Destroy the result property to stop synchronization.
*
* Notice that the object binds an event listener to a container element and uses bubbling mechanism to detect the
* selection modification. That's why you must avoid bubbling interruption in child elements of the container.
* All radios must have the same "name" attribute value. If neighter radio is selected, property is set to null.
*
* // Watch radio button selection
* var color = this.own(el.jwradio("color"));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="255" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwclass-string.html"></iframe>
*
* @param name Radios "name" attribute.
* Returns a string property containing current radio group selection and starts watching for its modification.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @returns Bound property. You must destroy it to stop the synchronization.
*/
export default function bindRadio(el: JQuery, name: string): DestroyableBindable<string>;
/**
* Radio group value management method.
*
* Binds radio group selection to string property and/or vice versa.
* Returns [[JW.UI.RadioBinding]] instance. Destroy it to stop synchronization.
*
* All radios must have the same "name" attribute value.
*
* // Bind radio button selection to property value
* this.own(el.jwradio("letter", value));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="170" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwradio.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwradio("first", this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="300" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwradio-two.html"></iframe>
*
* @param name Radios "name" attribute.
* @param property Radio value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* Watches string property modification and updates the radio group selection.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @param property Radio button value to select.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindRadio(el: JQuery, name: string, property: Bindable<any>): Destroyable;
/**
* Watches string property modification and updates the radio group selection.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @param property Radio button value to read and/or write.
* @param binding Binding direction.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindRadio(el: JQuery, name: string, property: IProperty<string>, binding?: Binding): Destroyable;

@@ -5,12 +5,7 @@ /// <reference types="jquery" />

/**
* Watches string modification and updates inner text of the DOM element.
* Returns [[JW.UI.TextUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner text to property value
* this.own(el.jwtext(text));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwtext.html"></iframe>
*
* Watches string property modification and updates inner text of the DOM element.
* @param el DOM element.
* @param property Text value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindText(el: JQuery, property: Bindable<any>): Destroyable;

@@ -49,11 +49,6 @@ "use strict";

/**
* Watches string modification and updates inner text of the DOM element.
* Returns [[JW.UI.TextUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner text to property value
* this.own(el.jwtext(text));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwtext.html"></iframe>
*
* Watches string property modification and updates inner text of the DOM element.
* @param el DOM element.
* @param property Text value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -60,0 +55,0 @@ function bindText(el, property) {

@@ -8,37 +8,23 @@ /// <reference types="jquery" />

/**
* DOM element value management method.
*
* Returns a string property containing current element value and starts watching for value modification.
* Destroy the result property to stop synchronization.
*
* // Watch input element value
* var value = this.own(el.jwval());
*
* @param simple If true, listens "change" event only. Defaults to false which enables
* reaction to any real-time field modification.
* Returns a string property containing current DOM element value and starts watching for its modification.
* @param el DOM element.
* @param simple Disable live watch by timer.
* @returns Bound property. You must destroy it to stop the synchronization.
*/
export default function bindVal(el: JQuery, simple?: boolean): DestroyableBindable<string>;
/**
* DOM element value management method.
*
* Binds DOM text input value to string property and/or vice versa.
* Returns [[JW.UI.ValueBinding]] instance. Destroy it to stop synchronization.
*
* // Bind element value to property
* this.own(el.jwval(value));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="285" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwval.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwval(this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="180" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwval-two.html"></iframe>
*
* @param property Element value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* @param simple If true, watch-binding listens "change" event only. Defaults to false which enables
* reaction to any real-time field modification.
* Watches string property modification and updates the DOM element value.
* @param el DOM element.
* @param value Element value to assign.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindVal(el: JQuery, value: Bindable<any>, simple?: boolean): Destroyable;
export default function bindVal(el: JQuery, value: Bindable<any>): Destroyable;
/**
* Watches string property modification and updates the DOM element value and/or vice versa.
* @param el DOM element.
* @param value Element value to read and/or write.
* @param binding Binding direction.
* @param simple Disable live watch by timer.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindVal(el: JQuery, value: IProperty<string>, binding: Binding, simple?: boolean): Destroyable;

@@ -1,25 +0,27 @@

import Property from "./Property";
import IProperty from "./IProperty";
/**
* Current page hash (without leading "#"). As of jWidget 1.4.1, two-way bound to location.hash.
* This is a singleton available as [[hash]].
* Interface of `hash` object. Extension of IProperty<string> interface with `updating` status indicator and
* `replaceState` optional parameter of `set` method.
*/
export declare class Hash extends Property<string> {
private readonly redirectionDetectionInterval;
private readonly redirectionDetectionLimit;
private redirectionStartTime;
private redirectionUrls;
private redirectionLocked;
private _updating;
constructor();
export interface IHash extends IProperty<string> {
/**
* Indicates if hash assignment is in progress at the moment. While `updating` is true, `location.hash`
* gets modified and `changeEvent` gets triggered. Checking this flag in corresponding event handlers may prevent
* infinite loops and unexpected callback conflicts.
*/
readonly updating: boolean;
/**
* Changes current page hash to the specified value.
*
* @param value New page hash value.
* @param replaceState If true, browser history forgets the current state, so that
* "Back" button returns you two steps back instead of one. Useful for automatic page redirections.
* Assigns `location.hash` to a new value and triggers `changeEvent`. Rises `updating` flag to prevent
* infinite loops and callback conflicts during this time.
* @param value New hash value to assign.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
set(value?: string, replaceState?: boolean): void;
set(value: string, replaceState?: boolean): void;
}
declare const hash: Hash;
/**
* Instance of IHash singleton. Provides a transparent Property-compatible interface over `location.hash`
* manipulations. Value of this property is always equal to `location.hash` without leading "#" symbol.
* Has a built-in protection against infinite redirections.
*/
declare const hash: IHash;
export default hash;

@@ -33,6 +33,2 @@ "use strict";

var Property_1 = require("./Property");
/**
* Current page hash (without leading "#"). As of jWidget 1.4.1, two-way bound to location.hash.
* This is a singleton available as [[hash]].
*/
var Hash = /** @class */ (function (_super) {

@@ -48,2 +44,5 @@ __extends(Hash, _super);

_this._updating = false;
if (hash != null) {
throw new Error("Hash is a singleton. Unable to create more instances.");
}
$(window).on("hashchange", function () {

@@ -61,9 +60,2 @@ _this.set(location.hash.substr(1));

});
/**
* Changes current page hash to the specified value.
*
* @param value New page hash value.
* @param replaceState If true, browser history forgets the current state, so that
* "Back" button returns you two steps back instead of one. Useful for automatic page redirections.
*/
Hash.prototype.set = function (value, replaceState) {

@@ -108,5 +100,9 @@ if (value === void 0) { value = ""; }

}(Property_1.default));
exports.Hash = Hash;
/**
* Instance of IHash singleton. Provides a transparent Property-compatible interface over `location.hash`
* manipulations. Value of this property is always equal to `location.hash` without leading "#" symbol.
* Has a built-in protection against infinite redirections.
*/
var hash = new Hash(); // An extra variable helps IntelliSense to find this import
exports.default = hash;
//# sourceMappingURL=hash.js.map
{
"name": "jwidget",
"version": "2.0.15",
"version": "2.0.16",
"description": "Object-oriented FrontEnd MV framework",

@@ -5,0 +5,0 @@ "homepage": "http://enepomnyaschih.github.io/jwidget",

@@ -8,15 +8,36 @@ import Bindable from './Bindable';

/**
* This router can handle complicated router hierarchies (something more than a single stack of routers) in exchange
* for neccessity to specify parent router on creation and base router on redirection explicitly.
*
* Also, it involves a new experimental feature: `arg` is passed to the handler as JW.Property instead of string.
* So, `setPath` methods are not needed anymore: just bind to the `arg`.
* URL router. Converts incoming part of URL (hash) to a target object and passes tail string to it
* for further routing.
*/
declare class Router<T extends Destroyable> extends Class {
/**
* Router name. Must be equal to the route name in the `parent` router. Required for proper `getFullPath` and
* `redirect` method processing. Root router does not have a name.
*/
readonly name: string;
/**
* Parent router. Required for proper `getFullPath` and `redirect` method processing. Root router does not have
* a parent.
*/
readonly parent: Router<any>;
/**
* Path that the router is bound to. Path is a final part of URL (hash) relevant to this
* router. Any path change results in `update` method call.
*/
readonly path: Bindable<string>;
/**
* Path separator function used by the router.
*/
readonly separator: Router.Separator;
/**
* Path joiner function used by the router.
*/
readonly joiner: Router.Joiner;
/**
* Route handler function used by the router.
*/
readonly handler: Router.Handler<T>;
/**
* `separator`, `joiner` and `handler` call scope.
*/
readonly scope: any;

@@ -27,10 +48,50 @@ private _target;

private _updating;
/**
* Creates router instance. Please notice that the router doesn't process current route immediately on
* initialization. To process the route, call `update` method.
* @param config Router configuration.
*/
constructor(config?: Router.Config<T>);
/**
* Router target. Main purpose of the router is to convert `path` to `target`. In particular, UIRouter
* creates Component instances based on current `path` value so you could render them.
*/
readonly target: Bindable<T>;
/**
* Current route. First chunk of the path detected by `separator` function. You can watch this property
* to activate and deactivate items in your menu.
*/
readonly route: Bindable<string>;
/**
* Remainder of current route after `separator` function call. This property is passed to `handler`
* function and can be passed over to child components for further routing.
*/
readonly arg: Bindable<string>;
/**
* @inheritDoc
*/
destroyObject(): void;
/**
* Issues route processing.
*/
update(): void;
/**
* Returns the result of `joiner` function call for this router.
* @param route Route name.
* @param arg Remainder of the path.
* @returns Full path.
*/
join(route: string, arg: string): string;
/**
* Returns full path as the result of `joiner` function call in `parent` router with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to this router.
* @returns Full path relative to the root router.
*/
getFullPath(path: string): string;
/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path)`.
* @param path Path relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
redirect(path: string, replaceState?: boolean): void;

@@ -40,36 +101,122 @@ }

declare namespace Router {
const defaultSeparator: RegExp;
const defaultJoiner = "/";
/**
* Default value of `separator`.
*/
const DEFAULT_SEPARATOR: RegExp;
/**
* Default value of `joiner`.
*/
const DEFAULT_JOINER = "/";
/**
* Signature of `separator` function. The function splits path to route and argument. Therefore, it must
* return two string values. If function returns null, it is assumed to be ["", null].
*/
interface Separator {
/**
* @param path Full path.
* @returns Route and argument.
*/
(path: string): string[];
}
/**
* Signature of `joiner` function. The function joins route and argument to a path.
*/
interface Joiner {
/**
* @param route Route.
* @param arg Argument.
* @returns Full path.
*/
(route: string, arg: string): string;
}
/**
* Signature of `handler` general-purpose function. The function maps the specified route to a target object
* (usually, Component) and passes argument to it for further routing.
*/
interface Handler<T> {
/**
* @param route Route.
* @param arg Argument.
* @returns Target object.
*/
(route: string, arg: Bindable<string>): T;
}
/**
* Signature of a single route in `handler` object. The function maps a single route to a target
* object (usually, Component) and passes argument to it for further routing.
*/
interface Route<T> {
/**
* @param arg Argument.
* @returns Target object.
*/
(arg: Bindable<string>): T;
}
/**
* Router handler configuration object.
*/
interface HandlerConfig<T> {
routes?: Dictionary<Route<T>>;
notFound?: Handler<T>;
/**
* Map of specific route handlers. If current route is present in this dictionary, the router calls its
* corresponding handler and passes argument to it. Route and argument themselves are computed with `separator`
* callback.
*/
readonly routes?: Dictionary<Route<T>>;
/**
* If none of the `routes` matches current route, the router calls this handler callback and passes both
* route and argument to it. By default, returns null for any input.
*/
readonly notFound?: Handler<T>;
}
/**
* Router configuration object.
*/
interface Config<T> {
/**
* Router name. Router name is a chunk of the path that caused this route to get initialized. Root router
* doesn't have a name.
*/
readonly name?: string;
/**
* Parent router. It provides `getFullPath` and `redirect` with a clue about all parts of the path. If
* your router provides you with wrong paths, check `name` and `parent` of all routers in your hierarchy - they
* are likely assigned to wrong values. Root router doesn't have a parent.
*/
readonly parent?: Router<any>;
/**
* Path to bind the router to. Root router should usually get bound to `hash` property. Child routers should
* receive `path` from their parents.
*/
readonly path?: Bindable<string>;
/**
* Target property. Router puts the result of `handler` function call to target property. If `target` is
* omitted, the router creates it automatically. Router automatically controls the life time of your targets,
* so, if you pass your precreated `target` property to a Router, make sure that it is not aggregating its value,
* i.e. `ownValue` method is not called.
*/
readonly target?: IProperty<T>;
/**
* Path separator function. Parses incoming path to two tokens: route and argument. Route gets used to
* process a single routing step and create a target, argument gets passed to the target for further routing.
*/
readonly separator?: Separator | RegExp;
/**
* Path joiner. Opposite to `separator`. Used in `getFullPath` and `redirect` methods to properly build the
* path. Joins incoming route and argument to a full path.
*/
readonly joiner?: Joiner | string;
/**
* Route handler. Maps the route string to a target object and passes argument to it for further routing.
*/
readonly handler?: Handler<T> | HandlerConfig<T>;
/**
* `separator`, `joiner` and `handler` call scope.
*/
readonly scope?: any;
}
/**
* Converts RegExp to separator function. The first token ($1) of path is used as a
* route, and the next non-null token ($2-...) is used as an argument.
* If path is null, it is assumed to be "".
*
* @param regexp Regular expression.
* If `separator` is a function, returns it immediately. Else converts the specified regular expression to
* a function by the following rule: The first token ($1) of path is used as a route, and the next non-null token
* ($2 or further) is used as an argument. If path is null, it is assumed to be "".
* @param separator Function or regular expression.
* @returns Separator function.

@@ -79,21 +226,7 @@ */

/**
* Converts joiner symbol/string to joiner function. Joins incoming route/argument pair via the specified string.
* Leading joiner symbols in argument are trimmed. If argument starts with "?", joiner symbol is not added.
* If argument is null or blank, returns route.
*
* Examples:
*
* <table>
* <tr><td>Incoming route</td><td>Incoming argument</td><td>Separator</td><td>Resulting path</td></tr>
* <tr><td>""</td><td>""</td><td>"/"</td><td>""</td></tr>
* <tr><td>"inbox"</td><td>""</td><td>"/"</td><td>"inbox"</td></tr>
* <tr><td>"inbox"</td><td>"1"</td><td>"/"</td><td>"inbox/1"</td></tr>
* <tr><td>"inbox"</td><td>"1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply/"</td><td>"/"</td><td>"inbox/1/reply/"</td></tr>
* <tr><td>"inbox"</td><td>"///1/reply///"</td><td>"/"</td><td>"inbox/1/reply///"</td></tr>
* <tr><td>"inbox"</td><td>"?id=1"</td><td>"/"</td><td>"inbox?id=1"</td></tr>
* </table>
*
* @param joiner Joiner symbol/string.
* If `joiner` is a function, returns it immediately. Else converts the specified string to a function by the
* following rule: joins incoming route/argument pair via the specified string. Leading joiner symbols in argument
* are trimmed. If argument starts with "?", joiner symbol is not added. If argument is null or blank, returns
* route.
* @param joiner Function or separation character.
* @returns Joiner function.

@@ -103,24 +236,3 @@ */

/**
* Converts handler configuration object to handler function. Configuration has two optional fields:
*
* - [[RouteMap.routes|routes]] is a mapping from route string to a handler function for
* this specific route. The function takes the path argument as an argument.
* - [[RouteMap.notFound|notFound]] is a handler function for all routes which don't
* match [[RouteMap.routes|routes]] mapping. The function takes route and path argument as
* arguments.
*
* Example:
*
* this.router = this.own(new JW.Plugins.Router({
* path: JW.UI.hash,
* handler: {
* routes: {
* "inbox" : function(arg) { return new Inbox(arg); },
* "" : function(arg) { return new JW.UI.Component(); }
* },
* notFound: function(route, arg) { return new NotFound(route, arg); }
* },
* scope: this
* }));
*
* If handler is a function, returns it immediately. Else converts the specified object to a function.
* @param handler Handler configuration object.

@@ -130,5 +242,20 @@ * @returns Handler function.

function makeHandler<T>(handler?: Handler<T> | HandlerConfig<T>): Handler<T>;
function getFullPath(path: string, router: Router<any>): string;
function redirect(path: string, router: Router<any>, replaceState?: boolean): void;
function bindRouting(component: any, path: Bindable<string>): Destroyable;
/**
* Returns full path as the result of `joiner` function call in `parent` of `router` with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to `router`.
* @param router Compute full path relative to this router.
* @returns Full path relative to the `router`.
*/
function getFullPath(path: string, router?: Router<any>): string;
/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path, router)`.
* @param path Path relative to `router`.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
function redirect(path: string, router?: Router<any>, replaceState?: boolean): void;
/**
* Recommended way to perform an asyncronous redirection in Router `handler` function.
*/
class Redirector extends Component {

@@ -138,3 +265,10 @@ private path;

private replaceState;
constructor(path: string, router: Router<any>, replaceState?: boolean);
/**
* Creates a new redirector.
* @param path Path relative to router.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the
* stack. Defaults to true.
*/
constructor(path: string, router?: Router<any>, replaceState?: boolean);
}

@@ -147,15 +281,3 @@ /**

*
* The logic is very similar to FE.CD.UI.Panel.List's routing, but it has some differences in API:
*
* * Node route array is constant whereas Panel.List may have variable set of panels;
* * In exchange, Panel.List requires all children to be AbstractPanels which requires some additional
* configuration. Also, the panels must be initialized in advance, but not to be rendered yet at the moment
* of router initialization.
*
* Configuration:
*
* * name, parentRouter, path - See FE.Lib.Multirouter;
* * routes: String[] - All possible routes;
* * defaultRoute?: String - Default route to redirect the router to (optional);
* * expanded?: Boolean | String[] - Panels to expand by default. Set to true to expand all panels.
* This allows you to render your content as a fixed list of panels representing the concurrent routes.
*/

@@ -167,15 +289,57 @@ class Node extends Class {

private _updating;
/**
* Default route this node was initialized with.
*/
readonly defaultRoute: string;
/**
* Router that manages this node. Node creates this router automatically. You should pass this router to
* child components as their parent router for further routing.
*/
readonly router: Router<Destroyable>;
/**
* Creates router node, assigns its properties to initial values and starts synchronization.
* @param config Node configuration.
*/
constructor(config: Node.Config);
/**
* Provides paths to bind child routers to, by name. Only one route is active at a time, but their paths
* always exist regardless of their activity.
*/
readonly paths: Dictionary<Bindable<string>>;
readonly expanded: Dictionary<Bindable<boolean>>;
/**
* Provides "expanded" flags to bind child panels to, by name. Support two-way binding.
*/
readonly expanded: Dictionary<IProperty<boolean>>;
}
namespace Node {
/**
* Router.Node configuration.
*/
interface Config {
/**
* Router name.
*/
readonly name?: string;
/**
* Parent router.
*/
readonly parent?: Router<any>;
/**
* Path to bind the router to.
*/
readonly path?: Bindable<string>;
/**
* Fixed list of routes to manage by this node. For every name in this list, corresponding properties will be
* created in `paths` and `expanded` dictionaries of the node.
*/
readonly routes: string[];
/**
* Initial "expanded" status of routes or initial routes to expand. Defaults to false (all routes are
* collapsed).
*/
readonly expanded?: boolean | string[];
/**
* Default route. If the initial path is blank (""), the router performs a redirection to this route, i.e.
* expands one of the panels. Doesn't work after initialization.
*/
readonly defaultRoute?: string;

@@ -182,0 +346,0 @@ }

@@ -43,10 +43,12 @@ "use strict";

/**
* This router can handle complicated router hierarchies (something more than a single stack of routers) in exchange
* for neccessity to specify parent router on creation and base router on redirection explicitly.
*
* Also, it involves a new experimental feature: `arg` is passed to the handler as JW.Property instead of string.
* So, `setPath` methods are not needed anymore: just bind to the `arg`.
* URL router. Converts incoming part of URL (hash) to a target object and passes tail string to it
* for further routing.
*/
var Router = /** @class */ (function (_super) {
__extends(Router, _super);
/**
* Creates router instance. Please notice that the router doesn't process current route immediately on
* initialization. To process the route, call `update` method.
* @param config Router configuration.
*/
function Router(config) {

@@ -73,2 +75,6 @@ if (config === void 0) { config = {}; }

Object.defineProperty(Router.prototype, "target", {
/**
* Router target. Main purpose of the router is to convert `path` to `target`. In particular, UIRouter
* creates Component instances based on current `path` value so you could render them.
*/
get: function () {

@@ -81,2 +87,6 @@ return this._target;

Object.defineProperty(Router.prototype, "route", {
/**
* Current route. First chunk of the path detected by `separator` function. You can watch this property
* to activate and deactivate items in your menu.
*/
get: function () {

@@ -89,2 +99,6 @@ return this._route;

Object.defineProperty(Router.prototype, "arg", {
/**
* Remainder of current route after `separator` function call. This property is passed to `handler`
* function and can be passed over to child components for further routing.
*/
get: function () {

@@ -96,2 +110,5 @@ return this._arg;

});
/**
* @inheritDoc
*/
Router.prototype.destroyObject = function () {

@@ -108,2 +125,5 @@ if (this._updating) {

};
/**
* Issues route processing.
*/
Router.prototype.update = function () {

@@ -134,8 +154,25 @@ if (this._updating) {

};
/**
* Returns the result of `joiner` function call for this router.
* @param route Route name.
* @param arg Remainder of the path.
* @returns Full path.
*/
Router.prototype.join = function (route, arg) {
return this.joiner.call(this.scope, route, arg);
};
/**
* Returns full path as the result of `joiner` function call in `parent` router with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to this router.
* @returns Full path relative to the root router.
*/
Router.prototype.getFullPath = function (path) {
return this.parent ? this.parent.getFullPath(this.parent.join(this.name, path)) : path;
};
/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path)`.
* @param path Path relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
Router.prototype.redirect = function (path, replaceState) {

@@ -148,14 +185,19 @@ Router.redirect(path, this, replaceState);

(function (Router) {
Router.defaultSeparator = /^\/*([^?\/]+)(?:\/(.*)|(\?.*))?$/;
Router.defaultJoiner = "/";
/**
* Converts RegExp to separator function. The first token ($1) of path is used as a
* route, and the next non-null token ($2-...) is used as an argument.
* If path is null, it is assumed to be "".
*
* @param regexp Regular expression.
* Default value of `separator`.
*/
Router.DEFAULT_SEPARATOR = /^\/*([^?\/]+)(?:\/(.*)|(\?.*))?$/;
/**
* Default value of `joiner`.
*/
Router.DEFAULT_JOINER = "/";
/**
* If `separator` is a function, returns it immediately. Else converts the specified regular expression to
* a function by the following rule: The first token ($1) of path is used as a route, and the next non-null token
* ($2 or further) is used as an argument. If path is null, it is assumed to be "".
* @param separator Function or regular expression.
* @returns Separator function.
*/
function makeSeparator(separator) {
if (separator === void 0) { separator = Router.defaultSeparator; }
if (separator === void 0) { separator = Router.DEFAULT_SEPARATOR; }
if (typeof separator === "function") {

@@ -171,25 +213,11 @@ return separator;

/**
* Converts joiner symbol/string to joiner function. Joins incoming route/argument pair via the specified string.
* Leading joiner symbols in argument are trimmed. If argument starts with "?", joiner symbol is not added.
* If argument is null or blank, returns route.
*
* Examples:
*
* <table>
* <tr><td>Incoming route</td><td>Incoming argument</td><td>Separator</td><td>Resulting path</td></tr>
* <tr><td>""</td><td>""</td><td>"/"</td><td>""</td></tr>
* <tr><td>"inbox"</td><td>""</td><td>"/"</td><td>"inbox"</td></tr>
* <tr><td>"inbox"</td><td>"1"</td><td>"/"</td><td>"inbox/1"</td></tr>
* <tr><td>"inbox"</td><td>"1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply/"</td><td>"/"</td><td>"inbox/1/reply/"</td></tr>
* <tr><td>"inbox"</td><td>"///1/reply///"</td><td>"/"</td><td>"inbox/1/reply///"</td></tr>
* <tr><td>"inbox"</td><td>"?id=1"</td><td>"/"</td><td>"inbox?id=1"</td></tr>
* </table>
*
* @param joiner Joiner symbol/string.
* If `joiner` is a function, returns it immediately. Else converts the specified string to a function by the
* following rule: joins incoming route/argument pair via the specified string. Leading joiner symbols in argument
* are trimmed. If argument starts with "?", joiner symbol is not added. If argument is null or blank, returns
* route.
* @param joiner Function or separation character.
* @returns Joiner function.
*/
function makeJoiner(joiner) {
if (joiner === void 0) { joiner = Router.defaultJoiner; }
if (joiner === void 0) { joiner = Router.DEFAULT_JOINER; }
if (typeof joiner === "function") {

@@ -205,24 +233,3 @@ return joiner;

/**
* Converts handler configuration object to handler function. Configuration has two optional fields:
*
* - [[RouteMap.routes|routes]] is a mapping from route string to a handler function for
* this specific route. The function takes the path argument as an argument.
* - [[RouteMap.notFound|notFound]] is a handler function for all routes which don't
* match [[RouteMap.routes|routes]] mapping. The function takes route and path argument as
* arguments.
*
* Example:
*
* this.router = this.own(new JW.Plugins.Router({
* path: JW.UI.hash,
* handler: {
* routes: {
* "inbox" : function(arg) { return new Inbox(arg); },
* "" : function(arg) { return new JW.UI.Component(); }
* },
* notFound: function(route, arg) { return new NotFound(route, arg); }
* },
* scope: this
* }));
*
* If handler is a function, returns it immediately. Else converts the specified object to a function.
* @param handler Handler configuration object.

@@ -243,2 +250,9 @@ * @returns Handler function.

Router.makeHandler = makeHandler;
/**
* Returns full path as the result of `joiner` function call in `parent` of `router` with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to `router`.
* @param router Compute full path relative to this router.
* @returns Full path relative to the `router`.
*/
function getFullPath(path, router) {

@@ -248,2 +262,8 @@ return router ? router.getFullPath(path) : path;

Router.getFullPath = getFullPath;
/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path, router)`.
* @param path Path relative to `router`.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
function redirect(path, router, replaceState) {

@@ -263,10 +283,14 @@ try {

Router.redirect = redirect;
function bindRouting(component, path) {
return !component ? null :
component.bindRouting ? component.bindRouting(path) :
component.path ? new Copier_1.default(path, component.path) : null;
}
Router.bindRouting = bindRouting;
/**
* Recommended way to perform an asyncronous redirection in Router `handler` function.
*/
var Redirector = /** @class */ (function (_super) {
__extends(Redirector, _super);
/**
* Creates a new redirector.
* @param path Path relative to router.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the
* stack. Defaults to true.
*/
function Redirector(path, router, replaceState) {

@@ -291,18 +315,10 @@ var _this = _super.call(this) || this;

*
* The logic is very similar to FE.CD.UI.Panel.List's routing, but it has some differences in API:
*
* * Node route array is constant whereas Panel.List may have variable set of panels;
* * In exchange, Panel.List requires all children to be AbstractPanels which requires some additional
* configuration. Also, the panels must be initialized in advance, but not to be rendered yet at the moment
* of router initialization.
*
* Configuration:
*
* * name, parentRouter, path - See FE.Lib.Multirouter;
* * routes: String[] - All possible routes;
* * defaultRoute?: String - Default route to redirect the router to (optional);
* * expanded?: Boolean | String[] - Panels to expand by default. Set to true to expand all panels.
* This allows you to render your content as a fixed list of panels representing the concurrent routes.
*/
var Node = /** @class */ (function (_super) {
__extends(Node, _super);
/**
* Creates router node, assigns its properties to initial values and starts synchronization.
* @param config Node configuration.
*/
function Node(config) {

@@ -349,2 +365,6 @@ var _this = _super.call(this) || this;

Object.defineProperty(Node.prototype, "paths", {
/**
* Provides paths to bind child routers to, by name. Only one route is active at a time, but their paths
* always exist regardless of their activity.
*/
get: function () {

@@ -357,2 +377,5 @@ return this._paths;

Object.defineProperty(Node.prototype, "expanded", {
/**
* Provides "expanded" flags to bind child panels to, by name. Support two-way binding.
*/
get: function () {

@@ -359,0 +382,0 @@ return this._expanded;

@@ -39,12 +39,5 @@ /*

* Watches boolean property modification and updates visibility of the DOM element.
* To make element invisible, sets "display: none" inline style. To make
* element visible, removes "display" inline style. Make sure that element is visible according to your CSS rules.
* Returns [[JW.UI.VisibleUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind element visibility to property value
* this.own(el.jwshow(checked));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="215" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwshow.html"></iframe>
*
* @param el DOM element.
* @param property Element visibility.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -51,0 +44,0 @@ export default function bindDisplay(el: JQuery, property: Bindable<any>): Destroyable {

@@ -25,8 +25,2 @@ /*

/**
* Result of [[JQuery.jwhtml|jwhtml]] method call. Destroy it to stop synchronization.
*
* Was used as a standalone class before jWidget 1.4.
* As of jWidget 1.4, [[JQuery.jwhtml|jwhtml]] is an easier alternative.
*/
class HtmlUpdater extends Class {

@@ -50,10 +44,5 @@ /**

* Watches string property modification and updates inner HTML of the DOM element.
* Returns [[JW.UI.HtmlUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner HTML to html property value
* this.own(el.jwhtml(html));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwhtml.html"></iframe>
*
* @param el DOM element.
* @param property HTML value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -60,0 +49,0 @@ export default function bindHtml(el: JQuery, property: Bindable<any>): Destroyable {

@@ -91,11 +91,7 @@ /*

/**
* DOM element property management method.
*
* Returns a boolean property containing current checkbox state and starts watching for its modification.
* Destroy the result property to stop synchronization.
*
* // Watch checkbox state
* var property = this.own(el.jwprop("checked"));
*
* Only "checked" prop is supported.
* @param el DOM element.
* @param prop Element's property name.
* @returns Bound property. You must destroy it to stop the synchronization.
*/

@@ -105,23 +101,18 @@ export default function bindProp(el: JQuery, prop: string): DestroyableBindable<boolean>;

/**
* DOM element property management method.
*
* Binds specified property of the DOM element to boolean property and/or vice versa.
* Returns [[JW.UI.PropBinding]] instance. Destroy it to stop synchronization.
*
* // Bind element state to property
* this.own(el.jwprop("disabled", property));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="140" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwprop.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwprop("checked", this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="150" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwprop-two.html"></iframe>
*
* Watches boolean property modification and updates the specified property of the DOM element.
* @param el DOM element.
* @param prop Element's property name.
* @param property Property value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* @param property Property value to assign.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindProp(el: JQuery, prop: string, property: Bindable<any>): Destroyable;
/**
* Watches boolean property modification and updates the specified property of the DOM element and/or vice versa.
* @param el DOM element.
* @param prop Element's property name.
* @param property Property value to read and/or write.
* @param binding Binding direction.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindProp(el: JQuery, prop: string, property: IProperty<boolean>, binding: Binding): Destroyable;

@@ -128,0 +119,0 @@ export default function bindProp(el: JQuery, prop: string, property?: any, binding?: Binding): Destroyable {

@@ -102,17 +102,6 @@ /*

/**
* Radio group value management method.
*
* Returns a string property containing current radio group selection and starts watching for selection modification.
* Destroy the result property to stop synchronization.
*
* Notice that the object binds an event listener to a container element and uses bubbling mechanism to detect the
* selection modification. That's why you must avoid bubbling interruption in child elements of the container.
* All radios must have the same "name" attribute value. If neighter radio is selected, property is set to null.
*
* // Watch radio button selection
* var color = this.own(el.jwradio("color"));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="255" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwclass-string.html"></iframe>
*
* @param name Radios "name" attribute.
* Returns a string property containing current radio group selection and starts watching for its modification.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @returns Bound property. You must destroy it to stop the synchronization.
*/

@@ -122,25 +111,18 @@ export default function bindRadio(el: JQuery, name: string): DestroyableBindable<string>;

/**
* Radio group value management method.
*
* Binds radio group selection to string property and/or vice versa.
* Returns [[JW.UI.RadioBinding]] instance. Destroy it to stop synchronization.
*
* All radios must have the same "name" attribute value.
*
* // Bind radio button selection to property value
* this.own(el.jwradio("letter", value));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="170" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwradio.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwradio("first", this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="300" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwradio-two.html"></iframe>
*
* @param name Radios "name" attribute.
* @param property Radio value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* Watches string property modification and updates the radio group selection.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @param property Radio button value to select.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindRadio(el: JQuery, name: string, property: Bindable<any>): Destroyable;
/**
* Watches string property modification and updates the radio group selection.
* @param el DOM element.
* @param name Value of "name" attribute in radio button elements.
* @param property Radio button value to read and/or write.
* @param binding Binding direction.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindRadio(el: JQuery, name: string, property: IProperty<string>, binding?: Binding): Destroyable;

@@ -147,0 +129,0 @@ export default function bindRadio(el: JQuery, name: string, property?: any, binding?: Binding): Destroyable {

@@ -38,11 +38,6 @@ /*

/**
* Watches string modification and updates inner text of the DOM element.
* Returns [[JW.UI.TextUpdater]] instance. Destroy it to stop synchronization.
*
* // Bind inner text to property value
* this.own(el.jwtext(text));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="220" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwtext.html"></iframe>
*
* Watches string property modification and updates inner text of the DOM element.
* @param el DOM element.
* @param property Text value.
* @returns Binding object. You must destroy it to stop the synchronization.
*/

@@ -49,0 +44,0 @@ export default function bindText(el: JQuery, property: Bindable<any>): Destroyable {

@@ -31,3 +31,3 @@ /*

class ValueBinding extends Class {
constructor(el: JQuery, property: Bindable<any>, simple?: boolean);
constructor(el: JQuery, property: Bindable<any>);
constructor(el: JQuery, property: IProperty<string>, binding: Binding, simple?: boolean);

@@ -104,12 +104,6 @@ constructor(el: JQuery, property: any, binding: any = UPDATE, simple?: boolean) {

/**
* DOM element value management method.
*
* Returns a string property containing current element value and starts watching for value modification.
* Destroy the result property to stop synchronization.
*
* // Watch input element value
* var value = this.own(el.jwval());
*
* @param simple If true, listens "change" event only. Defaults to false which enables
* reaction to any real-time field modification.
* Returns a string property containing current DOM element value and starts watching for its modification.
* @param el DOM element.
* @param simple Disable live watch by timer.
* @returns Bound property. You must destroy it to stop the synchronization.
*/

@@ -119,24 +113,17 @@ export default function bindVal(el: JQuery, simple?: boolean): DestroyableBindable<string>;

/**
* DOM element value management method.
*
* Binds DOM text input value to string property and/or vice versa.
* Returns [[JW.UI.ValueBinding]] instance. Destroy it to stop synchronization.
*
* // Bind element value to property
* this.own(el.jwval(value));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="285" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwval.html"></iframe>
*
* Two way binding:
*
* this.own(el.jwval(this.value, JW.TWOWAY));
*
* <iframe style="border: 1px solid green; padding: 10px;" width="730" height="180" src="http://enepomnyaschih.github.io/mt/1.4/jwui-property-jwval-two.html"></iframe>
*
* @param property Element value.
* @param binding Binding mode. Defaults to [[JW.Binding.UPDATE]].
* @param simple If true, watch-binding listens "change" event only. Defaults to false which enables
* reaction to any real-time field modification.
* Watches string property modification and updates the DOM element value.
* @param el DOM element.
* @param value Element value to assign.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindVal(el: JQuery, value: Bindable<any>, simple?: boolean): Destroyable;
export default function bindVal(el: JQuery, value: Bindable<any>): Destroyable;
/**
* Watches string property modification and updates the DOM element value and/or vice versa.
* @param el DOM element.
* @param value Element value to read and/or write.
* @param binding Binding direction.
* @param simple Disable live watch by timer.
* @returns Binding object. You must destroy it to stop the synchronization.
*/
export default function bindVal(el: JQuery, value: IProperty<string>, binding: Binding, simple?: boolean): Destroyable;

@@ -143,0 +130,0 @@ export default function bindVal(el: JQuery, value: any, binding?: any, simple?: any): Destroyable {

@@ -21,9 +21,29 @@ /*

import IProperty from "./IProperty";
import Property from "./Property";
/**
* Current page hash (without leading "#"). As of jWidget 1.4.1, two-way bound to location.hash.
* This is a singleton available as [[hash]].
* Interface of `hash` object. Extension of IProperty<string> interface with `updating` status indicator and
* `replaceState` optional parameter of `set` method.
*/
export class Hash extends Property<string> {
export interface IHash extends IProperty<string> {
/**
* Indicates if hash assignment is in progress at the moment. While `updating` is true, `location.hash`
* gets modified and `changeEvent` gets triggered. Checking this flag in corresponding event handlers may prevent
* infinite loops and unexpected callback conflicts.
*/
readonly updating: boolean;
/**
* Assigns `location.hash` to a new value and triggers `changeEvent`. Rises `updating` flag to prevent
* infinite loops and callback conflicts during this time.
* @param value New hash value to assign.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
set(value: string, replaceState?: boolean): void;
}
class Hash extends Property<string> implements IHash {
private readonly redirectionDetectionInterval = 1000;

@@ -40,2 +60,5 @@ private readonly redirectionDetectionLimit = 25;

super(location.hash.substr(1));
if (hash != null) {
throw new Error("Hash is a singleton. Unable to create more instances.")
}
$(window).on("hashchange", () => {

@@ -50,9 +73,2 @@ this.set(location.hash.substr(1));

/**
* Changes current page hash to the specified value.
*
* @param value New page hash value.
* @param replaceState If true, browser history forgets the current state, so that
* "Back" button returns you two steps back instead of one. Useful for automatic page redirections.
*/
set(value: string = "", replaceState?: boolean) {

@@ -96,3 +112,8 @@ if (this.redirectionLocked) {

const hash = new Hash(); // An extra variable helps IntelliSense to find this import
/**
* Instance of IHash singleton. Provides a transparent Property-compatible interface over `location.hash`
* manipulations. Value of this property is always equal to `location.hash` without leading "#" symbol.
* Has a built-in protection against infinite redirections.
*/
const hash: IHash = new Hash(); // An extra variable helps IntelliSense to find this import
export default hash;

@@ -37,15 +37,43 @@ /*

/**
* This router can handle complicated router hierarchies (something more than a single stack of routers) in exchange
* for neccessity to specify parent router on creation and base router on redirection explicitly.
*
* Also, it involves a new experimental feature: `arg` is passed to the handler as JW.Property instead of string.
* So, `setPath` methods are not needed anymore: just bind to the `arg`.
* URL router. Converts incoming part of URL (hash) to a target object and passes tail string to it
* for further routing.
*/
class Router<T extends Destroyable> extends Class {
/**
* Router name. Must be equal to the route name in the `parent` router. Required for proper `getFullPath` and
* `redirect` method processing. Root router does not have a name.
*/
readonly name: string;
/**
* Parent router. Required for proper `getFullPath` and `redirect` method processing. Root router does not have
* a parent.
*/
readonly parent: Router<any>;
/**
* Path that the router is bound to. Path is a final part of URL (hash) relevant to this
* router. Any path change results in `update` method call.
*/
readonly path: Bindable<string>;
/**
* Path separator function used by the router.
*/
readonly separator: Router.Separator;
/**
* Path joiner function used by the router.
*/
readonly joiner: Router.Joiner;
/**
* Route handler function used by the router.
*/
readonly handler: Router.Handler<T>;
/**
* `separator`, `joiner` and `handler` call scope.
*/
readonly scope: any;

@@ -58,2 +86,7 @@

/**
* Creates router instance. Please notice that the router doesn't process current route immediately on
* initialization. To process the route, call `update` method.
* @param config Router configuration.
*/
constructor(config: Router.Config<T> = {}) {

@@ -75,2 +108,6 @@ super();

/**
* Router target. Main purpose of the router is to convert `path` to `target`. In particular, UIRouter
* creates Component instances based on current `path` value so you could render them.
*/
get target(): Bindable<T> {

@@ -80,2 +117,6 @@ return this._target;

/**
* Current route. First chunk of the path detected by `separator` function. You can watch this property
* to activate and deactivate items in your menu.
*/
get route(): Bindable<string> {

@@ -85,2 +126,6 @@ return this._route;

/**
* Remainder of current route after `separator` function call. This property is passed to `handler`
* function and can be passed over to child components for further routing.
*/
get arg(): Bindable<string> {

@@ -90,2 +135,5 @@ return this._arg;

/**
* @inheritDoc
*/
destroyObject() {

@@ -103,2 +151,5 @@ if (this._updating) {

/**
* Issues route processing.
*/
update() {

@@ -129,2 +180,8 @@ if (this._updating) {

/**
* Returns the result of `joiner` function call for this router.
* @param route Route name.
* @param arg Remainder of the path.
* @returns Full path.
*/
join(route: string, arg: string): string {

@@ -134,2 +191,8 @@ return this.joiner.call(this.scope, route, arg);

/**
* Returns full path as the result of `joiner` function call in `parent` router with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to this router.
* @returns Full path relative to the root router.
*/
getFullPath(path: string): string {

@@ -139,2 +202,7 @@ return this.parent ? this.parent.getFullPath(this.parent.join(this.name, path)) : path;

/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path)`.
* @param path Path relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
redirect(path: string, replaceState?: boolean) {

@@ -148,34 +216,130 @@ Router.redirect(path, this, replaceState);

namespace Router {
export const defaultSeparator = /^\/*([^?\/]+)(?:\/(.*)|(\?.*))?$/;
export const defaultJoiner = "/";
/**
* Default value of `separator`.
*/
export const DEFAULT_SEPARATOR = /^\/*([^?\/]+)(?:\/(.*)|(\?.*))?$/;
/**
* Default value of `joiner`.
*/
export const DEFAULT_JOINER = "/";
/**
* Signature of `separator` function. The function splits path to route and argument. Therefore, it must
* return two string values. If function returns null, it is assumed to be ["", null].
*/
export interface Separator {
/**
* @param path Full path.
* @returns Route and argument.
*/
(path: string): string[];
}
/**
* Signature of `joiner` function. The function joins route and argument to a path.
*/
export interface Joiner {
/**
* @param route Route.
* @param arg Argument.
* @returns Full path.
*/
(route: string, arg: string): string;
}
/**
* Signature of `handler` general-purpose function. The function maps the specified route to a target object
* (usually, Component) and passes argument to it for further routing.
*/
export interface Handler<T> {
/**
* @param route Route.
* @param arg Argument.
* @returns Target object.
*/
(route: string, arg: Bindable<string>): T;
}
/**
* Signature of a single route in `handler` object. The function maps a single route to a target
* object (usually, Component) and passes argument to it for further routing.
*/
export interface Route<T> {
/**
* @param arg Argument.
* @returns Target object.
*/
(arg: Bindable<string>): T;
}
/**
* Router handler configuration object.
*/
export interface HandlerConfig<T> {
routes?: Dictionary<Route<T>>;
notFound?: Handler<T>;
/**
* Map of specific route handlers. If current route is present in this dictionary, the router calls its
* corresponding handler and passes argument to it. Route and argument themselves are computed with `separator`
* callback.
*/
readonly routes?: Dictionary<Route<T>>;
/**
* If none of the `routes` matches current route, the router calls this handler callback and passes both
* route and argument to it. By default, returns null for any input.
*/
readonly notFound?: Handler<T>;
}
/**
* Router configuration object.
*/
export interface Config<T> {
/**
* Router name. Router name is a chunk of the path that caused this route to get initialized. Root router
* doesn't have a name.
*/
readonly name?: string;
/**
* Parent router. It provides `getFullPath` and `redirect` with a clue about all parts of the path. If
* your router provides you with wrong paths, check `name` and `parent` of all routers in your hierarchy - they
* are likely assigned to wrong values. Root router doesn't have a parent.
*/
readonly parent?: Router<any>;
/**
* Path to bind the router to. Root router should usually get bound to `hash` property. Child routers should
* receive `path` from their parents.
*/
readonly path?: Bindable<string>;
/**
* Target property. Router puts the result of `handler` function call to target property. If `target` is
* omitted, the router creates it automatically. Router automatically controls the life time of your targets,
* so, if you pass your precreated `target` property to a Router, make sure that it is not aggregating its value,
* i.e. `ownValue` method is not called.
*/
readonly target?: IProperty<T>;
/**
* Path separator function. Parses incoming path to two tokens: route and argument. Route gets used to
* process a single routing step and create a target, argument gets passed to the target for further routing.
*/
readonly separator?: Separator | RegExp;
/**
* Path joiner. Opposite to `separator`. Used in `getFullPath` and `redirect` methods to properly build the
* path. Joins incoming route and argument to a full path.
*/
readonly joiner?: Joiner | string;
/**
* Route handler. Maps the route string to a target object and passes argument to it for further routing.
*/
readonly handler?: Handler<T> | HandlerConfig<T>;
/**
* `separator`, `joiner` and `handler` call scope.
*/
readonly scope?: any;

@@ -185,10 +349,9 @@ }

/**
* Converts RegExp to separator function. The first token ($1) of path is used as a
* route, and the next non-null token ($2-...) is used as an argument.
* If path is null, it is assumed to be "".
*
* @param regexp Regular expression.
* If `separator` is a function, returns it immediately. Else converts the specified regular expression to
* a function by the following rule: The first token ($1) of path is used as a route, and the next non-null token
* ($2 or further) is used as an argument. If path is null, it is assumed to be "".
* @param separator Function or regular expression.
* @returns Separator function.
*/
export function makeSeparator(separator: Separator | RegExp = defaultSeparator): Separator {
export function makeSeparator(separator: Separator | RegExp = DEFAULT_SEPARATOR): Separator {
if (typeof separator === "function") {

@@ -204,28 +367,14 @@ return separator;

/**
* Converts joiner symbol/string to joiner function. Joins incoming route/argument pair via the specified string.
* Leading joiner symbols in argument are trimmed. If argument starts with "?", joiner symbol is not added.
* If argument is null or blank, returns route.
*
* Examples:
*
* <table>
* <tr><td>Incoming route</td><td>Incoming argument</td><td>Separator</td><td>Resulting path</td></tr>
* <tr><td>""</td><td>""</td><td>"/"</td><td>""</td></tr>
* <tr><td>"inbox"</td><td>""</td><td>"/"</td><td>"inbox"</td></tr>
* <tr><td>"inbox"</td><td>"1"</td><td>"/"</td><td>"inbox/1"</td></tr>
* <tr><td>"inbox"</td><td>"1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply"</td><td>"/"</td><td>"inbox/1/reply"</td></tr>
* <tr><td>"inbox"</td><td>"/1/reply/"</td><td>"/"</td><td>"inbox/1/reply/"</td></tr>
* <tr><td>"inbox"</td><td>"///1/reply///"</td><td>"/"</td><td>"inbox/1/reply///"</td></tr>
* <tr><td>"inbox"</td><td>"?id=1"</td><td>"/"</td><td>"inbox?id=1"</td></tr>
* </table>
*
* @param joiner Joiner symbol/string.
* If `joiner` is a function, returns it immediately. Else converts the specified string to a function by the
* following rule: joins incoming route/argument pair via the specified string. Leading joiner symbols in argument
* are trimmed. If argument starts with "?", joiner symbol is not added. If argument is null or blank, returns
* route.
* @param joiner Function or separation character.
* @returns Joiner function.
*/
export function makeJoiner(joiner: Joiner | string = defaultJoiner): Joiner {
export function makeJoiner(joiner: Joiner | string = DEFAULT_JOINER): Joiner {
if (typeof joiner === "function") {
return joiner;
}
var trimmer = new RegExp("^(?:" + joiner.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&') + ")*");
const trimmer = new RegExp("^(?:" + joiner.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&') + ")*");
return function (route, arg) {

@@ -237,24 +386,3 @@ return !arg ? route : (arg.charAt(0) === "?") ? (route + arg) : (route + joiner + arg.replace(trimmer, ""));

/**
* Converts handler configuration object to handler function. Configuration has two optional fields:
*
* - [[RouteMap.routes|routes]] is a mapping from route string to a handler function for
* this specific route. The function takes the path argument as an argument.
* - [[RouteMap.notFound|notFound]] is a handler function for all routes which don't
* match [[RouteMap.routes|routes]] mapping. The function takes route and path argument as
* arguments.
*
* Example:
*
* this.router = this.own(new JW.Plugins.Router({
* path: JW.UI.hash,
* handler: {
* routes: {
* "inbox" : function(arg) { return new Inbox(arg); },
* "" : function(arg) { return new JW.UI.Component(); }
* },
* notFound: function(route, arg) { return new NotFound(route, arg); }
* },
* scope: this
* }));
*
* If handler is a function, returns it immediately. Else converts the specified object to a function.
* @param handler Handler configuration object.

@@ -274,7 +402,20 @@ * @returns Handler function.

export function getFullPath(path: string, router: Router<any>) {
/**
* Returns full path as the result of `joiner` function call in `parent` of `router` with `name` passed as
* `route` and `path` passed as `arg`. Returns `path` if this is the root router.
* @param path Path relative to `router`.
* @param router Compute full path relative to this router.
* @returns Full path relative to the `router`.
*/
export function getFullPath(path: string, router?: Router<any>) {
return router ? router.getFullPath(path) : path;
}
export function redirect(path: string, router: Router<any>, replaceState?: boolean) {
/**
* Immediately performs the redirection, i.e. sets `hash` to `getFullPath(path, router)`.
* @param path Path relative to `router`.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the stack.
*/
export function redirect(path: string, router?: Router<any>, replaceState?: boolean) {
try {

@@ -292,10 +433,14 @@ path = getFullPath(path, router);

export function bindRouting(component: any, path: Bindable<string>): Destroyable {
return !component ? null :
component.bindRouting ? component.bindRouting(path) :
component.path ? new Copier(path, component.path) : null;
}
/**
* Recommended way to perform an asyncronous redirection in Router `handler` function.
*/
export class Redirector extends Component {
constructor(private path: string, private router: Router<any>, private replaceState?: boolean) {
/**
* Creates a new redirector.
* @param path Path relative to router.
* @param router Redirect relative to this router.
* @param replaceState Replace the current browser historical state rather than pushing a new state to the
* stack. Defaults to true.
*/
constructor(private path: string, private router?: Router<any>, private replaceState?: boolean) {
super();

@@ -314,15 +459,3 @@ defer(0, this.own(new CancelToken())).then(() => {

*
* The logic is very similar to FE.CD.UI.Panel.List's routing, but it has some differences in API:
*
* * Node route array is constant whereas Panel.List may have variable set of panels;
* * In exchange, Panel.List requires all children to be AbstractPanels which requires some additional
* configuration. Also, the panels must be initialized in advance, but not to be rendered yet at the moment
* of router initialization.
*
* Configuration:
*
* * name, parentRouter, path - See FE.Lib.Multirouter;
* * routes: String[] - All possible routes;
* * defaultRoute?: String - Default route to redirect the router to (optional);
* * expanded?: Boolean | String[] - Panels to expand by default. Set to true to expand all panels.
* This allows you to render your content as a fixed list of panels representing the concurrent routes.
*/

@@ -335,5 +468,17 @@ export class Node extends Class {

/**
* Default route this node was initialized with.
*/
readonly defaultRoute: string;
/**
* Router that manages this node. Node creates this router automatically. You should pass this router to
* child components as their parent router for further routing.
*/
readonly router: Router<Destroyable>;
/**
* Creates router node, assigns its properties to initial values and starts synchronization.
* @param config Node configuration.
*/
constructor(config: Node.Config) {

@@ -381,2 +526,6 @@ super();

/**
* Provides paths to bind child routers to, by name. Only one route is active at a time, but their paths
* always exist regardless of their activity.
*/
get paths(): Dictionary<Bindable<string>> {

@@ -386,3 +535,6 @@ return this._paths;

get expanded(): Dictionary<Bindable<boolean>> {
/**
* Provides "expanded" flags to bind child panels to, by name. Support two-way binding.
*/
get expanded(): Dictionary<IProperty<boolean>> {
return this._expanded;

@@ -393,8 +545,37 @@ }

export namespace Node {
/**
* Router.Node configuration.
*/
export interface Config {
/**
* Router name.
*/
readonly name?: string;
/**
* Parent router.
*/
readonly parent?: Router<any>;
/**
* Path to bind the router to.
*/
readonly path?: Bindable<string>;
/**
* Fixed list of routes to manage by this node. For every name in this list, corresponding properties will be
* created in `paths` and `expanded` dictionaries of the node.
*/
readonly routes: string[];
/**
* Initial "expanded" status of routes or initial routes to expand. Defaults to false (all routes are
* collapsed).
*/
readonly expanded?: boolean | string[];
/**
* Default route. If the initial path is blank (""), the router performs a redirection to this route, i.e.
* expands one of the panels. Doesn't work after initialization.
*/
readonly defaultRoute?: string;

@@ -401,0 +582,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc