Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

can-route

Package Overview
Dependencies
Maintainers
8
Versions
118
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

can-route - npm Package Compare versions

Comparing version 4.0.0-pre.2 to 4.0.0-pre.3

258

can-route.js
/*jshint -W079 */
var queues = require("can-queues");
var Observation = require('can-observation');
var SimpleObservable = require("can-simple-observable");

@@ -20,3 +19,2 @@ var namespace = require('can-namespace');

var registerRoute = require("./src/register");
var urlDispatcher = require("./src/-url-dispatcher");
var urlHelpers = require("./src/url-helpers");

@@ -41,67 +39,18 @@ var routeParam = require("./src/param");

//
// Helper methods used for matching routes.
var attrHelper = function (prop, value) {
if("attr" in this) {
return this.attr.apply(this, arguments);
} else {
if(arguments.length > 1) {
canReflect.setKeyValue(this, prop, value);
return this;
} else if(typeof prop === 'object') {
canReflect.assignDeep(this,prop);
return this;
} else if(arguments.length === 1){
return canReflect.getKeyValue(this, prop);
} else {
return canReflect.unwrap(this);
}
}
};
// Helper for convert any object (or value) to stringified object (or value)
var stringify = function (obj) {
// Object is array, plain object, Map or List
if (obj && typeof obj === "object") {
if (obj && typeof obj === "object" && ("serialize" in obj)) {
obj = obj.serialize();
} else {
// Get array from array-like or shallow-copy object
obj = isFunction(obj.slice) ? obj.slice() : assign({}, obj);
}
// Convert each object property or array item into stringified new
each(obj, function (val, prop) {
obj[prop] = stringify(val);
});
// Object supports toString function
} else if (obj !== undefined && obj !== null && isFunction(obj.toString)) {
obj = obj.toString();
}
return obj;
};
// A ~~throttled~~ debounced function called multiple times will only fire once the
// timer runs down. Each call resets the timer.
var timer;
// Intermediate storage for `canRoute.data`.
var curParams;
// The last hash caused by a data change
var lastHash;
// Are data changes pending that haven't yet updated the hash
var changingData;
// List of attributes that have changed since last update
var changedAttrs = [];
// A dummy events object used to dispatch url change events on.
var matchedObservable = new Observation(function canRoute_matchedRoute(){
var url = bindingProxy.call("can.getValue");
return canRoute.deparam(url).route;
});
// If the `route.data` changes, update the hash.

@@ -111,14 +60,9 @@ // Using `.serialize()` retrieves the raw data contained in the `observable`.

// This might be able to use batchNum and avoid this.
var oldProperties = null;
var onRouteDataChange = function (ev, newProps, oldProps) {
function updateUrl(serializedData) {
// indicate that data is changing
changingData = 1;
// collect attributes that are changing
if(!oldProperties) {
oldProperties = oldProps;
}
clearTimeout(timer);
timer = setTimeout(function () {
var old = oldProperties;
oldProperties = null;
// indicate that the hash is set to look like the data

@@ -130,97 +74,44 @@ changingData = 0;

if(route) {
// if we are paraming for setting the hash
// we also want to make sure the route value is updated
// TODO: matched can almost certainly be an observation around the route derived from the serialize data
canRoute.matched(route.route);
}
bindingProxy.call("can.setValue", path, newProps, old);
//canRoute._call("setURL", path, newProps, old);
// trigger a url change so its possible to live-bind on url-based changes
urlDispatcher.dispatch("__url",[path, lastHash]);
lastHash = path;
changedAttrs = [];
bindingProxy.call("can.setValue", path);
}, 10);
};
}
// everything in the backing Map is a string
// add type coercion during Map setter to coerce all values to strings
var stringCoercingMapDecorator = function(map) {
var sym = canSymbol.for("can.route.stringCoercingMapDecorator");
if(!map.attr[sym]) {
var attrSuper = map.attr;
//!steal-remove-start
Object.defineProperty(updateUrl, "name", {
value: "can-route.updateUrl"
});
//!steal-remove-end
map.attr = function(prop, val) {
var serializable = this.define === undefined || this.define[prop] === undefined || !!this.define[prop].serialize,
args;
if (serializable) { // if setting non-str non-num attr
args = stringify(Array.apply(null, arguments));
} else {
args = arguments;
}
return attrSuper.apply(this, args);
};
canReflect.setKeyValue(map.attr, sym, true);
}
return map;
};
var recursiveClean = function(old, cur, data){
for(var attr in old){
if(cur[attr] === undefined){
if("removeAttr" in data) {
data.removeAttr(attr);
} else {
cur[attr] = undefined;
}
}
else if(Object.prototype.toString.call(old[attr]) === "[object Object]") {
recursiveClean( old[attr], cur[attr], attrHelper.call(data,attr) );
}
}
};
var // Deparameterizes the portion of the hash of interest and assign the
// Deparameterizes the portion of the hash of interest and assign the
// values to the `route.data` removing existing values no longer in the hash.
// setState is called typically by hashchange which fires asynchronously
// updateRouteData is called typically by hashchange which fires asynchronously
// So it's possible that someone started changing the data before the
// hashchange event fired. For this reason, it will not set the route data
// if the data is changing or the hash already matches the hash that was set.
setState =canRoute.setState = function () {
var hash =bindingProxy.call("can.getValue");
var oldParams = curParams;
curParams =canRoute.deparam(hash);
var matched;
function updateRouteData() {
var hash = bindingProxy.call("can.getValue");
// if the hash data is currently changing, or
// the hash is what we set it to anyway, do NOT change the hash
if (!changingData || hash !== lastHash) {
if ( !changingData ) {
queues.batch.start();
recursiveClean(oldParams, curParams,canRoute.data);
matched = curParams.route;
delete curParams.route;
canRoute.matched(matched);
canRoute.attr(curParams);
curParams.route = matched;
// trigger a url change so its possible to live-bind on url-based changes
urlDispatcher.dispatch("__url",[hash, lastHash]);
var state = canRoute.deparam(hash);
delete state.route;
canReflect.update(canRoute.data,state);
queues.batch.stop();
}
};
}
//!steal-remove-start
Object.defineProperty(updateRouteData, "name", {
value: "can-route.updateRouteData"
});
//!steal-remove-end
var matchedObservable = new SimpleObservable();
/**
* @static
*/
Object.defineProperty(canRoute,"routes",{

@@ -266,3 +157,3 @@ /**

set: function(newVal){
bindingProxy.currentBinding = newVal;
bindingProxy.currentBinding = newVal;
}

@@ -317,3 +208,10 @@ });

if(isBrowserWindow() || isWebWorker()) {
canRoute.setState();
// We can't use updateRouteData because we want to merge the route data
// into .data
var hash = bindingProxy.call("can.getValue");
queues.batch.start();
var state = canRoute.deparam(hash);
delete state.route;
canReflect.assign(canRoute.data,state);
queues.batch.stop();
}

@@ -334,3 +232,3 @@ }

// we need to be able to
// easily kick off calling setState
// easily kick off calling updateRouteData
// teardown whatever is there

@@ -342,4 +240,4 @@ // turn on a particular binding

if (!canRoute.currentBinding) {
bindingProxy.call("can.onValue", setState);
canReflect.onValue( canRoute.serializedObservation, onRouteDataChange, "notify");
bindingProxy.call("can.onValue", updateRouteData);
canReflect.onValue( canRoute.serializedObservation, updateUrl, "notify");
canRoute.currentBinding =canRoute.defaultBinding;

@@ -350,4 +248,4 @@ }

if (canRoute.currentBinding) {
bindingProxy.call("can.offValue", setState);
canReflect.offValue( canRoute.serializedObservation, onRouteDataChange, "notify");
bindingProxy.call("can.offValue", updateRouteData);
canReflect.offValue( canRoute.serializedObservation, updateUrl, "notify");
canRoute.currentBinding = null;

@@ -394,5 +292,5 @@ }

// exposing all internal eventQueue evt's to canRoute
canRoute[name] = function(eventName) {
canRoute[name] = function(eventName, handler) {
if (eventName === '__url') {
return urlDispatcher[name].apply(urlDispatcher, arguments);
return bindingProxy.call("can.onValue", handler );
}

@@ -423,3 +321,3 @@ return bindToCanRouteData(name, arguments);

if(!serializedObservation) {
serializedObservation = new Observation(function canRouteSerialized(){
serializedObservation = new Observation(function canRoute_data_serialized(){
return canReflect.serialize( canRoute.data );

@@ -439,2 +337,49 @@ });

});
// Helper for convert any object (or value) to stringified object (or value)
var stringify = function (obj) {
// Object is array, plain object, Map or List
if (obj && typeof obj === "object") {
if (obj && typeof obj === "object" && ("serialize" in obj)) {
obj = obj.serialize();
} else {
// Get array from array-like or shallow-copy object
obj = isFunction(obj.slice) ? obj.slice() : assign({}, obj);
}
// Convert each object property or array item into stringified new
each(obj, function (val, prop) {
obj[prop] = stringify(val);
});
// Object supports toString function
} else if (obj !== undefined && obj !== null && isFunction(obj.toString)) {
obj = obj.toString();
}
return obj;
};
// everything in the backing Map is a string
// add type coercion during Map setter to coerce all values to strings so unexpected conflicts don't happen.
// https://github.com/canjs/canjs/issues/2206
var stringCoercingMapDecorator = function(map) {
var sym = canSymbol.for("can.route.stringCoercingMapDecorator");
if(!map.attr[sym]) {
var attrSuper = map.attr;
map.attr = function(prop, val) {
var serializable = this.define === undefined || this.define[prop] === undefined || !!this.define[prop].serialize,
args;
if (serializable) { // if setting non-str non-num attr
args = stringify(Array.apply(null, arguments));
} else {
args = arguments;
}
return attrSuper.apply(this, args);
};
canReflect.setKeyValue(map.attr, sym, true);
}
return map;
};
Object.defineProperty(canRoute,"data", {

@@ -461,4 +406,19 @@ get: function(){

canRoute.attr = function(){
return attrHelper.apply(canRoute.data,arguments);
canRoute.attr = function(prop, value){
console.warn("can-route: can-route.attr is deprecated. Use methods on can-route.data instead.");
if("attr" in canRoute.data) {
return canRoute.data.attr.apply(canRoute.data, arguments);
} else {
if(arguments.length > 1) {
canReflect.setKeyValue(canRoute.data, prop, value);
return canRoute.data;
} else if(typeof prop === 'object') {
canReflect.assignDeep(canRoute.data,prop);
return canRoute.data;
} else if(arguments.length === 1){
return canReflect.getKeyValue(canRoute.data, prop);
} else {
return canReflect.unwrap(canRoute.data);
}
}
};

@@ -465,0 +425,0 @@

{
"name": "can-route",
"version": "4.0.0-pre.2",
"version": "4.0.0-pre.3",
"description": "Observable front-end application routing for CanJS.",

@@ -52,6 +52,8 @@ "homepage": "https://canjs.com/doc/can-route.html",

"can-symbol": "^1.0.0",
"can-util": "^3.9.0"
"can-util": "^3.9.0",
"can-key-tree": "<2.0.0"
},
"devDependencies": {
"can-define": "^2.0.0-pre.0",
"can-map": "^4.0.0-pre.8",
"can-stache-key": "^1.0.0-pre.0",

@@ -58,0 +60,0 @@ "detect-cyclic-packages": "^1.1.0",

var makeArray = require('can-util/js/make-array/make-array');
var canSymbol = require("can-symbol");
var SimpleObservable = require("can-simple-observable");
var defaultBinding = new SimpleObservable("hashchange")
var bindingProxy = {
defaultBinding: "hashchange",
get defaultBinding(){
return defaultBinding.get();
},
set defaultBinding(newVal){
defaultBinding.set(newVal);
},
currentBinding: null,

@@ -7,0 +15,0 @@ bindings: {},

@@ -6,5 +6,31 @@ // Regular expression for identifying &amp;key=value lists.

var canReflect = require("can-reflect");
var eventQueue = require("can-event-queue");
var domEvents = require("can-util/dom/events/events");
var ObservationRecorder = require("can-observation-recorder");
var queues = require("can-queues");
var KeyTree = require("can-key-tree");
var SimpleObservable = require("can-simple-observable");
module.exports = canReflect.assignSymbols({
function getHash(){
var loc = LOCATION();
return loc.href.split(/#!?/)[1] || "";
}
function HashchangeObservable() {
var dispatchHandlers = this.dispatchHandlers.bind(this);
var self = this;
this.handlers = new KeyTree([Object,Array],{
onFirst: function(){
self.value = getHash();
domEvents.addEventListener.call(window, 'hashchange', dispatchHandlers);
},
onEmpty: function(){
domEvents.removeEventListener.call(window, 'hashchange', dispatchHandlers);
}
});
}
HashchangeObservable.prototype = Object.create(SimpleObservable.prototype);
HashchangeObservable.constructor = HashchangeObservable;
canReflect.assign(HashchangeObservable.prototype,{
// STUFF NEEDED FOR can-route integration
paramsMatcher: paramsMatcher,

@@ -14,21 +40,23 @@ querySeparator: "&",

matchSlashes: false,
root: "#!"
},{
"can.onValue": function(handler){
eventQueue.on.call(window, 'hashchange', handler);
root: "#!",
dispatchHandlers: function() {
var old = this.value;
this.value = getHash();
if(old !== this.value) {
queues.enqueueByQueue(this.handlers.getNode([]), this, [this.value, old]
//!steal-remove-start
/* jshint laxcomma: true */
, null
, [ canReflect.getName(this), "changed to", this.value, "from", old ]
/* jshint laxcomma: false */
//!steal-remove-end
);
}
},
"can.offValue": function(handler) {
eventQueue.on.call(window, 'hashchange', handler);
get: function(){
ObservationRecorder.add(this);
return getHash();
},
// Gets the part of the url we are determinging the route from.
// For hashbased routing, it's everything after the #, for
// pushState it's configurable
"can.getValue": function() {
set: function(path){
var loc = LOCATION();
return loc.href.split(/#!?/)[1] || "";
},
// gets called with the serializedcanRoute data after a route has changed
// returns what the url has been updated to (for matching purposes)
"can.setValue": function(path){
var loc = LOCATION();
if(loc.hash !== "#" + path) {

@@ -40,1 +68,19 @@ loc.hash = "!" + path;

});
canReflect.assignSymbols(HashchangeObservable.prototype,{
"can.getValue": HashchangeObservable.prototype.get,
"can.setValue": HashchangeObservable.prototype.set,
"can.onValue": HashchangeObservable.prototype.on,
"can.offValue": HashchangeObservable.prototype.off,
"can.isMapLike": false,
"can.valueHasDependencies": function(){
return true;
},
//!steal-remove-start
"can.getName": function() {
return "HashchangeObservable<" + this.value + ">";
},
//!steal-remove-end
});
module.exports = new HashchangeObservable();
var bindingProxy = require("./binding-proxy");
var ObservationRecorder = require('can-observation-recorder');
var routeDeparam = require("./deparam");

@@ -10,6 +9,3 @@ var routeParam = require("./param");

var urlDispatcher = require("./-url-dispatcher");
var makeProps = function (props) {

@@ -41,3 +37,2 @@ var tags = [];

if (merge) {
ObservationRecorder.add(urlDispatcher,"__url");
var baseOptions = routeDeparam(bindingProxy.call("can.getValue"));

@@ -191,7 +186,5 @@ options = assign(assign({}, baseOptions), options);

current: function canRoute_current(options, subsetMatch) {
// "reads" the url so the url is live-bindable.
ObservationRecorder.add(urlDispatcher,"__url");
if(subsetMatch) {
// everything in options shouhld be in baseOptions
var baseOptions = routeDeparam( bindingProxy.call("matchingPartOfURL") );
var baseOptions = routeDeparam( bindingProxy.call("getValue") );
return matchCheck(options, baseOptions);

@@ -198,0 +191,0 @@ } else {

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