2018-10-31 17:00:31 +01:00
// modules are defined as an array
// [ module function, map of requires ]
//
// map of requires is short require name -> numeric require
//
// anything defined in a previous bundle is accessed via the
// orig method which is the require for previous bundles
// eslint-disable-next-line no-global-assign
parcelRequire = ( function ( modules , cache , entry , globalName ) {
// Save the require from previous bundle to this closure if any
var previousRequire = typeof parcelRequire === 'function' && parcelRequire ;
var nodeRequire = typeof require === 'function' && require ;
function newRequire ( name , jumped ) {
if ( ! cache [ name ] ) {
if ( ! modules [ name ] ) {
// if we cannot find the module within our internal map or
// cache jump to the current global require ie. the last bundle
// that was added to the page.
var currentRequire = typeof parcelRequire === 'function' && parcelRequire ;
if ( ! jumped && currentRequire ) {
return currentRequire ( name , true ) ;
}
// If there are other bundles on this page the require from the
// previous one is saved to 'previousRequire'. Repeat this as
// many times as there are bundles until the module is found or
// we exhaust the require chain.
if ( previousRequire ) {
return previousRequire ( name , true ) ;
}
// Try the node require function if it exists.
if ( nodeRequire && typeof name === 'string' ) {
return nodeRequire ( name ) ;
}
var err = new Error ( 'Cannot find module \'' + name + '\'' ) ;
err . code = 'MODULE_NOT_FOUND' ;
throw err ;
}
localRequire . resolve = resolve ;
localRequire . cache = { } ;
var module = cache [ name ] = new newRequire . Module ( name ) ;
modules [ name ] [ 0 ] . call ( module . exports , localRequire , module , module . exports , this ) ;
}
return cache [ name ] . exports ;
function localRequire ( x ) {
return newRequire ( localRequire . resolve ( x ) ) ;
}
function resolve ( x ) {
return modules [ name ] [ 1 ] [ x ] || x ;
}
}
function Module ( moduleName ) {
this . id = moduleName ;
this . bundle = newRequire ;
this . exports = { } ;
}
newRequire . isParcelRequire = true ;
newRequire . Module = Module ;
newRequire . modules = modules ;
newRequire . cache = cache ;
newRequire . parent = previousRequire ;
newRequire . register = function ( id , exports ) {
modules [ id ] = [ function ( require , module ) {
module . exports = exports ;
} , { } ] ;
} ;
for ( var i = 0 ; i < entry . length ; i ++ ) {
newRequire ( entry [ i ] ) ;
}
if ( entry . length ) {
// Expose entry point to Node, AMD or browser globals
// Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
var mainExports = newRequire ( entry [ entry . length - 1 ] ) ;
// CommonJS
if ( typeof exports === "object" && typeof module !== "undefined" ) {
module . exports = mainExports ;
// RequireJS
} else if ( typeof define === "function" && define . amd ) {
define ( function ( ) {
return mainExports ;
} ) ;
// <script>
} else if ( globalName ) {
this [ globalName ] = mainExports ;
}
}
// Override the current require with this new one
return newRequire ;
2018-11-14 17:32:35 +01:00
} ) ( { "../../../../brain/tools/events/EventEmitter.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var EventEmitter =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function EventEmitter ( ) {
_classCallCheck ( this , EventEmitter ) ;
this . listeners = new Map ( ) ;
} //--------------------------
// methods
//--------------------------
_createClass ( EventEmitter , [ {
key : "addListener" ,
value : function addListener ( label , callback ) {
this . listeners . has ( label ) || this . listeners . set ( label , [ ] ) ;
this . listeners . get ( label ) . push ( callback ) ;
}
} , {
key : "removeListener" ,
value : function removeListener ( label , callback ) {
var isFunction = function isFunction ( obj ) {
return typeof obj == 'function' || false ;
} ;
var listeners = this . listeners . get ( label ) ,
index ;
if ( listeners && listeners . length ) {
index = listeners . reduce ( function ( i , listener , index ) {
return isFunction ( listener ) && listener === callback ? i = index : i ;
} , - 1 ) ;
if ( index > - 1 ) {
listeners . splice ( index , 1 ) ;
this . listeners . set ( label , listeners ) ;
return true ;
}
}
return false ;
}
} , {
key : "emitEvent" ,
value : function emitEvent ( label ) {
for ( var _len = arguments . length , args = new Array ( _len > 1 ? _len - 1 : 0 ) , _key = 1 ; _key < _len ; _key ++ ) {
args [ _key - 1 ] = arguments [ _key ] ;
}
var listeners = this . listeners . get ( label ) ;
if ( listeners && listeners . length ) {
listeners . forEach ( function ( listener ) {
listener . apply ( void 0 , args ) ;
} ) ;
return true ;
}
return false ;
} //--------------------------
// event handlers
//--------------------------
} ] ) ;
return EventEmitter ;
} ( ) ;
var _default = EventEmitter ;
exports . default = _default ;
2018-11-14 17:32:35 +01:00
} , { } ] , "../../../../brain/tools/events/DataEvent.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
2019-01-03 17:17:02 +01:00
exports . default = exports . SITE _BACKGROUND _UPLOADED = exports . AVATAR _UPLOADED = exports . SETTINGS _UPDATED = exports . LOCAL _DB _READY = exports . POSTS _SYNCED = exports . POST _DELETED = exports . POST _UPDATED = exports . POST _ADDED = exports . POST _ERROR = exports . FEATURE _IMAGE _ADDED = exports . POST _IMAGE _ADDED = exports . PROJECTS _SORTED = exports . PROJECT _ADDED = exports . PROJECT _UPDATED = exports . ARCHIVES _ENTRY _LOADED = exports . ARCHIVES _PAGE _LOADED = exports . ARCHIVES _JSON _LOADED = exports . HTML _LOADED = exports . SETTINGS _LOADED = exports . IMG _REQUEST _LAME = exports . IMG _REQUEST _GOOD = exports . REQUEST _LAME = exports . REQUEST _GOOD = void 0 ;
2018-10-31 17:00:31 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var REQUEST _GOOD = 'requestGood' ;
exports . REQUEST _GOOD = REQUEST _GOOD ;
var REQUEST _LAME = 'requestLame' ;
exports . REQUEST _LAME = REQUEST _LAME ;
var IMG _REQUEST _GOOD = 'imgRequestGood' ;
exports . IMG _REQUEST _GOOD = IMG _REQUEST _GOOD ;
var IMG _REQUEST _LAME = 'imgRequestLame' ;
exports . IMG _REQUEST _LAME = IMG _REQUEST _LAME ;
var SETTINGS _LOADED = 'dataLoaded' ;
exports . SETTINGS _LOADED = SETTINGS _LOADED ;
var HTML _LOADED = 'htmlLoaded' ;
exports . HTML _LOADED = HTML _LOADED ;
var ARCHIVES _JSON _LOADED = 'archivesJSONLoaded' ;
exports . ARCHIVES _JSON _LOADED = ARCHIVES _JSON _LOADED ;
var ARCHIVES _PAGE _LOADED = 'archivesPAGELoaded' ;
exports . ARCHIVES _PAGE _LOADED = ARCHIVES _PAGE _LOADED ;
var ARCHIVES _ENTRY _LOADED = 'archivesEntryLoaded' ;
exports . ARCHIVES _ENTRY _LOADED = ARCHIVES _ENTRY _LOADED ;
var PROJECT _UPDATED = 'projectUpdated' ;
exports . PROJECT _UPDATED = PROJECT _UPDATED ;
var PROJECT _ADDED = 'projectAdded' ;
exports . PROJECT _ADDED = PROJECT _ADDED ;
var PROJECTS _SORTED = 'projectsSorted' ;
exports . PROJECTS _SORTED = PROJECTS _SORTED ;
var POST _IMAGE _ADDED = 'postImageAdded' ;
exports . POST _IMAGE _ADDED = POST _IMAGE _ADDED ;
2018-11-26 23:14:13 +01:00
var FEATURE _IMAGE _ADDED = 'featureImageAdded' ;
exports . FEATURE _IMAGE _ADDED = FEATURE _IMAGE _ADDED ;
2018-11-05 23:32:33 +01:00
var POST _ERROR = 'postError' ;
exports . POST _ERROR = POST _ERROR ;
var POST _ADDED = 'postAdded' ;
exports . POST _ADDED = POST _ADDED ;
var POST _UPDATED = 'postUpdated' ;
exports . POST _UPDATED = POST _UPDATED ;
var POST _DELETED = 'postImageAdded' ;
exports . POST _DELETED = POST _DELETED ;
2018-11-21 01:42:52 +01:00
var POSTS _SYNCED = 'postsSynced' ;
exports . POSTS _SYNCED = POSTS _SYNCED ;
2018-12-03 01:47:28 +01:00
var LOCAL _DB _READY = 'localDBReady' ;
exports . LOCAL _DB _READY = LOCAL _DB _READY ;
2018-12-19 18:56:18 +01:00
var SETTINGS _UPDATED = 'settingsUpdated' ;
exports . SETTINGS _UPDATED = SETTINGS _UPDATED ;
2018-12-20 19:50:28 +01:00
var AVATAR _UPLOADED = 'avatarUploaded' ;
exports . AVATAR _UPLOADED = AVATAR _UPLOADED ;
2019-01-03 17:17:02 +01:00
var SITE _BACKGROUND _UPLOADED = 'siteBackgroundUploaded' ;
exports . SITE _BACKGROUND _UPLOADED = SITE _BACKGROUND _UPLOADED ;
2018-10-31 17:00:31 +01:00
var DataEvent = function DataEvent ( ) {
_classCallCheck ( this , DataEvent ) ;
} ;
var _default = new DataEvent ( ) ;
exports . default = _default ;
2018-11-14 17:32:35 +01:00
} , { } ] , "../../../../brain/tools/utilities/DataUtils.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = exports . CONTENT _TYPE _FORM = exports . CONTENT _TYPE _JSON = exports . REQUEST _TYPE _DELETE = exports . REQUEST _TYPE _PUT = exports . REQUEST _TYPE _GET = exports . REQUEST _TYPE _POST = void 0 ;
2018-11-14 17:32:35 +01:00
var _EventEmitter2 = _interopRequireDefault ( require ( "../events/EventEmitter" ) ) ;
2018-10-31 17:00:31 +01:00
2018-11-14 17:32:35 +01:00
var DataEvent = _interopRequireWildcard ( require ( "../events/DataEvent" ) ) ;
2018-10-31 17:00:31 +01:00
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
function _typeof ( obj ) { if ( typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ) { _typeof = function _typeof ( obj ) { return typeof obj ; } ; } else { _typeof = function _typeof ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ; } return _typeof ( obj ) ; }
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
function _possibleConstructorReturn ( self , call ) { if ( call && ( _typeof ( call ) === "object" || typeof call === "function" ) ) { return call ; } return _assertThisInitialized ( self ) ; }
function _getPrototypeOf ( o ) { _getPrototypeOf = Object . setPrototypeOf ? Object . getPrototypeOf : function _getPrototypeOf ( o ) { return o . _ _proto _ _ || Object . getPrototypeOf ( o ) ; } ; return _getPrototypeOf ( o ) ; }
function _inherits ( subClass , superClass ) { if ( typeof superClass !== "function" && superClass !== null ) { throw new TypeError ( "Super expression must either be null or a function" ) ; } subClass . prototype = Object . create ( superClass && superClass . prototype , { constructor : { value : subClass , writable : true , configurable : true } } ) ; if ( superClass ) _setPrototypeOf ( subClass , superClass ) ; }
function _setPrototypeOf ( o , p ) { _setPrototypeOf = Object . setPrototypeOf || function _setPrototypeOf ( o , p ) { o . _ _proto _ _ = p ; return o ; } ; return _setPrototypeOf ( o , p ) ; }
function _assertThisInitialized ( self ) { if ( self === void 0 ) { throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ; } return self ; }
var REQUEST _TYPE _POST = "POST" ;
exports . REQUEST _TYPE _POST = REQUEST _TYPE _POST ;
var REQUEST _TYPE _GET = "GET" ;
exports . REQUEST _TYPE _GET = REQUEST _TYPE _GET ;
var REQUEST _TYPE _PUT = "PUT" ;
exports . REQUEST _TYPE _PUT = REQUEST _TYPE _PUT ;
var REQUEST _TYPE _DELETE = "DELETE" ;
exports . REQUEST _TYPE _DELETE = REQUEST _TYPE _DELETE ;
var CONTENT _TYPE _JSON = 'json' ;
exports . CONTENT _TYPE _JSON = CONTENT _TYPE _JSON ;
var CONTENT _TYPE _FORM = 'x-www-form-urlencoded' ;
exports . CONTENT _TYPE _FORM = CONTENT _TYPE _FORM ;
var DataUtils =
/*#__PURE__*/
function ( _EventEmitter ) {
_inherits ( DataUtils , _EventEmitter ) ;
//--------------------------
// constructor
//--------------------------
function DataUtils ( ) {
var _this ;
_classCallCheck ( this , DataUtils ) ;
_this = _possibleConstructorReturn ( this , _getPrototypeOf ( DataUtils ) . call ( this ) ) ;
var self = _assertThisInitialized ( _assertThisInitialized ( _this ) ) ;
return _this ;
} //--------------------------
// methods
//--------------------------
_createClass ( DataUtils , [ {
key : "request" ,
value : function request ( requestURL , eventType ) {
var requestType = arguments . length > 2 && arguments [ 2 ] !== undefined ? arguments [ 2 ] : REQUEST _TYPE _GET ;
var contentType = arguments . length > 3 && arguments [ 3 ] !== undefined ? arguments [ 3 ] : CONTENT _TYPE _JSON ;
var requestData = arguments . length > 4 && arguments [ 4 ] !== undefined ? arguments [ 4 ] : null ;
var self = this ;
return new Promise ( function ( resolve , reject ) {
var request = new XMLHttpRequest ( ) ;
request . upload . onprogress = self . handleLoadProgress ;
request . open ( requestType , requestURL , true ) ;
request . onload = function ( e ) {
if ( request . status == 200 ) {
resolve ( {
request : request ,
eventType : eventType
} ) ;
} else {
reject ( {
request : request ,
eventType : eventType
} ) ;
}
;
} ;
if ( requestType == REQUEST _TYPE _PUT || requestType == REQUEST _TYPE _POST ) {
switch ( contentType ) {
case CONTENT _TYPE _JSON :
request . setRequestHeader ( "Content-type" , "application/" + contentType ) ;
request . send ( JSON . stringify ( requestData ) ) ;
break ;
case CONTENT _TYPE _FORM :
request . send ( requestData ) ;
break ;
}
} else {
request . send ( ) ;
}
} ) ;
}
} , {
key : "imgLoad" ,
value : function imgLoad ( url ) {
'use strict' ; // Create new promise with the Promise() constructor;
// This has as its argument a function with two parameters, resolve and reject
return new Promise ( function ( resolve , reject ) {
// Standard XHR to load an image
var request = new XMLHttpRequest ( ) ;
request . open ( 'GET' , url ) ;
request . responseType = 'blob' ; // When the request loads, check whether it was successful
request . onload = function ( ) {
if ( request . status === 200 ) {
// If successful, resolve the promise by passing back the request response
resolve ( request . response ) ;
} else {
// If it fails, reject the promise with a error message
reject ( new Error ( 'Image didn\'t load successfully; error code:' + request . statusText ) ) ;
}
} ;
request . onerror = function ( ) {
// Also deal with the case when the entire request fails to begin with
// This is probably a network error, so reject the promise with an appropriate message
reject ( new Error ( 'There was a network error.' ) ) ;
} ; // Send the request
request . send ( ) ;
} ) ;
}
} , {
key : "loadImage" ,
value : function loadImage ( src ) {
'use strict' ;
var self = this ;
return new Promise ( function ( resolve , reject ) {
// Get a reference to the body element, and create a new image object
var body = document . querySelector ( 'body' ) ,
myImage = new Image ( ) ;
myImage . crossOrigin = "" ; // or "anonymous"
// Call the function with the URL we want to load, but then chain the
// promise then() method on to the end of it. This contains two callbacks
self . imgLoad ( src ) . then ( function ( response ) {
// The first runs when the promise resolves, with the request.reponse specified within the resolve() method.
var imageURL = window . URL . createObjectURL ( response ) ;
resolve ( imageURL ) ; //$('background-content').setStyle('background-image', 'url('+imageURL+')') //myImage.src = imageURL;
//console.log(imageURL);
//body.appendChild(myImage);
// The second runs when the promise is rejected, and logs the Error specified with the reject() method.
} , function ( Error ) {
reject ( Error ) ;
} ) ;
} ) ;
} //--------------------------
// event handlers
//--------------------------
} , {
key : "handleLoadProgress" ,
value : function handleLoadProgress ( e ) {
var percentComplete = Math . ceil ( e . loaded / e . total * 100 ) ; //console.log(percentComplete);
}
} ] ) ;
return DataUtils ;
} ( _EventEmitter2 . default ) ;
var _default = DataUtils ;
exports . default = _default ;
2018-12-06 22:49:49 +01:00
} , { "../events/EventEmitter" : "../../../../brain/tools/events/EventEmitter.js" , "../events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" } ] , "../../../../brain/tools/utilities/StringUtils.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var StringUtils =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function StringUtils ( ) {
_classCallCheck ( this , StringUtils ) ;
} //--------------------------
// methods
//--------------------------
_createClass ( StringUtils , [ {
key : "cleanString" ,
value : function cleanString ( string ) {
var clean = string . replace ( /(^\-+|[^a-zA-Z0-9\/_| -]+|\-+$)/g , '' ) . toLowerCase ( ) . replace ( /[\/_| -]+/g , '-' ) ;
return clean ;
}
} , {
key : "decodeHTML" ,
value : function decodeHTML ( string , quote _style ) {
var optTemp = 0 ,
i = 0 ,
noquotes = false ;
if ( typeof quote _style === 'undefined' ) {
quote _style = 2 ;
}
string = string . toString ( ) . replace ( /</g , '<' ) . replace ( />/g , '>' ) ;
var OPTS = {
'ENT_NOQUOTES' : 0 ,
'ENT_HTML_QUOTE_SINGLE' : 1 ,
'ENT_HTML_QUOTE_DOUBLE' : 2 ,
'ENT_COMPAT' : 2 ,
'ENT_QUOTES' : 3 ,
'ENT_IGNORE' : 4
} ;
if ( quote _style === 0 ) {
noquotes = true ;
}
if ( typeof quote _style !== 'number' ) {
// Allow for a single string or an array of string flags
quote _style = [ ] . concat ( quote _style ) ;
for ( i = 0 ; i < quote _style . length ; i ++ ) {
// Resolve string input to bitwise e.g. 'PATHINFO_EXTENSION' becomes 4
if ( OPTS [ quote _style [ i ] ] === 0 ) {
noquotes = true ;
} else if ( OPTS [ quote _style [ i ] ] ) {
optTemp = optTemp | OPTS [ quote _style [ i ] ] ;
}
}
quote _style = optTemp ;
}
if ( quote _style & OPTS . ENT _HTML _QUOTE _SINGLE ) {
string = string . replace ( /�*39;/g , "'" ) ; // PHP doesn't currently escape if more than one 0, but it should
// string = string.replace(/'|�*27;/g, "'"); // This would also be useful here, but not a part of PHP
}
if ( ! noquotes ) {
string = string . replace ( /"/g , '"' ) ;
} // Put this in last place to avoid escape being double-decoded
string = string . replace ( /&/g , '&' ) ;
return string ;
} //--------------------------
// event handlers
//--------------------------
} ] ) ;
return StringUtils ;
} ( ) ;
var _default = StringUtils ;
exports . default = _default ;
2018-12-06 22:49:49 +01:00
} , { } ] , "../../../../brain/tools/utilities/DateUtils.js" : [ function ( require , module , exports ) {
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var DateUtils =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function DateUtils ( ) {
_classCallCheck ( this , DateUtils ) ;
} //--------------------------
// methods
//--------------------------
_createClass ( DateUtils , [ {
key : "getMKtime" ,
value : function getMKtime ( ) {
var time = new Date ( new Date ( ) . getFullYear ( ) , new Date ( ) . getMonth ( ) , new Date ( ) . getDate ( ) , new Date ( ) . getHours ( ) , new Date ( ) . getMinutes ( ) , new Date ( ) . getSeconds ( ) , 0 ) . getTime ( ) / 1000 ;
return time ;
}
} , {
key : "convertMKtime" ,
value : function convertMKtime ( seconds ) {
var date = new Date ( seconds * 1000 ) ;
return date ;
}
} , {
key : "getDate" ,
value : function getDate ( type , rawdate ) {
var day = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCDate ( ) ) : String ( new Date ( ) . getUTCDate ( ) ) ;
var month = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCMonth ( ) + 1 ) : String ( new Date ( ) . getUTCMonth ( ) + 1 ) ;
var year = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCFullYear ( ) ) : String ( new Date ( ) . getUTCFullYear ( ) ) ;
var hour = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCHours ( ) ) : String ( new Date ( ) . getUTCHours ( ) ) ;
var minute = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCMinutes ( ) ) : String ( new Date ( ) . getUTCMinutes ( ) ) ;
var seconds = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCSeconds ( ) ) : String ( new Date ( ) . getUTCSeconds ( ) ) ;
var millisecond = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getUTCMilliseconds ( ) ) : String ( new Date ( ) . getUTCMilliseconds ( ) ) ;
var offset = rawdate != null || rawdate != '' ? String ( new Date ( rawdate ) . getTimezoneOffset ( ) ) : String ( new Date ( ) . getTimezoneOffset ( ) ) ;
if ( day . length == 1 ) day = String ( "0" + day ) ;
if ( month . length == 1 ) month = String ( "0" + month ) ;
offset = String ( offset / 60 ) ;
if ( offset . length == 1 ) offset = String ( "0" + offset ) ;
switch ( type ) {
case "day" :
return day ;
break ;
case "month" :
return month ;
break ;
case "year" :
return year ;
break ;
case "stamp" :
return String ( year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + seconds + "." + millisecond + "-" + offset ) ;
break ;
default :
return String ( year + "-" + month + "-" + day ) ;
break ;
}
} //--------------------------
// event handlers
//--------------------------
} ] ) ;
return DateUtils ;
} ( ) ;
var _default = DateUtils ;
exports . default = _default ;
2018-11-21 01:42:52 +01:00
} , { } ] , "../../../../node_modules/dexie/dist/dexie.es.js" : [ function ( require , module , exports ) {
var global = arguments [ 3 ] ;
2018-10-31 17:00:31 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-21 01:42:52 +01:00
function _typeof ( obj ) { if ( typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ) { _typeof = function ( obj ) { return typeof obj ; } ; } else { _typeof = function ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ; } return _typeof ( obj ) ; }
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
/ *
* Dexie . js - a minimalistic wrapper for IndexedDB
* === === === === === === === === === === === === === === === ==
*
* By David Fahlander , david . fahlander @ gmail . com
*
* Version { version } , { date }
*
* http : //dexie.org
*
* Apache License Version 2.0 , January 2004 , http : //www.apache.org/licenses/
* /
var keys = Object . keys ;
var isArray = Array . isArray ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var _global = typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function extend ( obj , extension ) {
if ( _typeof ( extension ) !== 'object' ) return obj ;
keys ( extension ) . forEach ( function ( key ) {
obj [ key ] = extension [ key ] ;
} ) ;
return obj ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var getProto = Object . getPrototypeOf ;
var _hasOwn = { } . hasOwnProperty ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function hasOwn ( obj , prop ) {
return _hasOwn . call ( obj , prop ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function props ( proto , extension ) {
if ( typeof extension === 'function' ) extension = extension ( getProto ( proto ) ) ;
keys ( extension ) . forEach ( function ( key ) {
setProp ( proto , key , extension [ key ] ) ;
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var defineProperty = Object . defineProperty ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function setProp ( obj , prop , functionOrGetSet , options ) {
defineProperty ( obj , prop , extend ( functionOrGetSet && hasOwn ( functionOrGetSet , "get" ) && typeof functionOrGetSet . get === 'function' ? {
get : functionOrGetSet . get ,
set : functionOrGetSet . set ,
configurable : true
} : {
value : functionOrGetSet ,
configurable : true ,
writable : true
} , options ) ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function derive ( Child ) {
return {
from : function ( Parent ) {
Child . prototype = Object . create ( Parent . prototype ) ;
setProp ( Child . prototype , "constructor" , Child ) ;
return {
extend : props . bind ( null , Child . prototype )
} ;
}
} ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var getOwnPropertyDescriptor = Object . getOwnPropertyDescriptor ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function getPropertyDescriptor ( obj , prop ) {
var pd = getOwnPropertyDescriptor ( obj , prop ) ,
proto ;
return pd || ( proto = getProto ( obj ) ) && getPropertyDescriptor ( proto , prop ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var _slice = [ ] . slice ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function slice ( args , start , end ) {
return _slice . call ( args , start , end ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function override ( origFunc , overridedFactory ) {
return overridedFactory ( origFunc ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function assert ( b ) {
if ( ! b ) throw new Error ( "Assertion Failed" ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function asap ( fn ) {
if ( _global . setImmediate ) setImmediate ( fn ) ; else setTimeout ( fn , 0 ) ;
}
/ * * G e n e r a t e a n o b j e c t ( h a s h m a p ) b a s e d o n g i v e n a r r a y .
* @ param extractor Function taking an array item and its index and returning an array of 2 items ( [ key , value ] ) to
* instert on the resulting object for each item in the array . If this function returns a falsy value , the
* current item wont affect the resulting object .
* /
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function arrayToObject ( array , extractor ) {
return array . reduce ( function ( result , item , i ) {
var nameAndValue = extractor ( item , i ) ;
if ( nameAndValue ) result [ nameAndValue [ 0 ] ] = nameAndValue [ 1 ] ;
return result ;
} , { } ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function trycatcher ( fn , reject ) {
return function ( ) {
try {
fn . apply ( this , arguments ) ;
} catch ( e ) {
reject ( e ) ;
2018-10-31 17:00:31 +01:00
}
2018-11-21 01:42:52 +01:00
} ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function tryCatch ( fn , onerror , args ) {
try {
fn . apply ( null , args ) ;
} catch ( ex ) {
onerror && onerror ( ex ) ;
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function getByKeyPath ( obj , keyPath ) {
// http://www.w3.org/TR/IndexedDB/#steps-for-extracting-a-key-from-a-value-using-a-key-path
if ( hasOwn ( obj , keyPath ) ) return obj [ keyPath ] ; // This line is moved from last to first for optimization purpose.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( ! keyPath ) return obj ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( typeof keyPath !== 'string' ) {
var rv = [ ] ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , l = keyPath . length ; i < l ; ++ i ) {
var val = getByKeyPath ( obj , keyPath [ i ] ) ;
rv . push ( val ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
return rv ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var period = keyPath . indexOf ( '.' ) ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( period !== - 1 ) {
var innerObj = obj [ keyPath . substr ( 0 , period ) ] ;
return innerObj === undefined ? undefined : getByKeyPath ( innerObj , keyPath . substr ( period + 1 ) ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
return undefined ;
}
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
function setByKeyPath ( obj , keyPath , value ) {
if ( ! obj || keyPath === undefined ) return ;
if ( 'isFrozen' in Object && Object . isFrozen ( obj ) ) return ;
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
if ( typeof keyPath !== 'string' && 'length' in keyPath ) {
assert ( typeof value !== 'string' && 'length' in value ) ;
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , l = keyPath . length ; i < l ; ++ i ) {
setByKeyPath ( obj , keyPath [ i ] , value [ i ] ) ;
}
} else {
var period = keyPath . indexOf ( '.' ) ;
if ( period !== - 1 ) {
var currentKeyPath = keyPath . substr ( 0 , period ) ;
var remainingKeyPath = keyPath . substr ( period + 1 ) ;
if ( remainingKeyPath === "" ) {
if ( value === undefined ) delete obj [ currentKeyPath ] ; else obj [ currentKeyPath ] = value ;
} else {
var innerObj = obj [ currentKeyPath ] ;
if ( ! innerObj ) innerObj = obj [ currentKeyPath ] = { } ;
setByKeyPath ( innerObj , remainingKeyPath , value ) ;
}
} else {
if ( value === undefined ) delete obj [ keyPath ] ; else obj [ keyPath ] = value ;
}
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
function delByKeyPath ( obj , keyPath ) {
if ( typeof keyPath === 'string' ) setByKeyPath ( obj , keyPath , undefined ) ; else if ( 'length' in keyPath ) [ ] . map . call ( keyPath , function ( kp ) {
setByKeyPath ( obj , kp , undefined ) ;
} ) ;
}
function shallowClone ( obj ) {
var rv = { } ;
for ( var m in obj ) {
if ( hasOwn ( obj , m ) ) rv [ m ] = obj [ m ] ;
2018-11-11 20:49:26 +01:00
}
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
return rv ;
}
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
var concat = [ ] . concat ;
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
function flatten ( a ) {
return concat . apply ( [ ] , a ) ;
} //https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
var intrinsicTypes = "Boolean,String,Date,RegExp,Blob,File,FileList,ArrayBuffer,DataView,Uint8ClampedArray,ImageData,Map,Set" . split ( ',' ) . concat ( flatten ( [ 8 , 16 , 32 , 64 ] . map ( function ( num ) {
return [ "Int" , "Uint" , "Float" ] . map ( function ( t ) {
return t + num + "Array" ;
} ) ;
} ) ) ) . filter ( function ( t ) {
return _global [ t ] ;
} ) . map ( function ( t ) {
return _global [ t ] ;
} ) ;
function deepClone ( any ) {
if ( ! any || _typeof ( any ) !== 'object' ) return any ;
var rv ;
if ( isArray ( any ) ) {
rv = [ ] ;
for ( var i = 0 , l = any . length ; i < l ; ++ i ) {
rv . push ( deepClone ( any [ i ] ) ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} else if ( intrinsicTypes . indexOf ( any . constructor ) >= 0 ) {
rv = any ;
} else {
rv = any . constructor ? Object . create ( any . constructor . prototype ) : { } ;
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
for ( var prop in any ) {
if ( hasOwn ( any , prop ) ) {
rv [ prop ] = deepClone ( any [ prop ] ) ;
}
}
2018-11-11 20:49:26 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return rv ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getObjectDiff ( a , b , rv , prfx ) {
// Compares objects a and b and produces a diff object.
rv = rv || { } ;
prfx = prfx || '' ;
keys ( a ) . forEach ( function ( prop ) {
if ( ! hasOwn ( b , prop ) ) rv [ prfx + prop ] = undefined ; // Property removed
else {
var ap = a [ prop ] ,
bp = b [ prop ] ;
if ( _typeof ( ap ) === 'object' && _typeof ( bp ) === 'object' && ap && bp && // Now compare constructors are same (not equal because wont work in Safari)
'' + ap . constructor === '' + bp . constructor ) // Same type of object but its properties may have changed
getObjectDiff ( ap , bp , rv , prfx + prop + "." ) ; else if ( ap !== bp ) rv [ prfx + prop ] = b [ prop ] ; // Primitive value changed
}
} ) ;
keys ( b ) . forEach ( function ( prop ) {
if ( ! hasOwn ( a , prop ) ) {
rv [ prfx + prop ] = b [ prop ] ; // Property added
}
} ) ;
return rv ;
} // If first argument is iterable or array-like, return it as an array
2018-11-05 23:32:33 +01:00
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var iteratorSymbol = typeof Symbol !== 'undefined' && Symbol . iterator ;
var getIteratorOf = iteratorSymbol ? function ( x ) {
var i ;
return x != null && ( i = x [ iteratorSymbol ] ) && i . apply ( x ) ;
} : function ( ) {
return null ;
} ;
var NO _CHAR _ARRAY = { } ; // Takes one or several arguments and returns an array based on the following criteras:
// * If several arguments provided, return arguments converted to an array in a way that
// still allows javascript engine to optimize the code.
// * If single argument is an array, return a clone of it.
// * If this-pointer equals NO_CHAR_ARRAY, don't accept strings as valid iterables as a special
// case to the two bullets below.
// * If single argument is an iterable, convert it to an array and return the resulting array.
// * If single argument is array-like (has length of type number), convert it to an array.
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function getArrayOf ( arrayLike ) {
var i , a , x , it ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( arguments . length === 1 ) {
if ( isArray ( arrayLike ) ) return arrayLike . slice ( ) ;
if ( this === NO _CHAR _ARRAY && typeof arrayLike === 'string' ) return [ arrayLike ] ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( it = getIteratorOf ( arrayLike ) ) {
a = [ ] ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
while ( x = it . next ( ) , ! x . done ) {
a . push ( x . value ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
return a ;
2018-11-11 20:49:26 +01:00
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
if ( arrayLike == null ) return [ arrayLike ] ;
i = arrayLike . length ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
if ( typeof i === 'number' ) {
a = new Array ( i ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
while ( i -- ) {
a [ i ] = arrayLike [ i ] ;
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
return a ;
}
return [ arrayLike ] ;
2018-11-02 21:25:47 +01:00
}
2018-11-21 01:42:52 +01:00
i = arguments . length ;
a = new Array ( i ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
while ( i -- ) {
a [ i ] = arguments [ i ] ;
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
return a ;
} // By default, debug will be true only if platform is a web platform and its page is served from localhost.
// When debug = true, error's stacks will contain asyncronic long stacks.
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var debug = typeof location !== 'undefined' && // By default, use debug mode if served from localhost.
/^(http|https):\/\/(localhost|127\.0\.0\.1)/ . test ( location . href ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function setDebug ( value , filter ) {
debug = value ;
libraryFilter = filter ;
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var libraryFilter = function ( ) {
return true ;
} ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var NEEDS _THROW _FOR _STACK = ! new Error ( "" ) . stack ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getErrorWithStack ( ) {
"use strict" ;
if ( NEEDS _THROW _FOR _STACK ) try {
// Doing something naughty in strict mode here to trigger a specific error
// that can be explicitely ignored in debugger's exception settings.
// If we'd just throw new Error() here, IE's debugger's exception settings
// will just consider it as "exception thrown by javascript code" which is
// something you wouldn't want it to ignore.
getErrorWithStack . arguments ;
throw new Error ( ) ; // Fallback if above line don't throw.
} catch ( e ) {
return e ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
return new Error ( ) ;
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function prettyStack ( exception , numIgnoredFrames ) {
var stack = exception . stack ;
if ( ! stack ) return "" ;
numIgnoredFrames = numIgnoredFrames || 0 ;
if ( stack . indexOf ( exception . name ) === 0 ) numIgnoredFrames += ( exception . name + exception . message ) . split ( '\n' ) . length ;
return stack . split ( '\n' ) . slice ( numIgnoredFrames ) . filter ( libraryFilter ) . map ( function ( frame ) {
return "\n" + frame ;
} ) . join ( '' ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function deprecated ( what , fn ) {
return function ( ) {
console . warn ( what + " is deprecated. See https://github.com/dfahlander/Dexie.js/wiki/Deprecations. " + prettyStack ( getErrorWithStack ( ) , 1 ) ) ;
return fn . apply ( this , arguments ) ;
2018-11-05 23:32:33 +01:00
} ;
2018-11-21 01:42:52 +01:00
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
var dexieErrorNames = [ 'Modify' , 'Bulk' , 'OpenFailed' , 'VersionChange' , 'Schema' , 'Upgrade' , 'InvalidTable' , 'MissingAPI' , 'NoSuchDatabase' , 'InvalidArgument' , 'SubTransaction' , 'Unsupported' , 'Internal' , 'DatabaseClosed' , 'PrematureCommit' , 'ForeignAwait' ] ;
var idbDomErrorNames = [ 'Unknown' , 'Constraint' , 'Data' , 'TransactionInactive' , 'ReadOnly' , 'Version' , 'NotFound' , 'InvalidState' , 'InvalidAccess' , 'Abort' , 'Timeout' , 'QuotaExceeded' , 'Syntax' , 'DataClone' ] ;
var errorList = dexieErrorNames . concat ( idbDomErrorNames ) ;
var defaultTexts = {
VersionChanged : "Database version changed by other database connection" ,
DatabaseClosed : "Database has been closed" ,
Abort : "Transaction aborted" ,
TransactionInactive : "Transaction has already completed or failed"
} ; //
// DexieError - base class of all out exceptions.
//
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function DexieError ( name , msg ) {
// Reason we don't use ES6 classes is because:
// 1. It bloats transpiled code and increases size of minified code.
// 2. It doesn't give us much in this case.
// 3. It would require sub classes to call super(), which
// is not needed when deriving from Error.
this . _e = getErrorWithStack ( ) ;
this . name = name ;
this . message = msg ;
}
derive ( DexieError ) . from ( Error ) . extend ( {
stack : {
get : function ( ) {
return this . _stack || ( this . _stack = this . name + ": " + this . message + prettyStack ( this . _e , 2 ) ) ;
}
} ,
toString : function ( ) {
return this . name + ": " + this . message ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getMultiErrorMessage ( msg , failures ) {
return msg + ". Errors: " + failures . map ( function ( f ) {
return f . toString ( ) ;
} ) . filter ( function ( v , i , s ) {
return s . indexOf ( v ) === i ;
} ) // Only unique error strings
. join ( '\n' ) ;
} //
// ModifyError - thrown in Collection.modify()
// Specific constructor because it contains members failures and failedKeys.
//
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function ModifyError ( msg , failures , successCount , failedKeys ) {
this . _e = getErrorWithStack ( ) ;
this . failures = failures ;
this . failedKeys = failedKeys ;
this . successCount = successCount ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
derive ( ModifyError ) . from ( DexieError ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function BulkError ( msg , failures ) {
this . _e = getErrorWithStack ( ) ;
this . name = "BulkError" ;
this . failures = failures ;
this . message = getMultiErrorMessage ( msg , failures ) ;
}
derive ( BulkError ) . from ( DexieError ) ; //
//
// Dynamically generate error names and exception classes based
// on the names in errorList.
//
//
// Map of {ErrorName -> ErrorName + "Error"}
var errnames = errorList . reduce ( function ( obj , name ) {
return obj [ name ] = name + "Error" , obj ;
} , { } ) ; // Need an alias for DexieError because we're gonna create subclasses with the same name.
var BaseException = DexieError ; // Map of {ErrorName -> exception constructor}
var exceptions = errorList . reduce ( function ( obj , name ) {
// Let the name be "DexieError" because this name may
// be shown in call stack and when debugging. DexieError is
// the most true name because it derives from DexieError,
// and we cannot change Function.name programatically without
// dynamically create a Function object, which would be considered
// 'eval-evil'.
var fullName = name + "Error" ;
function DexieError ( msgOrInner , inner ) {
this . _e = getErrorWithStack ( ) ;
this . name = fullName ;
if ( ! msgOrInner ) {
this . message = defaultTexts [ name ] || fullName ;
this . inner = null ;
} else if ( typeof msgOrInner === 'string' ) {
this . message = msgOrInner ;
this . inner = inner || null ;
} else if ( _typeof ( msgOrInner ) === 'object' ) {
this . message = msgOrInner . name + " " + msgOrInner . message ;
this . inner = msgOrInner ;
}
}
derive ( DexieError ) . from ( BaseException ) ;
obj [ name ] = DexieError ;
return obj ;
} , { } ) ; // Use ECMASCRIPT standard exceptions where applicable:
exceptions . Syntax = SyntaxError ;
exceptions . Type = TypeError ;
exceptions . Range = RangeError ;
var exceptionMap = idbDomErrorNames . reduce ( function ( obj , name ) {
obj [ name + "Error" ] = exceptions [ name ] ;
return obj ;
} , { } ) ;
function mapError ( domError , message ) {
if ( ! domError || domError instanceof DexieError || domError instanceof TypeError || domError instanceof SyntaxError || ! domError . name || ! exceptionMap [ domError . name ] ) return domError ;
var rv = new exceptionMap [ domError . name ] ( message || domError . message , domError ) ;
if ( "stack" in domError ) {
// Derive stack from inner exception if it has a stack
setProp ( rv , "stack" , {
get : function ( ) {
return this . inner . stack ;
}
} ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
return rv ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var fullNameExceptions = errorList . reduce ( function ( obj , name ) {
if ( [ "Syntax" , "Type" , "Range" ] . indexOf ( name ) === - 1 ) obj [ name + "Error" ] = exceptions [ name ] ;
return obj ;
} , { } ) ;
fullNameExceptions . ModifyError = ModifyError ;
fullNameExceptions . DexieError = DexieError ;
fullNameExceptions . BulkError = BulkError ;
function nop ( ) { }
function mirror ( val ) {
return val ;
}
function pureFunctionChain ( f1 , f2 ) {
// Enables chained events that takes ONE argument and returns it to the next function in chain.
// This pattern is used in the hook("reading") event.
if ( f1 == null || f1 === mirror ) return f2 ;
return function ( val ) {
return f2 ( f1 ( val ) ) ;
2018-11-11 20:49:26 +01:00
} ;
2018-11-21 01:42:52 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function callBoth ( on1 , on2 ) {
return function ( ) {
on1 . apply ( this , arguments ) ;
on2 . apply ( this , arguments ) ;
} ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function hookCreatingChain ( f1 , f2 ) {
// Enables chained events that takes several arguments and may modify first argument by making a modification and then returning the same instance.
// This pattern is used in the hook("creating") event.
if ( f1 === nop ) return f2 ;
return function ( ) {
var res = f1 . apply ( this , arguments ) ;
if ( res !== undefined ) arguments [ 0 ] = res ;
var onsuccess = this . onsuccess ,
// In case event listener has set this.onsuccess
onerror = this . onerror ; // In case event listener has set this.onerror
this . onsuccess = null ;
this . onerror = null ;
var res2 = f2 . apply ( this , arguments ) ;
if ( onsuccess ) this . onsuccess = this . onsuccess ? callBoth ( onsuccess , this . onsuccess ) : onsuccess ;
if ( onerror ) this . onerror = this . onerror ? callBoth ( onerror , this . onerror ) : onerror ;
return res2 !== undefined ? res2 : res ;
} ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function hookDeletingChain ( f1 , f2 ) {
if ( f1 === nop ) return f2 ;
return function ( ) {
f1 . apply ( this , arguments ) ;
var onsuccess = this . onsuccess ,
// In case event listener has set this.onsuccess
onerror = this . onerror ; // In case event listener has set this.onerror
this . onsuccess = this . onerror = null ;
f2 . apply ( this , arguments ) ;
if ( onsuccess ) this . onsuccess = this . onsuccess ? callBoth ( onsuccess , this . onsuccess ) : onsuccess ;
if ( onerror ) this . onerror = this . onerror ? callBoth ( onerror , this . onerror ) : onerror ;
} ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function hookUpdatingChain ( f1 , f2 ) {
if ( f1 === nop ) return f2 ;
return function ( modifications ) {
var res = f1 . apply ( this , arguments ) ;
extend ( modifications , res ) ; // If f1 returns new modifications, extend caller's modifications with the result before calling next in chain.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var onsuccess = this . onsuccess ,
// In case event listener has set this.onsuccess
onerror = this . onerror ; // In case event listener has set this.onerror
this . onsuccess = null ;
this . onerror = null ;
var res2 = f2 . apply ( this , arguments ) ;
if ( onsuccess ) this . onsuccess = this . onsuccess ? callBoth ( onsuccess , this . onsuccess ) : onsuccess ;
if ( onerror ) this . onerror = this . onerror ? callBoth ( onerror , this . onerror ) : onerror ;
return res === undefined ? res2 === undefined ? undefined : res2 : extend ( res , res2 ) ;
} ;
}
function reverseStoppableEventChain ( f1 , f2 ) {
if ( f1 === nop ) return f2 ;
return function ( ) {
if ( f2 . apply ( this , arguments ) === false ) return false ;
return f1 . apply ( this , arguments ) ;
} ;
}
function promisableChain ( f1 , f2 ) {
if ( f1 === nop ) return f2 ;
return function ( ) {
var res = f1 . apply ( this , arguments ) ;
if ( res && typeof res . then === 'function' ) {
var thiz = this ,
i = arguments . length ,
args = new Array ( i ) ;
while ( i -- ) {
args [ i ] = arguments [ i ] ;
}
return res . then ( function ( ) {
return f2 . apply ( thiz , args ) ;
2018-11-11 20:49:26 +01:00
} ) ;
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
return f2 . apply ( this , arguments ) ;
} ;
}
/ *
* Copyright ( c ) 2014 - 2017 David Fahlander
* Apache License Version 2.0 , January 2004 , http : //www.apache.org/licenses/LICENSE-2.0
* /
//
// Promise and Zone (PSD) for Dexie library
//
// I started out writing this Promise class by copying promise-light (https://github.com/taylorhakes/promise-light) by
// https://github.com/taylorhakes - an A+ and ECMASCRIPT 6 compliant Promise implementation.
//
// In previous versions this was fixed by not calling setTimeout when knowing that the resolve() or reject() came from another
// tick. In Dexie v1.4.0, I've rewritten the Promise class entirely. Just some fragments of promise-light is left. I use
// another strategy now that simplifies everything a lot: to always execute callbacks in a new micro-task, but have an own micro-task
// engine that is indexedDB compliant across all browsers.
// Promise class has also been optimized a lot with inspiration from bluebird - to avoid closures as much as possible.
// Also with inspiration from bluebird, asyncronic stacks in debug mode.
//
// Specific non-standard features of this Promise class:
// * Custom zone support (a.k.a. PSD) with ability to keep zones also when using native promises as well as
// native async / await.
// * Promise.follow() method built upon the custom zone engine, that allows user to track all promises created from current stack frame
// and below + all promises that those promises creates or awaits.
// * Detect any unhandled promise in a PSD-scope (PSD.onunhandled).
//
// David Fahlander, https://github.com/dfahlander
//
// Just a pointer that only this module knows about.
// Used in Promise constructor to emulate a private constructor.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var INTERNAL = { } ; // Async stacks (long stacks) must not grow infinitely.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var LONG _STACKS _CLIP _LIMIT = 100 ;
var MAX _LONG _STACKS = 20 ;
var ZONE _ECHO _LIMIT = 7 ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var nativePromiseInstanceAndProto = function ( ) {
try {
// Be able to patch native async functions
return new Function ( "let F=async ()=>{},p=F();return [p,Object.getPrototypeOf(p),Promise.resolve(),F.constructor];" ) ( ) ;
} catch ( e ) {
var P = _global . Promise ;
return P ? [ P . resolve ( ) , P . prototype , P . resolve ( ) ] : [ ] ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ( ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var resolvedNativePromise = nativePromiseInstanceAndProto [ 0 ] ;
var nativePromiseProto = nativePromiseInstanceAndProto [ 1 ] ;
var resolvedGlobalPromise = nativePromiseInstanceAndProto [ 2 ] ;
var nativePromiseThen = nativePromiseProto && nativePromiseProto . then ;
var NativePromise = resolvedNativePromise && resolvedNativePromise . constructor ;
var AsyncFunction = nativePromiseInstanceAndProto [ 3 ] ;
var patchGlobalPromise = ! ! resolvedGlobalPromise ;
var stack _being _generated = false ;
/ * T h e d e f a u l t f u n c t i o n u s e d o n l y f o r t h e v e r y f i r s t p r o m i s e i n a p r o m i s e c h a i n .
As soon as then promise is resolved or rejected , all next tasks will be executed in micro ticks
emulated in this module . For indexedDB compatibility , this means that every method needs to
execute at least one promise before doing an indexedDB operation . Dexie will always call
db . ready ( ) . then ( ) for every operation to make sure the indexedDB event is started in an
indexedDB - compatible emulated micro task loop .
* /
var schedulePhysicalTick = resolvedGlobalPromise ? function ( ) {
resolvedGlobalPromise . then ( physicalTick ) ;
} : _global . setImmediate ? // setImmediate supported. Those modern platforms also supports Function.bind().
setImmediate . bind ( null , physicalTick ) : _global . MutationObserver ? // MutationObserver supported
function ( ) {
var hiddenDiv = document . createElement ( "div" ) ;
new MutationObserver ( function ( ) {
physicalTick ( ) ;
hiddenDiv = null ;
} ) . observe ( hiddenDiv , {
attributes : true
} ) ;
hiddenDiv . setAttribute ( 'i' , '1' ) ;
} : // No support for setImmediate or MutationObserver. No worry, setTimeout is only called
// once time. Every tick that follows will be our emulated micro tick.
// Could have uses setTimeout.bind(null, 0, physicalTick) if it wasnt for that FF13 and below has a bug
function ( ) {
setTimeout ( physicalTick , 0 ) ;
} ; // Configurable through Promise.scheduler.
// Don't export because it would be unsafe to let unknown
// code call it unless they do try..catch within their callback.
// This function can be retrieved through getter of Promise.scheduler though,
// but users must not do Promise.scheduler = myFuncThatThrowsException
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var asap$1 = function ( callback , args ) {
microtickQueue . push ( [ callback , args ] ) ;
if ( needsNewPhysicalTick ) {
schedulePhysicalTick ( ) ;
needsNewPhysicalTick = false ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var isOutsideMicroTick = true ;
var needsNewPhysicalTick = true ;
var unhandledErrors = [ ] ;
var rejectingErrors = [ ] ;
var currentFulfiller = null ;
var rejectionMapper = mirror ; // Remove in next major when removing error mapping of DOMErrors and DOMExceptions
var globalPSD = {
id : 'global' ,
global : true ,
ref : 0 ,
unhandleds : [ ] ,
onunhandled : globalError ,
pgp : false ,
env : { } ,
finalize : function ( ) {
this . unhandleds . forEach ( function ( uh ) {
try {
globalError ( uh [ 0 ] , uh [ 1 ] ) ;
} catch ( e ) { }
2018-11-11 20:49:26 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
} ;
var PSD = globalPSD ;
var microtickQueue = [ ] ; // Callbacks to call in this or next physical tick.
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var numScheduledCalls = 0 ; // Number of listener-calls left to do in this physical tick.
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var tickFinalizers = [ ] ; // Finalizers to call when there are no more async calls scheduled within current physical tick.
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function Promise ( fn ) {
if ( _typeof ( this ) !== 'object' ) throw new TypeError ( 'Promises must be constructed via new' ) ;
this . _listeners = [ ] ;
this . onuncatched = nop ; // Deprecate in next major. Not needed. Better to use global error handler.
// A library may set `promise._lib = true;` after promise is created to make resolve() or reject()
// execute the microtask engine implicitely within the call to resolve() or reject().
// To remain A+ compliant, a library must only set `_lib=true` if it can guarantee that the stack
// only contains library code when calling resolve() or reject().
// RULE OF THUMB: ONLY set _lib = true for promises explicitely resolving/rejecting directly from
// global scope (event handler, timer etc)!
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . _lib = false ; // Current async scope
var psd = this . _PSD = PSD ;
if ( debug ) {
this . _stackHolder = getErrorWithStack ( ) ;
this . _prev = null ;
this . _numPrev = 0 ; // Number of previous promises (for long stacks)
2018-11-11 20:49:26 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( typeof fn !== 'function' ) {
if ( fn !== INTERNAL ) throw new TypeError ( 'Not a function' ) ; // Private constructor (INTERNAL, state, value).
// Used internally by Promise.resolve() and Promise.reject().
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . _state = arguments [ 1 ] ;
this . _value = arguments [ 2 ] ;
if ( this . _state === false ) handleRejection ( this , this . _value ) ; // Map error, set stack and addPossiblyUnhandledError().
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
return ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
this . _state = null ; // null (=pending), false (=rejected) or true (=resolved)
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . _value = null ; // error or result
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
++ psd . ref ; // Refcounting current scope
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
executePromiseTask ( this , fn ) ;
} // Prepare a property descriptor to put onto Promise.prototype.then
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var thenProp = {
get : function ( ) {
var psd = PSD ,
microTaskId = totalEchoes ;
function then ( onFulfilled , onRejected ) {
var _this = this ;
var possibleAwait = ! psd . global && ( psd !== PSD || microTaskId !== totalEchoes ) ;
if ( possibleAwait ) decrementExpectedAwaits ( ) ;
var rv = new Promise ( function ( resolve , reject ) {
propagateToListener ( _this , new Listener ( nativeAwaitCompatibleWrap ( onFulfilled , psd , possibleAwait ) , nativeAwaitCompatibleWrap ( onRejected , psd , possibleAwait ) , resolve , reject , psd ) ) ;
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
debug && linkToPreviousPromise ( rv , this ) ;
return rv ;
2018-11-11 20:49:26 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
then . prototype = INTERNAL ; // For idempotense, see setter below.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return then ;
} ,
// Be idempotent and allow another framework (such as zone.js or another instance of a Dexie.Promise module) to replace Promise.prototype.then
// and when that framework wants to restore the original property, we must identify that and restore the original property descriptor.
set : function ( value ) {
setProp ( this , 'then' , value && value . prototype === INTERNAL ? thenProp : // Restore to original property descriptor.
{
get : function ( ) {
return value ; // Getter returning provided value (behaves like value is just changed)
} ,
set : thenProp . set // Keep a setter that is prepared to restore original.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
} ) ;
}
} ;
props ( Promise . prototype , {
then : thenProp ,
_then : function ( onFulfilled , onRejected ) {
// A little tinier version of then() that don't have to create a resulting promise.
propagateToListener ( this , new Listener ( null , null , onFulfilled , onRejected , PSD ) ) ;
} ,
catch : function ( onRejected ) {
if ( arguments . length === 1 ) return this . then ( null , onRejected ) ; // First argument is the Error type to catch
var type = arguments [ 0 ] ,
handler = arguments [ 1 ] ;
return typeof type === 'function' ? this . then ( null , function ( err ) {
// Catching errors by its constructor type (similar to java / c++ / c#)
// Sample: promise.catch(TypeError, function (e) { ... });
return err instanceof type ? handler ( err ) : PromiseReject ( err ) ;
} ) : this . then ( null , function ( err ) {
// Catching errors by the error.name property. Makes sense for indexedDB where error type
// is always DOMError but where e.name tells the actual error type.
// Sample: promise.catch('ConstraintError', function (e) { ... });
return err && err . name === type ? handler ( err ) : PromiseReject ( err ) ;
} ) ;
} ,
finally : function ( onFinally ) {
return this . then ( function ( value ) {
onFinally ( ) ;
return value ;
} , function ( err ) {
onFinally ( ) ;
return PromiseReject ( err ) ;
} ) ;
} ,
stack : {
get : function ( ) {
if ( this . _stack ) return this . _stack ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
try {
stack _being _generated = true ;
var stacks = getStack ( this , [ ] , MAX _LONG _STACKS ) ;
var stack = stacks . join ( "\nFrom previous: " ) ;
if ( this . _state !== null ) this . _stack = stack ; // Stack may be updated on reject.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return stack ;
} finally {
stack _being _generated = false ;
}
}
} ,
timeout : function ( ms , msg ) {
var _this = this ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return ms < Infinity ? new Promise ( function ( resolve , reject ) {
var handle = setTimeout ( function ( ) {
return reject ( new exceptions . Timeout ( msg ) ) ;
} , ms ) ;
_this . then ( resolve , reject ) . finally ( clearTimeout . bind ( null , handle ) ) ;
} ) : this ;
2018-11-02 21:25:47 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
if ( typeof Symbol !== 'undefined' && Symbol . toStringTag ) setProp ( Promise . prototype , Symbol . toStringTag , 'Promise' ) ; // Now that Promise.prototype is defined, we have all it takes to set globalPSD.env.
// Environment globals snapshotted on leaving global zone
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
globalPSD . env = snapShot ( ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function Listener ( onFulfilled , onRejected , resolve , reject , zone ) {
this . onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null ;
this . onRejected = typeof onRejected === 'function' ? onRejected : null ;
this . resolve = resolve ;
this . reject = reject ;
this . psd = zone ;
} // Promise Static Properties
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
props ( Promise , {
all : function ( ) {
var values = getArrayOf . apply ( null , arguments ) // Supports iterables, implicit arguments and array-like.
. map ( onPossibleParallellAsync ) ; // Handle parallell async/awaits
return new Promise ( function ( resolve , reject ) {
if ( values . length === 0 ) resolve ( [ ] ) ;
var remaining = values . length ;
values . forEach ( function ( a , i ) {
return Promise . resolve ( a ) . then ( function ( x ) {
values [ i ] = x ;
if ( ! -- remaining ) resolve ( values ) ;
} , reject ) ;
} ) ;
} ) ;
} ,
resolve : function ( value ) {
if ( value instanceof Promise ) return value ;
if ( value && typeof value . then === 'function' ) return new Promise ( function ( resolve , reject ) {
value . then ( resolve , reject ) ;
} ) ;
var rv = new Promise ( INTERNAL , true , value ) ;
linkToPreviousPromise ( rv , currentFulfiller ) ;
return rv ;
} ,
reject : PromiseReject ,
race : function ( ) {
var values = getArrayOf . apply ( null , arguments ) . map ( onPossibleParallellAsync ) ;
return new Promise ( function ( resolve , reject ) {
values . map ( function ( value ) {
return Promise . resolve ( value ) . then ( resolve , reject ) ;
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} ) ;
} ,
PSD : {
get : function ( ) {
return PSD ;
} ,
set : function ( value ) {
return PSD = value ;
}
} ,
//totalEchoes: {get: ()=>totalEchoes},
//task: {get: ()=>task},
newPSD : newScope ,
usePSD : usePSD ,
scheduler : {
get : function ( ) {
return asap$1 ;
} ,
set : function ( value ) {
asap$1 = value ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ,
rejectionMapper : {
get : function ( ) {
return rejectionMapper ;
} ,
set : function ( value ) {
rejectionMapper = value ;
} // Map reject failures
} ,
follow : function ( fn , zoneProps ) {
return new Promise ( function ( resolve , reject ) {
return newScope ( function ( resolve , reject ) {
var psd = PSD ;
psd . unhandleds = [ ] ; // For unhandled standard- or 3rd party Promises. Checked at psd.finalize()
psd . onunhandled = reject ; // Triggered directly on unhandled promises of this library.
psd . finalize = callBoth ( function ( ) {
var _this = this ; // Unhandled standard or 3rd part promises are put in PSD.unhandleds and
// examined upon scope completion while unhandled rejections in this Promise
// will trigger directly through psd.onunhandled
run _at _end _of _this _or _next _physical _tick ( function ( ) {
_this . unhandleds . length === 0 ? resolve ( ) : reject ( _this . unhandleds [ 0 ] ) ;
} ) ;
} , psd . finalize ) ;
fn ( ) ;
} , zoneProps , resolve , reject ) ;
} ) ;
2018-11-02 21:25:47 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
/ * *
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once .
*
* Makes no guarantees about asynchrony .
* /
function executePromiseTask ( promise , fn ) {
// Promise Resolution Procedure:
// https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
try {
fn ( function ( value ) {
if ( promise . _state !== null ) return ; // Already settled
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( value === promise ) throw new TypeError ( 'A promise cannot be resolved with itself.' ) ;
var shouldExecuteTick = promise . _lib && beginMicroTickScope ( ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( value && typeof value . then === 'function' ) {
executePromiseTask ( promise , function ( resolve , reject ) {
value instanceof Promise ? value . _then ( resolve , reject ) : value . then ( resolve , reject ) ;
} ) ;
} else {
promise . _state = true ;
promise . _value = value ;
propagateAllListeners ( promise ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( shouldExecuteTick ) endMicroTickScope ( ) ;
} , handleRejection . bind ( null , promise ) ) ; // If Function.bind is not supported. Exception is handled in catch below
} catch ( ex ) {
handleRejection ( promise , ex ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
function handleRejection ( promise , reason ) {
rejectingErrors . push ( reason ) ;
if ( promise . _state !== null ) return ;
var shouldExecuteTick = promise . _lib && beginMicroTickScope ( ) ;
reason = rejectionMapper ( reason ) ;
promise . _state = false ;
promise . _value = reason ;
debug && reason !== null && _typeof ( reason ) === 'object' && ! reason . _promise && tryCatch ( function ( ) {
var origProp = getPropertyDescriptor ( reason , "stack" ) ;
reason . _promise = promise ;
setProp ( reason , "stack" , {
get : function ( ) {
return stack _being _generated ? origProp && ( origProp . get ? origProp . get . apply ( reason ) : origProp . value ) : promise . stack ;
}
} ) ;
} ) ; // Add the failure to a list of possibly uncaught errors
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
addPossiblyUnhandledError ( promise ) ;
propagateAllListeners ( promise ) ;
if ( shouldExecuteTick ) endMicroTickScope ( ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function propagateAllListeners ( promise ) {
//debug && linkToPreviousPromise(promise);
var listeners = promise . _listeners ;
promise . _listeners = [ ] ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , len = listeners . length ; i < len ; ++ i ) {
propagateToListener ( promise , listeners [ i ] ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var psd = promise . _PSD ;
-- psd . ref || psd . finalize ( ) ; // if psd.ref reaches zero, call psd.finalize();
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( numScheduledCalls === 0 ) {
// If numScheduledCalls is 0, it means that our stack is not in a callback of a scheduled call,
// and that no deferreds where listening to this rejection or success.
// Since there is a risk that our stack can contain application code that may
// do stuff after this code is finished that may generate new calls, we cannot
// call finalizers here.
++ numScheduledCalls ;
asap$1 ( function ( ) {
if ( -- numScheduledCalls === 0 ) finalizePhysicalTick ( ) ; // Will detect unhandled errors
} , [ ] ) ;
}
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function propagateToListener ( promise , listener ) {
if ( promise . _state === null ) {
promise . _listeners . push ( listener ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var cb = promise . _state ? listener . onFulfilled : listener . onRejected ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( cb === null ) {
// This Listener doesnt have a listener for the event being triggered (onFulfilled or onReject) so lets forward the event to any eventual listeners on the Promise instance returned by then() or catch()
return ( promise . _state ? listener . resolve : listener . reject ) ( promise . _value ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
++ listener . psd . ref ;
++ numScheduledCalls ;
asap$1 ( callListener , [ cb , promise , listener ] ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
function callListener ( cb , promise , listener ) {
try {
// Set static variable currentFulfiller to the promise that is being fullfilled,
// so that we connect the chain of promises (for long stacks support)
currentFulfiller = promise ; // Call callback and resolve our listener with it's return value.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var ret ,
value = promise . _value ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( promise . _state ) {
// cb is onResolved
ret = cb ( value ) ;
} else {
// cb is onRejected
if ( rejectingErrors . length ) rejectingErrors = [ ] ;
ret = cb ( value ) ;
if ( rejectingErrors . indexOf ( value ) === - 1 ) markErrorAsHandled ( promise ) ; // Callback didnt do Promise.reject(err) nor reject(err) onto another promise.
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
listener . resolve ( ret ) ;
} catch ( e ) {
// Exception thrown in callback. Reject our listener.
listener . reject ( e ) ;
} finally {
// Restore env and currentFulfiller.
currentFulfiller = null ;
if ( -- numScheduledCalls === 0 ) finalizePhysicalTick ( ) ;
-- listener . psd . ref || listener . psd . finalize ( ) ;
}
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getStack ( promise , stacks , limit ) {
if ( stacks . length === limit ) return stacks ;
var stack = "" ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( promise . _state === false ) {
var failure = promise . _value ,
errorName ,
message ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( failure != null ) {
errorName = failure . name || "Error" ;
message = failure . message || failure ;
stack = prettyStack ( failure , 0 ) ;
} else {
errorName = failure ; // If error is undefined or null, show that.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
message = "" ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
stacks . push ( errorName + ( message ? ": " + message : "" ) + stack ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( debug ) {
stack = prettyStack ( promise . _stackHolder , 2 ) ;
if ( stack && stacks . indexOf ( stack ) === - 1 ) stacks . push ( stack ) ;
if ( promise . _prev ) getStack ( promise . _prev , stacks , limit ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
return stacks ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
function linkToPreviousPromise ( promise , prev ) {
// Support long stacks by linking to previous completed promise.
var numPrev = prev ? prev . _numPrev + 1 : 0 ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( numPrev < LONG _STACKS _CLIP _LIMIT ) {
promise . _prev = prev ;
promise . _numPrev = numPrev ;
}
}
/ * T h e c a l l b a c k t o s c h e d u l e w i t h s e t I m m e d i a t e ( ) o r s e t T i m e o u t ( ) .
It runs a virtual microtick and executes any callback registered in microtickQueue .
* /
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function physicalTick ( ) {
beginMicroTickScope ( ) && endMicroTickScope ( ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function beginMicroTickScope ( ) {
var wasRootExec = isOutsideMicroTick ;
isOutsideMicroTick = false ;
needsNewPhysicalTick = false ;
return wasRootExec ;
}
/ * E x e c u t e s m i c r o - t i c k s w i t h o u t d o i n g t r y . . c a t c h .
This can be possible because we only use this internally and
the registered functions are exception - safe ( they do try . . catch
internally before calling any external method ) . If registering
functions in the microtickQueue that are not exception - safe , this
would destroy the framework and make it instable . So we don ' t export
our asap method .
* /
2018-11-02 21:25:47 +01:00
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
function endMicroTickScope ( ) {
var callbacks , i , l ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
do {
while ( microtickQueue . length > 0 ) {
callbacks = microtickQueue ;
microtickQueue = [ ] ;
l = callbacks . length ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
for ( i = 0 ; i < l ; ++ i ) {
var item = callbacks [ i ] ;
item [ 0 ] . apply ( null , item [ 1 ] ) ;
}
}
} while ( microtickQueue . length > 0 ) ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
isOutsideMicroTick = true ;
needsNewPhysicalTick = true ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function finalizePhysicalTick ( ) {
var unhandledErrs = unhandledErrors ;
unhandledErrors = [ ] ;
unhandledErrs . forEach ( function ( p ) {
p . _PSD . onunhandled . call ( null , p . _value , p ) ;
} ) ;
var finalizers = tickFinalizers . slice ( 0 ) ; // Clone first because finalizer may remove itself from list.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var i = finalizers . length ;
while ( i ) {
finalizers [ -- i ] ( ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function run _at _end _of _this _or _next _physical _tick ( fn ) {
function finalizer ( ) {
fn ( ) ;
tickFinalizers . splice ( tickFinalizers . indexOf ( finalizer ) , 1 ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
tickFinalizers . push ( finalizer ) ;
++ numScheduledCalls ;
asap$1 ( function ( ) {
if ( -- numScheduledCalls === 0 ) finalizePhysicalTick ( ) ;
} , [ ] ) ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function addPossiblyUnhandledError ( promise ) {
// Only add to unhandledErrors if not already there. The first one to add to this list
// will be upon the first rejection so that the root cause (first promise in the
// rejection chain) is the one listed.
if ( ! unhandledErrors . some ( function ( p ) {
return p . _value === promise . _value ;
} ) ) unhandledErrors . push ( promise ) ;
}
function markErrorAsHandled ( promise ) {
// Called when a reject handled is actually being called.
// Search in unhandledErrors for any promise whos _value is this promise_value (list
// contains only rejected promises, and only one item per error)
var i = unhandledErrors . length ;
while ( i ) {
if ( unhandledErrors [ -- i ] . _value === promise . _value ) {
// Found a promise that failed with this same error object pointer,
// Remove that since there is a listener that actually takes care of it.
unhandledErrors . splice ( i , 1 ) ;
return ;
}
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function PromiseReject ( reason ) {
return new Promise ( INTERNAL , false , reason ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function wrap ( fn , errorCatcher ) {
var psd = PSD ;
return function ( ) {
var wasRootExec = beginMicroTickScope ( ) ,
outerScope = PSD ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
try {
switchToZone ( psd , true ) ;
return fn . apply ( this , arguments ) ;
} catch ( e ) {
errorCatcher && errorCatcher ( e ) ;
} finally {
switchToZone ( outerScope , false ) ;
if ( wasRootExec ) endMicroTickScope ( ) ;
}
} ;
} //
// variables used for native await support
//
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var task = {
awaits : 0 ,
echoes : 0 ,
id : 0
} ; // The ongoing macro-task when using zone-echoing.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var taskCounter = 0 ; // ID counter for macro tasks.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var zoneStack = [ ] ; // Stack of left zones to restore asynchronically.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var zoneEchoes = 0 ; // zoneEchoes is a must in order to persist zones between native await expressions.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
var totalEchoes = 0 ; // ID counter for micro-tasks. Used to detect possible native await in our Promise.prototype.then.
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var zone _id _counter = 0 ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function newScope ( fn , props$$1 , a1 , a2 ) {
var parent = PSD ,
psd = Object . create ( parent ) ;
psd . parent = parent ;
psd . ref = 0 ;
psd . global = false ;
psd . id = ++ zone _id _counter ; // Prepare for promise patching (done in usePSD):
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var globalEnv = globalPSD . env ;
psd . env = patchGlobalPromise ? {
Promise : Promise ,
PromiseProp : {
value : Promise ,
configurable : true ,
writable : true
} ,
all : Promise . all ,
race : Promise . race ,
resolve : Promise . resolve ,
reject : Promise . reject ,
nthen : getPatchedPromiseThen ( globalEnv . nthen , psd ) ,
gthen : getPatchedPromiseThen ( globalEnv . gthen , psd ) // global then
} : { } ;
if ( props$$1 ) extend ( psd , props$$1 ) ; // unhandleds and onunhandled should not be specifically set here.
// Leave them on parent prototype.
// unhandleds.push(err) will push to parent's prototype
// onunhandled() will call parents onunhandled (with this scope's this-pointer though!)
++ parent . ref ;
psd . finalize = function ( ) {
-- this . parent . ref || this . parent . finalize ( ) ;
} ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var rv = usePSD ( psd , fn , a1 , a2 ) ;
if ( psd . ref === 0 ) psd . finalize ( ) ;
return rv ;
} // Function to call if scopeFunc returns NativePromise
// Also for each NativePromise in the arguments to Promise.all()
function incrementExpectedAwaits ( ) {
if ( ! task . id ) task . id = ++ taskCounter ;
++ task . awaits ;
task . echoes += ZONE _ECHO _LIMIT ;
return task . id ;
} // Function to call when 'then' calls back on a native promise where onAwaitExpected() had been called.
// Also call this when a native await calls then method on a promise. In that case, don't supply
// sourceTaskId because we already know it refers to current task.
function decrementExpectedAwaits ( sourceTaskId ) {
if ( ! task . awaits || sourceTaskId && sourceTaskId !== task . id ) return ;
if ( -- task . awaits === 0 ) task . id = 0 ;
task . echoes = task . awaits * ZONE _ECHO _LIMIT ; // Will reset echoes to 0 if awaits is 0.
} // Call from Promise.all() and Promise.race()
function onPossibleParallellAsync ( possiblePromise ) {
if ( task . echoes && possiblePromise && possiblePromise . constructor === NativePromise ) {
incrementExpectedAwaits ( ) ;
return possiblePromise . then ( function ( x ) {
decrementExpectedAwaits ( ) ;
return x ;
} , function ( e ) {
decrementExpectedAwaits ( ) ;
return rejection ( e ) ;
2018-11-11 20:49:26 +01:00
} ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return possiblePromise ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function zoneEnterEcho ( targetZone ) {
++ totalEchoes ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( ! task . echoes || -- task . echoes === 0 ) {
task . echoes = task . id = 0 ; // Cancel zone echoing.
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
zoneStack . push ( PSD ) ;
switchToZone ( targetZone , true ) ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function zoneLeaveEcho ( ) {
var zone = zoneStack [ zoneStack . length - 1 ] ;
zoneStack . pop ( ) ;
switchToZone ( zone , false ) ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function switchToZone ( targetZone , bEnteringZone ) {
var currentZone = PSD ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( bEnteringZone ? task . echoes && ( ! zoneEchoes ++ || targetZone !== PSD ) : zoneEchoes && ( ! -- zoneEchoes || targetZone !== PSD ) ) {
// Enter or leave zone asynchronically as well, so that tasks initiated during current tick
// will be surrounded by the zone when they are invoked.
enqueueNativeMicroTask ( bEnteringZone ? zoneEnterEcho . bind ( null , targetZone ) : zoneLeaveEcho ) ;
2018-11-05 23:32:33 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( targetZone === PSD ) return ;
PSD = targetZone ; // The actual zone switch occurs at this line.
// Snapshot on every leave from global zone.
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( currentZone === globalPSD ) globalPSD . env = snapShot ( ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( patchGlobalPromise ) {
// Let's patch the global and native Promises (may be same or may be different)
var GlobalPromise = globalPSD . env . Promise ; // Swich environments (may be PSD-zone or the global zone. Both apply.)
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
var targetEnv = targetZone . env ; // Change Promise.prototype.then for native and global Promise (they MAY differ on polyfilled environments, but both can be accessed)
// Must be done on each zone change because the patched method contains targetZone in its closure.
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
nativePromiseProto . then = targetEnv . nthen ;
GlobalPromise . prototype . then = targetEnv . gthen ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( currentZone . global || targetZone . global ) {
// Leaving or entering global zone. It's time to patch / restore global Promise.
// Set this Promise to window.Promise so that transiled async functions will work on Firefox, Safari and IE, as well as with Zonejs and angular.
Object . defineProperty ( _global , 'Promise' , targetEnv . PromiseProp ) ; // Support Promise.all() etc to work indexedDB-safe also when people are including es6-promise as a module (they might
// not be accessing global.Promise but a local reference to it)
GlobalPromise . all = targetEnv . all ;
GlobalPromise . race = targetEnv . race ;
GlobalPromise . resolve = targetEnv . resolve ;
GlobalPromise . reject = targetEnv . reject ;
}
2018-11-05 23:32:33 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function snapShot ( ) {
var GlobalPromise = _global . Promise ;
return patchGlobalPromise ? {
Promise : GlobalPromise ,
PromiseProp : Object . getOwnPropertyDescriptor ( _global , "Promise" ) ,
all : GlobalPromise . all ,
race : GlobalPromise . race ,
resolve : GlobalPromise . resolve ,
reject : GlobalPromise . reject ,
nthen : nativePromiseProto . then ,
gthen : GlobalPromise . prototype . then
} : { } ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function usePSD ( psd , fn , a1 , a2 , a3 ) {
var outerScope = PSD ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
try {
switchToZone ( psd , true ) ;
return fn ( a1 , a2 , a3 ) ;
} finally {
switchToZone ( outerScope , false ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function enqueueNativeMicroTask ( job ) {
//
// Precondition: nativePromiseThen !== undefined
//
nativePromiseThen . call ( resolvedNativePromise , job ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function nativeAwaitCompatibleWrap ( fn , zone , possibleAwait ) {
return typeof fn !== 'function' ? fn : function ( ) {
var outerZone = PSD ;
if ( possibleAwait ) incrementExpectedAwaits ( ) ;
switchToZone ( zone , true ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
try {
return fn . apply ( this , arguments ) ;
} finally {
switchToZone ( outerZone , false ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getPatchedPromiseThen ( origThen , zone ) {
return function ( onResolved , onRejected ) {
return origThen . call ( this , nativeAwaitCompatibleWrap ( onResolved , zone , false ) , nativeAwaitCompatibleWrap ( onRejected , zone , false ) ) ;
} ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var UNHANDLEDREJECTION = "unhandledrejection" ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function globalError ( err , promise ) {
var rv ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
try {
rv = promise . onuncatched ( err ) ;
} catch ( e ) { }
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( rv !== false ) try {
var event ,
eventData = {
promise : promise ,
reason : err
2018-11-05 23:32:33 +01:00
} ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( _global . document && document . createEvent ) {
event = document . createEvent ( 'Event' ) ;
event . initEvent ( UNHANDLEDREJECTION , true , true ) ;
extend ( event , eventData ) ;
} else if ( _global . CustomEvent ) {
event = new CustomEvent ( UNHANDLEDREJECTION , {
detail : eventData
} ) ;
extend ( event , eventData ) ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( event && _global . dispatchEvent ) {
dispatchEvent ( event ) ;
if ( ! _global . PromiseRejectionEvent && _global . onunhandledrejection ) // No native support for PromiseRejectionEvent but user has set window.onunhandledrejection. Manually call it.
try {
_global . onunhandledrejection ( event ) ;
} catch ( _ ) { }
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( ! event . defaultPrevented ) {
console . warn ( "Unhandled rejection: " + ( err . stack || err ) ) ;
}
} catch ( e ) { }
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var rejection = Promise . reject ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function Events ( ctx ) {
var evs = { } ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
var rv = function ( eventName , subscriber ) {
if ( subscriber ) {
// Subscribe. If additional arguments than just the subscriber was provided, forward them as well.
var i = arguments . length ,
args = new Array ( i - 1 ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
while ( -- i ) {
args [ i - 1 ] = arguments [ i ] ;
}
evs [ eventName ] . subscribe . apply ( null , args ) ;
return ctx ;
} else if ( typeof eventName === 'string' ) {
// Return interface allowing to fire or unsubscribe from event
return evs [ eventName ] ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
rv . addEventType = add ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 1 , l = arguments . length ; i < l ; ++ i ) {
add ( arguments [ i ] ) ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
return rv ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function add ( eventName , chainFunction , defaultFunction ) {
if ( _typeof ( eventName ) === 'object' ) return addConfiguredEvents ( eventName ) ;
if ( ! chainFunction ) chainFunction = reverseStoppableEventChain ;
if ( ! defaultFunction ) defaultFunction = nop ;
var context = {
subscribers : [ ] ,
fire : defaultFunction ,
subscribe : function ( cb ) {
if ( context . subscribers . indexOf ( cb ) === - 1 ) {
context . subscribers . push ( cb ) ;
context . fire = chainFunction ( context . fire , cb ) ;
}
} ,
unsubscribe : function ( cb ) {
context . subscribers = context . subscribers . filter ( function ( fn ) {
return fn !== cb ;
} ) ;
context . fire = context . subscribers . reduce ( chainFunction , defaultFunction ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ;
evs [ eventName ] = rv [ eventName ] = context ;
return context ;
}
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function addConfiguredEvents ( cfg ) {
// events(this, {reading: [functionChain, nop]});
keys ( cfg ) . forEach ( function ( eventName ) {
var args = cfg [ eventName ] ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( isArray ( args ) ) {
add ( eventName , cfg [ eventName ] [ 0 ] , cfg [ eventName ] [ 1 ] ) ;
} else if ( args === 'asap' ) {
// Rather than approaching event subscription using a functional approach, we here do it in a for-loop where subscriber is executed in its own stack
// enabling that any exception that occur wont disturb the initiator and also not nescessary be catched and forgotten.
var context = add ( eventName , mirror , function fire ( ) {
// Optimazation-safe cloning of arguments into args.
var i = arguments . length ,
args = new Array ( i ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
while ( i -- ) {
args [ i ] = arguments [ i ] ;
} // All each subscriber:
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
context . subscribers . forEach ( function ( fn ) {
asap ( function fireEvent ( ) {
fn . apply ( null , args ) ;
} ) ;
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} ) ;
} else throw new exceptions . InvalidArgument ( "Invalid event config" ) ;
} ) ;
}
}
/ *
* Dexie . js - a minimalistic wrapper for IndexedDB
* === === === === === === === === === === === === === === === ==
*
* Copyright ( c ) 2014 - 2017 David Fahlander
*
* Version { version } , { date }
*
* http : //dexie.org
*
* Apache License Version 2.0 , January 2004 , http : //www.apache.org/licenses/LICENSE-2.0
*
* /
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
var DEXIE _VERSION = '{version}' ;
var maxString = String . fromCharCode ( 65535 ) ;
var maxKey = function ( ) {
try {
IDBKeyRange . only ( [ [ ] ] ) ;
return [ [ ] ] ;
} catch ( e ) {
return maxString ;
2018-11-02 21:25:47 +01:00
}
2018-11-21 01:42:52 +01:00
} ( ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var minKey = - Infinity ;
var INVALID _KEY _ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>." ;
var STRING _EXPECTED = "String expected." ;
var connections = [ ] ;
var isIEOrEdge = typeof navigator !== 'undefined' && /(MSIE|Trident|Edge)/ . test ( navigator . userAgent ) ;
var hasIEDeleteObjectStoreBug = isIEOrEdge ;
var hangsOnDeleteLargeKeyRange = isIEOrEdge ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var dexieStackFrameFilter = function ( frame ) {
return ! /(dexie\.js|dexie\.min\.js)/ . test ( frame ) ;
} ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
var dbNamesDB ; // Global database for backing Dexie.getDatabaseNames() on browser without indexedDB.webkitGetDatabaseNames()
// Init debug
setDebug ( debug , dexieStackFrameFilter ) ;
function Dexie ( dbName , options ) {
/// <param name="options" type="Object" optional="true">Specify only if you wich to control which addons that should run on this instance</param>
var deps = Dexie . dependencies ;
var opts = extend ( {
// Default Options
addons : Dexie . addons ,
autoOpen : true ,
indexedDB : deps . indexedDB ,
IDBKeyRange : deps . IDBKeyRange // Backend IDBKeyRange api. Default to browser env.
} , options ) ;
var addons = opts . addons ,
autoOpen = opts . autoOpen ,
indexedDB = opts . indexedDB ,
IDBKeyRange = opts . IDBKeyRange ;
var globalSchema = this . _dbSchema = { } ;
var versions = [ ] ;
var dbStoreNames = [ ] ;
var allTables = { } ; ///<var type="IDBDatabase" />
var idbdb = null ; // Instance of IDBDatabase
var dbOpenError = null ;
var isBeingOpened = false ;
var onReadyBeingFired = null ;
var openComplete = false ;
var READONLY = "readonly" ,
READWRITE = "readwrite" ;
var db = this ;
var dbReadyResolve ,
dbReadyPromise = new Promise ( function ( resolve ) {
dbReadyResolve = resolve ;
} ) ,
cancelOpen ,
openCanceller = new Promise ( function ( _ , reject ) {
cancelOpen = reject ;
} ) ;
var autoSchema = true ;
var hasNativeGetDatabaseNames = ! ! getNativeGetDatabaseNamesFn ( indexedDB ) ,
hasGetAll ;
function init ( ) {
// Default subscribers to "versionchange" and "blocked".
// Can be overridden by custom handlers. If custom handlers return false, these default
// behaviours will be prevented.
db . on ( "versionchange" , function ( ev ) {
// Default behavior for versionchange event is to close database connection.
// Caller can override this behavior by doing db.on("versionchange", function(){ return false; });
// Let's not block the other window from making it's delete() or open() call.
// NOTE! This event is never fired in IE,Edge or Safari.
if ( ev . newVersion > 0 ) console . warn ( "Another connection wants to upgrade database '" + db . name + "'. Closing db now to resume the upgrade." ) ; else console . warn ( "Another connection wants to delete database '" + db . name + "'. Closing db now to resume the delete request." ) ;
db . close ( ) ; // In many web applications, it would be recommended to force window.reload()
// when this event occurs. To do that, subscribe to the versionchange event
// and call window.location.reload(true) if ev.newVersion > 0 (not a deletion)
// The reason for this is that your current web app obviously has old schema code that needs
// to be updated. Another window got a newer version of the app and needs to upgrade DB but
// your window is blocking it unless we close it here.
} ) ;
db . on ( "blocked" , function ( ev ) {
if ( ! ev . newVersion || ev . newVersion < ev . oldVersion ) console . warn ( "Dexie.delete('" + db . name + "') was blocked" ) ; else console . warn ( "Upgrade '" + db . name + "' blocked by other connection holding version " + ev . oldVersion / 10 ) ;
} ) ;
} //
//
//
// ------------------------- Versioning Framework---------------------------
//
//
//
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . version = function ( versionNumber ) {
/// <param name="versionNumber" type="Number"></param>
/// <returns type="Version"></returns>
if ( idbdb || isBeingOpened ) throw new exceptions . Schema ( "Cannot add version when database is open" ) ;
this . verno = Math . max ( this . verno , versionNumber ) ;
var versionInstance = versions . filter ( function ( v ) {
return v . _cfg . version === versionNumber ;
} ) [ 0 ] ;
if ( versionInstance ) return versionInstance ;
versionInstance = new Version ( versionNumber ) ;
versions . push ( versionInstance ) ;
versions . sort ( lowerVersionFirst ) ; // Disable autoschema mode, as at least one version is specified.
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
autoSchema = false ;
return versionInstance ;
} ;
function Version ( versionNumber ) {
this . _cfg = {
version : versionNumber ,
storesSource : null ,
dbschema : { } ,
tables : { } ,
contentUpgrade : null
2018-11-11 20:49:26 +01:00
} ;
2018-11-21 01:42:52 +01:00
this . stores ( { } ) ; // Derive earlier schemas by default.
}
extend ( Version . prototype , {
stores : function ( stores ) {
/// <summary>
/// Defines the schema for a particular version
/// </summary>
/// <param name="stores" type="Object">
/// Example: <br/>
/// {users: "id++,first,last,&username,*email", <br/>
/// passwords: "id++,&username"}<br/>
/// <br/>
/// Syntax: {Table: "[primaryKey][++],[&][*]index1,[&][*]index2,..."}<br/><br/>
/// Special characters:<br/>
/// "&" means unique key, <br/>
/// "*" means value is multiEntry, <br/>
/// "++" means auto-increment and only applicable for primary key <br/>
/// </param>
this . _cfg . storesSource = this . _cfg . storesSource ? extend ( this . _cfg . storesSource , stores ) : stores ; // Derive stores from earlier versions if they are not explicitely specified as null or a new syntax.
var storesSpec = { } ;
versions . forEach ( function ( version ) {
extend ( storesSpec , version . _cfg . storesSource ) ;
} ) ;
var dbschema = this . _cfg . dbschema = { } ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . _parseStoresSpec ( storesSpec , dbschema ) ; // Update the latest schema to this version
// Update API
globalSchema = db . _dbSchema = dbschema ;
removeTablesApi ( [ allTables , db , Transaction . prototype ] ) ; // Keep Transaction.prototype even though it should be depr.
setApiOnPlace ( [ allTables , db , Transaction . prototype , this . _cfg . tables ] , keys ( dbschema ) , dbschema ) ;
dbStoreNames = keys ( dbschema ) ;
return this ;
} ,
upgrade : function ( upgradeFunction ) {
this . _cfg . contentUpgrade = upgradeFunction ;
return this ;
} ,
_parseStoresSpec : function ( stores , outSchema ) {
keys ( stores ) . forEach ( function ( tableName ) {
if ( stores [ tableName ] !== null ) {
var instanceTemplate = { } ;
var indexes = parseIndexSyntax ( stores [ tableName ] ) ;
var primKey = indexes . shift ( ) ;
if ( primKey . multi ) throw new exceptions . Schema ( "Primary key cannot be multi-valued" ) ;
if ( primKey . keyPath ) setByKeyPath ( instanceTemplate , primKey . keyPath , primKey . auto ? 0 : primKey . keyPath ) ;
indexes . forEach ( function ( idx ) {
if ( idx . auto ) throw new exceptions . Schema ( "Only primary key can be marked as autoIncrement (++)" ) ;
if ( ! idx . keyPath ) throw new exceptions . Schema ( "Index must have a name and cannot be an empty string" ) ;
setByKeyPath ( instanceTemplate , idx . keyPath , idx . compound ? idx . keyPath . map ( function ( ) {
return "" ;
} ) : "" ) ;
} ) ;
outSchema [ tableName ] = new TableSchema ( tableName , primKey , indexes , instanceTemplate ) ;
}
} ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function runUpgraders ( oldVersion , idbtrans , reject ) {
var trans = db . _createTransaction ( READWRITE , dbStoreNames , globalSchema ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
trans . create ( idbtrans ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
trans . _completion . catch ( reject ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
var rejectTransaction = trans . _reject . bind ( trans ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
newScope ( function ( ) {
PSD . trans = trans ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( oldVersion === 0 ) {
// Create tables:
keys ( globalSchema ) . forEach ( function ( tableName ) {
createTable ( idbtrans , tableName , globalSchema [ tableName ] . primKey , globalSchema [ tableName ] . indexes ) ;
} ) ;
Promise . follow ( function ( ) {
return db . on . populate . fire ( trans ) ;
} ) . catch ( rejectTransaction ) ;
} else updateTablesAndIndexes ( oldVersion , trans , idbtrans ) . catch ( rejectTransaction ) ;
} ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function updateTablesAndIndexes ( oldVersion , trans , idbtrans ) {
// Upgrade version to version, step-by-step from oldest to newest version.
// Each transaction object will contain the table set that was current in that version (but also not-yet-deleted tables from its previous version)
var queue = [ ] ;
var oldVersionStruct = versions . filter ( function ( version ) {
return version . _cfg . version === oldVersion ;
} ) [ 0 ] ;
if ( ! oldVersionStruct ) throw new exceptions . Upgrade ( "Dexie specification of currently installed DB version is missing" ) ;
globalSchema = db . _dbSchema = oldVersionStruct . _cfg . dbschema ;
var anyContentUpgraderHasRun = false ;
var versToRun = versions . filter ( function ( v ) {
return v . _cfg . version > oldVersion ;
} ) ;
versToRun . forEach ( function ( version ) {
/// <param name="version" type="Version"></param>
queue . push ( function ( ) {
var oldSchema = globalSchema ;
var newSchema = version . _cfg . dbschema ;
adjustToExistingIndexNames ( oldSchema , idbtrans ) ;
adjustToExistingIndexNames ( newSchema , idbtrans ) ;
globalSchema = db . _dbSchema = newSchema ;
var diff = getSchemaDiff ( oldSchema , newSchema ) ; // Add tables
diff . add . forEach ( function ( tuple ) {
createTable ( idbtrans , tuple [ 0 ] , tuple [ 1 ] . primKey , tuple [ 1 ] . indexes ) ;
} ) ; // Change tables
diff . change . forEach ( function ( change ) {
if ( change . recreate ) {
throw new exceptions . Upgrade ( "Not yet support for changing primary key" ) ;
} else {
var store = idbtrans . objectStore ( change . name ) ; // Add indexes
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
change . add . forEach ( function ( idx ) {
addIndex ( store , idx ) ;
} ) ; // Update indexes
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
change . change . forEach ( function ( idx ) {
store . deleteIndex ( idx . name ) ;
addIndex ( store , idx ) ;
} ) ; // Delete indexes
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
change . del . forEach ( function ( idxName ) {
store . deleteIndex ( idxName ) ;
} ) ;
}
} ) ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( version . _cfg . contentUpgrade ) {
anyContentUpgraderHasRun = true ;
return Promise . follow ( function ( ) {
version . _cfg . contentUpgrade ( trans ) ;
} ) ;
}
} ) ;
queue . push ( function ( idbtrans ) {
if ( ! anyContentUpgraderHasRun || ! hasIEDeleteObjectStoreBug ) {
var newSchema = version . _cfg . dbschema ; // Delete old tables
deleteRemovedTables ( newSchema , idbtrans ) ;
}
} ) ;
} ) ; // Now, create a queue execution engine
function runQueue ( ) {
return queue . length ? Promise . resolve ( queue . shift ( ) ( trans . idbtrans ) ) . then ( runQueue ) : Promise . resolve ( ) ;
2018-11-11 20:49:26 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return runQueue ( ) . then ( function ( ) {
createMissingTables ( globalSchema , idbtrans ) ; // At last, make sure to create any missing tables. (Needed by addons that add stores to DB without specifying version)
} ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function getSchemaDiff ( oldSchema , newSchema ) {
var diff = {
del : [ ] ,
add : [ ] ,
change : [ ] // Array of {name: tableName, recreate: newDefinition, del: delIndexNames, add: newIndexDefs, change: changedIndexDefs}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
} ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( var table in oldSchema ) {
if ( ! newSchema [ table ] ) diff . del . push ( table ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( table in newSchema ) {
var oldDef = oldSchema [ table ] ,
newDef = newSchema [ table ] ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( ! oldDef ) {
diff . add . push ( [ table , newDef ] ) ;
} else {
var change = {
name : table ,
def : newDef ,
recreate : false ,
del : [ ] ,
add : [ ] ,
change : [ ]
} ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( oldDef . primKey . src !== newDef . primKey . src ) {
// Primary key has changed. Remove and re-add table.
change . recreate = true ;
diff . change . push ( change ) ;
} else {
// Same primary key. Just find out what differs:
var oldIndexes = oldDef . idxByName ;
var newIndexes = newDef . idxByName ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( var idxName in oldIndexes ) {
if ( ! newIndexes [ idxName ] ) change . del . push ( idxName ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
for ( idxName in newIndexes ) {
var oldIdx = oldIndexes [ idxName ] ,
newIdx = newIndexes [ idxName ] ;
if ( ! oldIdx ) change . add . push ( newIdx ) ; else if ( oldIdx . src !== newIdx . src ) change . change . push ( newIdx ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( change . del . length > 0 || change . add . length > 0 || change . change . length > 0 ) {
diff . change . push ( change ) ;
}
}
}
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return diff ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function createTable ( idbtrans , tableName , primKey , indexes ) {
/// <param name="idbtrans" type="IDBTransaction"></param>
var store = idbtrans . db . createObjectStore ( tableName , primKey . keyPath ? {
keyPath : primKey . keyPath ,
autoIncrement : primKey . auto
} : {
autoIncrement : primKey . auto
} ) ;
indexes . forEach ( function ( idx ) {
addIndex ( store , idx ) ;
} ) ;
return store ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function createMissingTables ( newSchema , idbtrans ) {
keys ( newSchema ) . forEach ( function ( tableName ) {
if ( ! idbtrans . db . objectStoreNames . contains ( tableName ) ) {
createTable ( idbtrans , tableName , newSchema [ tableName ] . primKey , newSchema [ tableName ] . indexes ) ;
}
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
function deleteRemovedTables ( newSchema , idbtrans ) {
for ( var i = 0 ; i < idbtrans . db . objectStoreNames . length ; ++ i ) {
var storeName = idbtrans . db . objectStoreNames [ i ] ;
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
if ( newSchema [ storeName ] == null ) {
idbtrans . db . deleteObjectStore ( storeName ) ;
}
}
}
function addIndex ( store , idx ) {
store . createIndex ( idx . name , idx . keyPath , {
unique : idx . unique ,
multiEntry : idx . multi
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} //
//
// Dexie Protected API
//
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . _allTables = allTables ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
this . _createTransaction = function ( mode , storeNames , dbschema , parentTransaction ) {
return new Transaction ( mode , storeNames , dbschema , parentTransaction ) ;
2018-11-11 20:49:26 +01:00
} ;
2018-11-21 01:42:52 +01:00
/ * G e n e r a t e a t e m p o r a r y t r a n s a c t i o n w h e n d b o p e r a t i o n s a r e d o n e o u t s i d e a t r a n s a c t i o n s c o p e .
* /
2018-11-11 20:49:26 +01:00
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function tempTransaction ( mode , storeNames , fn ) {
if ( ! openComplete && ! PSD . letThrough ) {
if ( ! isBeingOpened ) {
if ( ! autoOpen ) return rejection ( new exceptions . DatabaseClosed ( ) ) ;
db . open ( ) . catch ( nop ) ; // Open in background. If if fails, it will be catched by the final promise anyway.
}
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
return dbReadyPromise . then ( function ( ) {
return tempTransaction ( mode , storeNames , fn ) ;
} ) ;
} else {
var trans = db . _createTransaction ( mode , storeNames , globalSchema ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
trans . create ( ) ;
} catch ( ex ) {
return rejection ( ex ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return trans . _promise ( mode , function ( resolve , reject ) {
return newScope ( function ( ) {
PSD . trans = trans ;
return fn ( resolve , reject , trans ) ;
} ) ;
} ) . then ( function ( result ) {
// Instead of resolving value directly, wait with resolving it until transaction has completed.
// Otherwise the data would not be in the DB if requesting it in the then() operation.
// Specifically, to ensure that the following expression will work:
//
// db.friends.put({name: "Arne"}).then(function () {
// db.friends.where("name").equals("Arne").count(function(count) {
// assert (count === 1);
// });
// });
//
return trans . _completion . then ( function ( ) {
return result ;
} ) ;
} ) ;
/*.catch(err => { / / Don ' t do this as of now . If would affect bulk - and modify methods in a way that could be more intuitive . But wait ! Maybe change in next major .
trans . _reject ( err ) ;
return rejection ( err ) ;
} ) ; * /
}
2018-11-05 23:32:33 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . _whenReady = function ( fn ) {
return openComplete || PSD . letThrough ? fn ( ) : new Promise ( function ( resolve , reject ) {
if ( ! isBeingOpened ) {
if ( ! autoOpen ) {
reject ( new exceptions . DatabaseClosed ( ) ) ;
return ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
db . open ( ) . catch ( nop ) ; // Open in background. If if fails, it will be catched by the final promise anyway.
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
dbReadyPromise . then ( resolve , reject ) ;
} ) . then ( fn ) ;
} ; //
//
//
//
// Dexie API
//
//
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . verno = 0 ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . open = function ( ) {
if ( isBeingOpened || idbdb ) return dbReadyPromise . then ( function ( ) {
return dbOpenError ? rejection ( dbOpenError ) : db ;
} ) ;
debug && ( openCanceller . _stackHolder = getErrorWithStack ( ) ) ; // Let stacks point to when open() was called rather than where new Dexie() was called.
isBeingOpened = true ;
dbOpenError = null ;
openComplete = false ; // Function pointers to call when the core opening process completes.
var resolveDbReady = dbReadyResolve ,
// upgradeTransaction to abort on failure.
upgradeTransaction = null ;
return Promise . race ( [ openCanceller , new Promise ( function ( resolve , reject ) {
// Multiply db.verno with 10 will be needed to workaround upgrading bug in IE:
// IE fails when deleting objectStore after reading from it.
// A future version of Dexie.js will stopover an intermediate version to workaround this.
// At that point, we want to be backward compatible. Could have been multiplied with 2, but by using 10, it is easier to map the number to the real version number.
// If no API, throw!
if ( ! indexedDB ) throw new exceptions . MissingAPI ( "indexedDB API not found. If using IE10+, make sure to run your code on a server URL " + "(not locally). If using old Safari versions, make sure to include indexedDB polyfill." ) ;
var req = autoSchema ? indexedDB . open ( dbName ) : indexedDB . open ( dbName , Math . round ( db . verno * 10 ) ) ;
if ( ! req ) throw new exceptions . MissingAPI ( "IndexedDB API not available" ) ; // May happen in Safari private mode, see https://github.com/dfahlander/Dexie.js/issues/134
req . onerror = eventRejectHandler ( reject ) ;
req . onblocked = wrap ( fireOnBlocked ) ;
req . onupgradeneeded = wrap ( function ( e ) {
upgradeTransaction = req . transaction ;
if ( autoSchema && ! db . _allowEmptyDB ) {
// Caller did not specify a version or schema. Doing that is only acceptable for opening alread existing databases.
// If onupgradeneeded is called it means database did not exist. Reject the open() promise and make sure that we
// do not create a new database by accident here.
req . onerror = preventDefault ; // Prohibit onabort error from firing before we're done!
upgradeTransaction . abort ( ) ; // Abort transaction (would hope that this would make DB disappear but it doesnt.)
// Close database and delete it.
req . result . close ( ) ;
var delreq = indexedDB . deleteDatabase ( dbName ) ; // The upgrade transaction is atomic, and javascript is single threaded - meaning that there is no risk that we delete someone elses database here!
delreq . onsuccess = delreq . onerror = wrap ( function ( ) {
reject ( new exceptions . NoSuchDatabase ( "Database " + dbName + " doesnt exist" ) ) ;
} ) ;
} else {
upgradeTransaction . onerror = eventRejectHandler ( reject ) ;
var oldVer = e . oldVersion > Math . pow ( 2 , 62 ) ? 0 : e . oldVersion ; // Safari 8 fix.
runUpgraders ( oldVer / 10 , upgradeTransaction , reject , req ) ;
}
} , reject ) ;
req . onsuccess = wrap ( function ( ) {
// Core opening procedure complete. Now let's just record some stuff.
upgradeTransaction = null ;
idbdb = req . result ;
connections . push ( db ) ; // Used for emulating versionchange event on IE/Edge/Safari.
if ( autoSchema ) readGlobalSchema ( ) ; else if ( idbdb . objectStoreNames . length > 0 ) {
try {
adjustToExistingIndexNames ( globalSchema , idbdb . transaction ( safariMultiStoreFix ( idbdb . objectStoreNames ) , READONLY ) ) ;
} catch ( e ) { // Safari may bail out if > 1 store names. However, this shouldnt be a showstopper. Issue #120.
}
}
idbdb . onversionchange = wrap ( function ( ev ) {
db . _vcFired = true ; // detect implementations that not support versionchange (IE/Edge/Safari)
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
db . on ( "versionchange" ) . fire ( ev ) ;
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( ! hasNativeGetDatabaseNames && dbName !== '__dbnames' ) {
dbNamesDB . dbnames . put ( {
name : dbName
} ) . catch ( nop ) ;
}
resolve ( ) ;
} , reject ) ;
} ) ] ) . then ( function ( ) {
// Before finally resolving the dbReadyPromise and this promise,
// call and await all on('ready') subscribers:
// Dexie.vip() makes subscribers able to use the database while being opened.
// This is a must since these subscribers take part of the opening procedure.
onReadyBeingFired = [ ] ;
return Promise . resolve ( Dexie . vip ( db . on . ready . fire ) ) . then ( function fireRemainders ( ) {
if ( onReadyBeingFired . length > 0 ) {
// In case additional subscribers to db.on('ready') were added during the time db.on.ready.fire was executed.
var remainders = onReadyBeingFired . reduce ( promisableChain , nop ) ;
onReadyBeingFired = [ ] ;
return Promise . resolve ( Dexie . vip ( remainders ) ) . then ( fireRemainders ) ;
}
} ) ;
} ) . finally ( function ( ) {
onReadyBeingFired = null ;
} ) . then ( function ( ) {
// Resolve the db.open() with the db instance.
isBeingOpened = false ;
return db ;
} ) . catch ( function ( err ) {
try {
// Did we fail within onupgradeneeded? Make sure to abort the upgrade transaction so it doesnt commit.
upgradeTransaction && upgradeTransaction . abort ( ) ;
} catch ( e ) { }
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
isBeingOpened = false ; // Set before calling db.close() so that it doesnt reject openCanceller again (leads to unhandled rejection event).
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
db . close ( ) ; // Closes and resets idbdb, removes connections, resets dbReadyPromise and openCanceller so that a later db.open() is fresh.
// A call to db.close() may have made on-ready subscribers fail. Use dbOpenError if set, since err could be a follow-up error on that.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
dbOpenError = err ; // Record the error. It will be used to reject further promises of db operations.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return rejection ( dbOpenError ) ;
} ) . finally ( function ( ) {
openComplete = true ;
resolveDbReady ( ) ; // dbReadyPromise is resolved no matter if open() rejects or resolved. It's just to wake up waiters.
} ) ;
2018-11-11 20:49:26 +01:00
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . close = function ( ) {
var idx = connections . indexOf ( db ) ;
if ( idx >= 0 ) connections . splice ( idx , 1 ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( idbdb ) {
try {
idbdb . close ( ) ;
} catch ( e ) { }
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
idbdb = null ;
2018-11-11 20:49:26 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
autoOpen = false ;
dbOpenError = new exceptions . DatabaseClosed ( ) ;
if ( isBeingOpened ) cancelOpen ( dbOpenError ) ; // Reset dbReadyPromise promise:
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
dbReadyPromise = new Promise ( function ( resolve ) {
dbReadyResolve = resolve ;
} ) ;
openCanceller = new Promise ( function ( _ , reject ) {
cancelOpen = reject ;
} ) ;
2018-11-11 20:49:26 +01:00
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . delete = function ( ) {
var hasArguments = arguments . length > 0 ;
return new Promise ( function ( resolve , reject ) {
if ( hasArguments ) throw new exceptions . InvalidArgument ( "Arguments not allowed in db.delete()" ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( isBeingOpened ) {
dbReadyPromise . then ( doDelete ) ;
} else {
doDelete ( ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function doDelete ( ) {
db . close ( ) ;
var req = indexedDB . deleteDatabase ( dbName ) ;
req . onsuccess = wrap ( function ( ) {
if ( ! hasNativeGetDatabaseNames ) {
dbNamesDB . dbnames . delete ( dbName ) . catch ( nop ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
resolve ( ) ;
} ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onblocked = fireOnBlocked ;
}
} ) ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . backendDB = function ( ) {
return idbdb ;
} ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
this . isOpen = function ( ) {
return idbdb !== null ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . hasBeenClosed = function ( ) {
return dbOpenError && dbOpenError instanceof exceptions . DatabaseClosed ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . hasFailed = function ( ) {
return dbOpenError !== null ;
2018-11-11 20:49:26 +01:00
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . dynamicallyOpened = function ( ) {
return autoSchema ;
} ; //
// Properties
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . name = dbName ; // db.tables - an array of all Table instances.
props ( this , {
tables : {
get : function ( ) {
/// <returns type="Array" elementType="Table" />
return keys ( allTables ) . map ( function ( name ) {
return allTables [ name ] ;
} ) ;
}
2018-11-11 20:49:26 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ; //
// Events
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . on = Events ( this , "populate" , "blocked" , "versionchange" , {
ready : [ promisableChain , nop ]
} ) ;
this . on . ready . subscribe = override ( this . on . ready . subscribe , function ( subscribe ) {
return function ( subscriber , bSticky ) {
Dexie . vip ( function ( ) {
if ( openComplete ) {
// Database already open. Call subscriber asap.
if ( ! dbOpenError ) Promise . resolve ( ) . then ( subscriber ) ; // bSticky: Also subscribe to future open sucesses (after close / reopen)
if ( bSticky ) subscribe ( subscriber ) ;
} else if ( onReadyBeingFired ) {
// db.on('ready') subscribers are currently being executed and have not yet resolved or rejected
onReadyBeingFired . push ( subscriber ) ;
if ( bSticky ) subscribe ( subscriber ) ;
} else {
// Database not yet open. Subscribe to it.
subscribe ( subscriber ) ; // If bSticky is falsy, make sure to unsubscribe subscriber when fired once.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( ! bSticky ) subscribe ( function unsubscribe ( ) {
db . on . ready . unsubscribe ( subscriber ) ;
db . on . ready . unsubscribe ( unsubscribe ) ;
} ) ;
}
} ) ;
} ;
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . transaction = function ( ) {
/// <summary>
///
/// </summary>
/// <param name="mode" type="String">"r" for readonly, or "rw" for readwrite</param>
/// <param name="tableInstances">Table instance, Array of Table instances, String or String Array of object stores to include in the transaction</param>
/// <param name="scopeFunc" type="Function">Function to execute with transaction</param>
var args = extractTransactionArgs . apply ( this , arguments ) ;
return this . _transaction . apply ( this , args ) ;
} ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
function extractTransactionArgs ( mode , _tableArgs _ , scopeFunc ) {
// Let table arguments be all arguments between mode and last argument.
var i = arguments . length ;
if ( i < 2 ) throw new exceptions . InvalidArgument ( "Too few arguments" ) ; // Prevent optimzation killer (https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments)
// and clone arguments except the first one into local var 'args'.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var args = new Array ( i - 1 ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
while ( -- i ) {
args [ i - 1 ] = arguments [ i ] ;
} // Let scopeFunc be the last argument and pop it so that args now only contain the table arguments.
2018-10-31 17:00:31 +01:00
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
scopeFunc = args . pop ( ) ;
var tables = flatten ( args ) ; // Support using array as middle argument, or a mix of arrays and non-arrays.
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
return [ mode , tables , scopeFunc ] ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . _transaction = function ( mode , tables , scopeFunc ) {
var parentTransaction = PSD . trans ; // Check if parent transactions is bound to this db instance, and if caller wants to reuse it
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( ! parentTransaction || parentTransaction . db !== db || mode . indexOf ( '!' ) !== - 1 ) parentTransaction = null ;
var onlyIfCompatible = mode . indexOf ( '?' ) !== - 1 ;
mode = mode . replace ( '!' , '' ) . replace ( '?' , '' ) ; // Ok. Will change arguments[0] as well but we wont touch arguments henceforth.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
//
// Get storeNames from arguments. Either through given table instances, or through given table names.
//
var storeNames = tables . map ( function ( table ) {
var storeName = table instanceof Table ? table . name : table ;
if ( typeof storeName !== 'string' ) throw new TypeError ( "Invalid table argument to Dexie.transaction(). Only Table or String are allowed" ) ;
return storeName ;
} ) ; //
// Resolve mode. Allow shortcuts "r" and "rw".
//
if ( mode == "r" || mode == READONLY ) mode = READONLY ; else if ( mode == "rw" || mode == READWRITE ) mode = READWRITE ; else throw new exceptions . InvalidArgument ( "Invalid transaction mode: " + mode ) ;
if ( parentTransaction ) {
// Basic checks
if ( parentTransaction . mode === READONLY && mode === READWRITE ) {
if ( onlyIfCompatible ) {
// Spawn new transaction instead.
parentTransaction = null ;
} else throw new exceptions . SubTransaction ( "Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY" ) ;
}
if ( parentTransaction ) {
storeNames . forEach ( function ( storeName ) {
if ( parentTransaction && parentTransaction . storeNames . indexOf ( storeName ) === - 1 ) {
if ( onlyIfCompatible ) {
// Spawn new transaction instead.
parentTransaction = null ;
} else throw new exceptions . SubTransaction ( "Table " + storeName + " not included in parent transaction." ) ;
}
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( onlyIfCompatible && parentTransaction && ! parentTransaction . active ) {
// '?' mode should not keep using an inactive transaction.
parentTransaction = null ;
}
}
} catch ( e ) {
return parentTransaction ? parentTransaction . _promise ( null , function ( _ , reject ) {
reject ( e ) ;
} ) : rejection ( e ) ;
} // If this is a sub-transaction, lock the parent and then launch the sub-transaction.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return parentTransaction ? parentTransaction . _promise ( mode , enterTransactionScope , "lock" ) : PSD . trans ? // no parent transaction despite PSD.trans exists. Make sure also
// that the zone we create is not a sub-zone of current, because
// Promise.follow() should not wait for it if so.
usePSD ( PSD . transless , function ( ) {
return db . _whenReady ( enterTransactionScope ) ;
} ) : db . _whenReady ( enterTransactionScope ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function enterTransactionScope ( ) {
return Promise . resolve ( ) . then ( function ( ) {
// Keep a pointer to last non-transactional PSD to use if someone calls Dexie.ignoreTransaction().
var transless = PSD . transless || PSD ; // Our transaction.
//return new Promise((resolve, reject) => {
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var trans = db . _createTransaction ( mode , storeNames , globalSchema , parentTransaction ) ; // Let the transaction instance be part of a Promise-specific data (PSD) value.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var zoneProps = {
trans : trans ,
transless : transless
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( parentTransaction ) {
// Emulate transaction commit awareness for inner transaction (must 'commit' when the inner transaction has no more operations ongoing)
trans . idbtrans = parentTransaction . idbtrans ;
} else {
trans . create ( ) ; // Create the backend transaction so that complete() or error() will trigger even if no operation is made upon it.
} // Support for native async await.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( scopeFunc . constructor === AsyncFunction ) {
incrementExpectedAwaits ( ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var returnValue ;
var promiseFollowed = Promise . follow ( function ( ) {
// Finally, call the scope function with our table and transaction arguments.
returnValue = scopeFunc . call ( trans , trans ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( returnValue ) {
if ( returnValue . constructor === NativePromise ) {
var decrementor = decrementExpectedAwaits . bind ( null , null ) ;
returnValue . then ( decrementor , decrementor ) ;
} else if ( typeof returnValue . next === 'function' && typeof returnValue . throw === 'function' ) {
// scopeFunc returned an iterator with throw-support. Handle yield as await.
returnValue = awaitIterator ( returnValue ) ;
}
}
} , zoneProps ) ;
return ( returnValue && typeof returnValue . then === 'function' ? // Promise returned. User uses promise-style transactions.
Promise . resolve ( returnValue ) . then ( function ( x ) {
return trans . active ? x // Transaction still active. Continue.
: rejection ( new exceptions . PrematureCommit ( "Transaction committed too early. See http://bit.ly/2kdckMn" ) ) ;
} ) // No promise returned. Wait for all outstanding promises before continuing.
: promiseFollowed . then ( function ( ) {
return returnValue ;
} ) ) . then ( function ( x ) {
// sub transactions don't react to idbtrans.oncomplete. We must trigger a completion:
if ( parentTransaction ) trans . _resolve ( ) ; // wait for trans._completion
// (if root transaction, this means 'complete' event. If sub-transaction, we've just fired it ourselves)
return trans . _completion . then ( function ( ) {
return x ;
} ) ;
} ) . catch ( function ( e ) {
trans . _reject ( e ) ; // Yes, above then-handler were maybe not called because of an unhandled rejection in scopeFunc!
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return rejection ( e ) ;
} ) ;
} ) ;
}
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . table = function ( tableName ) {
/// <returns type="Table"></returns>
if ( ! hasOwn ( allTables , tableName ) ) {
throw new exceptions . InvalidTable ( "Table " + tableName + " does not exist" ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return allTables [ tableName ] ;
} ; //
//
//
// Table Class
//
//
//
2018-10-31 17:00:31 +01:00
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
function Table ( name , tableSchema , optionalTrans ) {
/// <param name="name" type="String"></param>
this . name = name ;
this . schema = tableSchema ;
this . _tx = optionalTrans ;
this . hook = allTables [ name ] ? allTables [ name ] . hook : Events ( null , {
"creating" : [ hookCreatingChain , nop ] ,
"reading" : [ pureFunctionChain , mirror ] ,
"updating" : [ hookUpdatingChain , nop ] ,
"deleting" : [ hookDeletingChain , nop ]
} ) ;
2018-10-31 17:00:31 +01:00
}
2018-11-21 01:42:52 +01:00
function BulkErrorHandlerCatchAll ( errorList , done , supportHooks ) {
return ( supportHooks ? hookedEventRejectHandler : eventRejectHandler ) ( function ( e ) {
errorList . push ( e ) ;
done && done ( ) ;
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function bulkDelete ( idbstore , trans , keysOrTuples , hasDeleteHook , deletingHook ) {
// If hasDeleteHook, keysOrTuples must be an array of tuples: [[key1, value2],[key2,value2],...],
// else keysOrTuples must be just an array of keys: [key1, key2, ...].
return new Promise ( function ( resolve , reject ) {
var len = keysOrTuples . length ,
lastItem = len - 1 ;
if ( len === 0 ) return resolve ( ) ;
if ( ! hasDeleteHook ) {
for ( var i = 0 ; i < len ; ++ i ) {
var req = idbstore . delete ( keysOrTuples [ i ] ) ;
req . onerror = eventRejectHandler ( reject ) ;
if ( i === lastItem ) req . onsuccess = wrap ( function ( ) {
return resolve ( ) ;
} ) ;
}
} else {
var hookCtx ,
errorHandler = hookedEventRejectHandler ( reject ) ,
successHandler = hookedEventSuccessHandler ( null ) ;
tryCatch ( function ( ) {
for ( var i = 0 ; i < len ; ++ i ) {
hookCtx = {
onsuccess : null ,
onerror : null
} ;
var tuple = keysOrTuples [ i ] ;
deletingHook . call ( hookCtx , tuple [ 0 ] , tuple [ 1 ] , trans ) ;
var req = idbstore . delete ( tuple [ 0 ] ) ;
req . _hookCtx = hookCtx ;
req . onerror = errorHandler ;
if ( i === lastItem ) req . onsuccess = hookedEventSuccessHandler ( resolve ) ; else req . onsuccess = successHandler ;
}
} , function ( err ) {
hookCtx . onerror && hookCtx . onerror ( err ) ;
throw err ;
} ) ;
}
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
props ( Table . prototype , {
//
// Table Protected Methods
//
_trans : function getTransaction ( mode , fn , writeLocked ) {
var trans = this . _tx || PSD . trans ;
return trans && trans . db === db ? trans === PSD . trans ? trans . _promise ( mode , fn , writeLocked ) : newScope ( function ( ) {
return trans . _promise ( mode , fn , writeLocked ) ;
} , {
trans : trans ,
transless : PSD . transless || PSD
} ) : tempTransaction ( mode , [ this . name ] , fn ) ;
} ,
_idbstore : function getIDBObjectStore ( mode , fn , writeLocked ) {
var tableName = this . name ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function supplyIdbStore ( resolve , reject , trans ) {
if ( trans . storeNames . indexOf ( tableName ) === - 1 ) throw new exceptions . NotFound ( "Table" + tableName + " not part of transaction" ) ;
return fn ( resolve , reject , trans . idbtrans . objectStore ( tableName ) , trans ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return this . _trans ( mode , supplyIdbStore , writeLocked ) ;
} ,
//
// Table Public Methods
//
get : function ( keyOrCrit , cb ) {
if ( keyOrCrit && keyOrCrit . constructor === Object ) return this . where ( keyOrCrit ) . first ( cb ) ;
var self = this ;
return this . _idbstore ( READONLY , function ( resolve , reject , idbstore ) {
var req = idbstore . get ( keyOrCrit ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = wrap ( function ( ) {
resolve ( self . hook . reading . fire ( req . result ) ) ;
} , reject ) ;
} ) . then ( cb ) ;
} ,
where : function ( indexOrCrit ) {
if ( typeof indexOrCrit === 'string' ) return new WhereClause ( this , indexOrCrit ) ;
if ( isArray ( indexOrCrit ) ) return new WhereClause ( this , "[" + indexOrCrit . join ( '+' ) + "]" ) ; // indexOrCrit is an object map of {[keyPath]:value}
var keyPaths = keys ( indexOrCrit ) ;
if ( keyPaths . length === 1 ) // Only one critera. This was the easy case:
return this . where ( keyPaths [ 0 ] ) . equals ( indexOrCrit [ keyPaths [ 0 ] ] ) ; // Multiple criterias.
// Let's try finding a compound index that matches all keyPaths in
// arbritary order:
var compoundIndex = this . schema . indexes . concat ( this . schema . primKey ) . filter ( function ( ix ) {
return ix . compound && keyPaths . every ( function ( keyPath ) {
return ix . keyPath . indexOf ( keyPath ) >= 0 ;
} ) && ix . keyPath . every ( function ( keyPath ) {
return keyPaths . indexOf ( keyPath ) >= 0 ;
} ) ;
} ) [ 0 ] ;
if ( compoundIndex && maxKey !== maxString ) // Cool! We found such compound index
// and this browser supports compound indexes (maxKey !== maxString)!
return this . where ( compoundIndex . name ) . equals ( compoundIndex . keyPath . map ( function ( kp ) {
return indexOrCrit [ kp ] ;
} ) ) ;
if ( ! compoundIndex ) console . warn ( "The query " + JSON . stringify ( indexOrCrit ) + " on " + this . name + " would benefit of a " + ( "compound index [" + keyPaths . join ( '+' ) + "]" ) ) ; // Ok, now let's fallback to finding at least one matching index
// and filter the rest.
var idxByName = this . schema . idxByName ;
var simpleIndex = keyPaths . reduce ( function ( r , keyPath ) {
return [ r [ 0 ] || idxByName [ keyPath ] , r [ 0 ] || ! idxByName [ keyPath ] ? combine ( r [ 1 ] , function ( x ) {
return '' + getByKeyPath ( x , keyPath ) == '' + indexOrCrit [ keyPath ] ;
} ) : r [ 1 ] ] ;
} , [ null , null ] ) ;
var idx = simpleIndex [ 0 ] ;
return idx ? this . where ( idx . name ) . equals ( indexOrCrit [ idx . keyPath ] ) . filter ( simpleIndex [ 1 ] ) : compoundIndex ? this . filter ( simpleIndex [ 1 ] ) : // Has compound but browser bad. Allow filter.
this . where ( keyPaths ) . equals ( '' ) ; // No index at all. Fail lazily.
} ,
count : function ( cb ) {
return this . toCollection ( ) . count ( cb ) ;
} ,
offset : function ( offset ) {
return this . toCollection ( ) . offset ( offset ) ;
} ,
limit : function ( numRows ) {
return this . toCollection ( ) . limit ( numRows ) ;
} ,
reverse : function ( ) {
return this . toCollection ( ) . reverse ( ) ;
} ,
filter : function ( filterFunction ) {
return this . toCollection ( ) . and ( filterFunction ) ;
} ,
each : function ( fn ) {
return this . toCollection ( ) . each ( fn ) ;
} ,
toArray : function ( cb ) {
return this . toCollection ( ) . toArray ( cb ) ;
} ,
orderBy : function ( index ) {
return new Collection ( new WhereClause ( this , isArray ( index ) ? "[" + index . join ( '+' ) + "]" : index ) ) ;
} ,
toCollection : function ( ) {
return new Collection ( new WhereClause ( this ) ) ;
} ,
mapToClass : function ( constructor , structure ) {
/// <summary>
/// Map table to a javascript constructor function. Objects returned from the database will be instances of this class, making
/// it possible to the instanceOf operator as well as extending the class using constructor.prototype.method = function(){...}.
/// </summary>
/// <param name="constructor">Constructor function representing the class.</param>
/// <param name="structure" optional="true">Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also
/// know what type each member has. Example: {name: String, emailAddresses: [String], password}</param>
this . schema . mappedClass = constructor ;
var instanceTemplate = Object . create ( constructor . prototype ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( structure ) {
// structure and instanceTemplate is for IDE code competion only while constructor.prototype is for actual inheritance.
applyStructure ( instanceTemplate , structure ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
this . schema . instanceTemplate = instanceTemplate ; // Now, subscribe to the when("reading") event to make all objects that come out from this table inherit from given class
// no matter which method to use for reading (Table.get() or Table.where(...)... )
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var readHook = function ( obj ) {
if ( ! obj ) return obj ; // No valid object. (Value is null). Return as is.
// Create a new object that derives from constructor:
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var res = Object . create ( constructor . prototype ) ; // Clone members:
2018-11-03 19:06:09 +01:00
2018-11-21 01:42:52 +01:00
for ( var m in obj ) {
if ( hasOwn ( obj , m ) ) try {
res [ m ] = obj [ m ] ;
} catch ( _ ) { }
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
return res ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( this . schema . readHook ) {
this . hook . reading . unsubscribe ( this . schema . readHook ) ;
}
2018-11-02 21:25:47 +01:00
2018-11-21 01:42:52 +01:00
this . schema . readHook = readHook ;
this . hook ( "reading" , readHook ) ;
return constructor ;
} ,
defineClass : function ( structure ) {
/// <summary>
/// Define all members of the class that represents the table. This will help code completion of when objects are read from the database
/// as well as making it possible to extend the prototype of the returned constructor function.
/// </summary>
/// <param name="structure">Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also
/// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}}</param>
return this . mapToClass ( Dexie . defineClass ( structure ) , structure ) ;
} ,
bulkDelete : function ( keys$$1 ) {
if ( this . hook . deleting . fire === nop ) {
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore , trans ) {
resolve ( bulkDelete ( idbstore , trans , keys$$1 , false , nop ) ) ;
} ) ;
} else {
return this . where ( ':id' ) . anyOf ( keys$$1 ) . delete ( ) . then ( function ( ) { } ) ; // Resolve with undefined.
}
} ,
bulkPut : function ( objects , keys$$1 ) {
var _this = this ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore ) {
if ( ! idbstore . keyPath && ! _this . schema . primKey . auto && ! keys$$1 ) throw new exceptions . InvalidArgument ( "bulkPut() with non-inbound keys requires keys array in second argument" ) ;
if ( idbstore . keyPath && keys$$1 ) throw new exceptions . InvalidArgument ( "bulkPut(): keys argument invalid on tables with inbound keys" ) ;
if ( keys$$1 && keys$$1 . length !== objects . length ) throw new exceptions . InvalidArgument ( "Arguments objects and keys must have the same length" ) ;
if ( objects . length === 0 ) return resolve ( ) ; // Caller provided empty list.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var done = function ( result ) {
if ( errorList . length === 0 ) resolve ( result ) ; else reject ( new BulkError ( _this . name + ".bulkPut(): " + errorList . length + " of " + numObjs + " operations failed" , errorList ) ) ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var req ,
errorList = [ ] ,
errorHandler ,
numObjs = objects . length ,
table = _this ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( _this . hook . creating . fire === nop && _this . hook . updating . fire === nop ) {
//
// Standard Bulk (no 'creating' or 'updating' hooks to care about)
//
errorHandler = BulkErrorHandlerCatchAll ( errorList ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , l = objects . length ; i < l ; ++ i ) {
req = keys$$1 ? idbstore . put ( objects [ i ] , keys$$1 [ i ] ) : idbstore . put ( objects [ i ] ) ;
req . onerror = errorHandler ;
} // Only need to catch success or error on the last operation
// according to the IDB spec.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
req . onerror = BulkErrorHandlerCatchAll ( errorList , done ) ;
req . onsuccess = eventSuccessHandler ( done ) ;
} else {
var effectiveKeys = keys$$1 || idbstore . keyPath && objects . map ( function ( o ) {
return getByKeyPath ( o , idbstore . keyPath ) ;
} ) ; // Generate map of {[key]: object}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var objectLookup = effectiveKeys && arrayToObject ( effectiveKeys , function ( key , i ) {
return key != null && [ key , objects [ i ] ] ;
} ) ;
var promise = ! effectiveKeys ? // Auto-incremented key-less objects only without any keys argument.
table . bulkAdd ( objects ) : // Keys provided. Either as inbound in provided objects, or as a keys argument.
// Begin with updating those that exists in DB:
table . where ( ':id' ) . anyOf ( effectiveKeys . filter ( function ( key ) {
return key != null ;
} ) ) . modify ( function ( ) {
this . value = objectLookup [ this . primKey ] ;
objectLookup [ this . primKey ] = null ; // Mark as "don't add this"
} ) . catch ( ModifyError , function ( e ) {
errorList = e . failures ; // No need to concat here. These are the first errors added.
} ) . then ( function ( ) {
// Now, let's examine which items didnt exist so we can add them:
var objsToAdd = [ ] ,
keysToAdd = keys$$1 && [ ] ; // Iterate backwards. Why? Because if same key was used twice, just add the last one.
for ( var i = effectiveKeys . length - 1 ; i >= 0 ; -- i ) {
var key = effectiveKeys [ i ] ;
if ( key == null || objectLookup [ key ] ) {
objsToAdd . push ( objects [ i ] ) ;
keys$$1 && keysToAdd . push ( key ) ;
if ( key != null ) objectLookup [ key ] = null ; // Mark as "dont add again"
}
} // The items are in reverse order so reverse them before adding.
// Could be important in order to get auto-incremented keys the way the caller
// would expect. Could have used unshift instead of push()/reverse(),
// but: http://jsperf.com/unshift-vs-reverse
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
objsToAdd . reverse ( ) ;
keys$$1 && keysToAdd . reverse ( ) ;
return table . bulkAdd ( objsToAdd , keysToAdd ) ;
} ) . then ( function ( lastAddedKey ) {
// Resolve with key of the last object in given arguments to bulkPut():
var lastEffectiveKey = effectiveKeys [ effectiveKeys . length - 1 ] ; // Key was provided.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return lastEffectiveKey != null ? lastEffectiveKey : lastAddedKey ;
} ) ;
promise . then ( done ) . catch ( BulkError , function ( e ) {
// Concat failure from ModifyError and reject using our 'done' method.
errorList = errorList . concat ( e . failures ) ;
done ( ) ;
} ) . catch ( reject ) ;
}
} , "locked" ) ; // If called from transaction scope, lock transaction til all steps are done.
} ,
bulkAdd : function ( objects , keys$$1 ) {
var self = this ,
creatingHook = this . hook . creating . fire ;
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore , trans ) {
if ( ! idbstore . keyPath && ! self . schema . primKey . auto && ! keys$$1 ) throw new exceptions . InvalidArgument ( "bulkAdd() with non-inbound keys requires keys array in second argument" ) ;
if ( idbstore . keyPath && keys$$1 ) throw new exceptions . InvalidArgument ( "bulkAdd(): keys argument invalid on tables with inbound keys" ) ;
if ( keys$$1 && keys$$1 . length !== objects . length ) throw new exceptions . InvalidArgument ( "Arguments objects and keys must have the same length" ) ;
if ( objects . length === 0 ) return resolve ( ) ; // Caller provided empty list.
function done ( result ) {
if ( errorList . length === 0 ) resolve ( result ) ; else reject ( new BulkError ( self . name + ".bulkAdd(): " + errorList . length + " of " + numObjs + " operations failed" , errorList ) ) ;
}
var req ,
errorList = [ ] ,
errorHandler ,
successHandler ,
numObjs = objects . length ;
if ( creatingHook !== nop ) {
//
// There are subscribers to hook('creating')
// Must behave as documented.
//
var keyPath = idbstore . keyPath ,
hookCtx ;
errorHandler = BulkErrorHandlerCatchAll ( errorList , null , true ) ;
successHandler = hookedEventSuccessHandler ( null ) ;
tryCatch ( function ( ) {
for ( var i = 0 , l = objects . length ; i < l ; ++ i ) {
hookCtx = {
onerror : null ,
onsuccess : null
} ;
var key = keys$$1 && keys$$1 [ i ] ;
var obj = objects [ i ] ,
effectiveKey = keys$$1 ? key : keyPath ? getByKeyPath ( obj , keyPath ) : undefined ,
keyToUse = creatingHook . call ( hookCtx , effectiveKey , obj , trans ) ;
if ( effectiveKey == null && keyToUse != null ) {
if ( keyPath ) {
obj = deepClone ( obj ) ;
setByKeyPath ( obj , keyPath , keyToUse ) ;
} else {
key = keyToUse ;
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
req = key != null ? idbstore . add ( obj , key ) : idbstore . add ( obj ) ;
req . _hookCtx = hookCtx ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( i < l - 1 ) {
req . onerror = errorHandler ;
if ( hookCtx . onsuccess ) req . onsuccess = successHandler ;
}
}
} , function ( err ) {
hookCtx . onerror && hookCtx . onerror ( err ) ;
throw err ;
} ) ;
req . onerror = BulkErrorHandlerCatchAll ( errorList , done , true ) ;
req . onsuccess = hookedEventSuccessHandler ( done ) ;
} else {
//
// Standard Bulk (no 'creating' hook to care about)
//
errorHandler = BulkErrorHandlerCatchAll ( errorList ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , l = objects . length ; i < l ; ++ i ) {
req = keys$$1 ? idbstore . add ( objects [ i ] , keys$$1 [ i ] ) : idbstore . add ( objects [ i ] ) ;
req . onerror = errorHandler ;
} // Only need to catch success or error on the last operation
// according to the IDB spec.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
req . onerror = BulkErrorHandlerCatchAll ( errorList , done ) ;
req . onsuccess = eventSuccessHandler ( done ) ;
}
} ) ;
} ,
add : function ( obj , key ) {
/// <summary>
/// Add an object to the database. In case an object with same primary key already exists, the object will not be added.
/// </summary>
/// <param name="obj" type="Object">A javascript object to insert</param>
/// <param name="key" optional="true">Primary key</param>
var creatingHook = this . hook . creating . fire ;
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore , trans ) {
var hookCtx = {
onsuccess : null ,
onerror : null
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( creatingHook !== nop ) {
var effectiveKey = key != null ? key : idbstore . keyPath ? getByKeyPath ( obj , idbstore . keyPath ) : undefined ;
var keyToUse = creatingHook . call ( hookCtx , effectiveKey , obj , trans ) ; // Allow subscribers to when("creating") to generate the key.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( effectiveKey == null && keyToUse != null ) {
if ( idbstore . keyPath ) setByKeyPath ( obj , idbstore . keyPath , keyToUse ) ; else key = keyToUse ;
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
var req = key != null ? idbstore . add ( obj , key ) : idbstore . add ( obj ) ;
req . _hookCtx = hookCtx ;
req . onerror = hookedEventRejectHandler ( reject ) ;
req . onsuccess = hookedEventSuccessHandler ( function ( result ) {
// TODO: Remove these two lines in next major release (2.0?)
// It's no good practice to have side effects on provided parameters
var keyPath = idbstore . keyPath ;
if ( keyPath ) setByKeyPath ( obj , keyPath , result ) ;
resolve ( result ) ;
} ) ;
} catch ( e ) {
if ( hookCtx . onerror ) hookCtx . onerror ( e ) ;
throw e ;
2018-11-05 23:32:33 +01:00
}
2018-11-11 20:49:26 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} ,
put : function ( obj , key ) {
var _this = this ; /// <summary>
/// Add an object to the database but in case an object with same primary key alread exists, the existing one will get updated.
/// </summary>
/// <param name="obj" type="Object">A javascript object to insert or update</param>
/// <param name="key" optional="true">Primary key</param>
var creatingHook = this . hook . creating . fire ,
updatingHook = this . hook . updating . fire ;
if ( creatingHook !== nop || updatingHook !== nop ) {
//
// People listens to when("creating") or when("updating") events!
// We must know whether the put operation results in an CREATE or UPDATE.
//
var keyPath = this . schema . primKey . keyPath ;
var effectiveKey = key !== undefined ? key : keyPath && getByKeyPath ( obj , keyPath ) ;
if ( effectiveKey == null ) return this . add ( obj ) ; // Since key is optional, make sure we get it from obj if not provided
// Primary key exist. Lock transaction and try modifying existing. If nothing modified, call add().
// clone obj before this async call. If caller modifies obj the line after put(), the IDB spec requires that it should not affect operation.
obj = deepClone ( obj ) ;
return this . _trans ( READWRITE , function ( ) {
return _this . where ( ":id" ) . equals ( effectiveKey ) . modify ( function ( ) {
// Replace extisting value with our object
// CRUD event firing handled in Collection.modify()
this . value = obj ;
} ) . then ( function ( count ) {
return count === 0 ? _this . add ( obj , key ) : effectiveKey ;
} ) ;
} , "locked" ) ; // Lock needed because operation is splitted into modify() and add().
} else {
// Use the standard IDB put() method.
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore ) {
var req = key !== undefined ? idbstore . put ( obj , key ) : idbstore . put ( obj ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = wrap ( function ( ev ) {
var keyPath = idbstore . keyPath ;
if ( keyPath ) setByKeyPath ( obj , keyPath , ev . target . result ) ;
resolve ( req . result ) ;
} ) ;
} ) ;
}
} ,
'delete' : function ( key ) {
/// <param name="key">Primary key of the object to delete</param>
if ( this . hook . deleting . subscribers . length ) {
// People listens to when("deleting") event. Must implement delete using Collection.delete() that will
// call the CRUD event. Only Collection.delete() will know whether an object was actually deleted.
return this . where ( ":id" ) . equals ( key ) . delete ( ) ;
} else {
// No one listens. Use standard IDB delete() method.
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore ) {
var req = idbstore . delete ( key ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = wrap ( function ( ) {
resolve ( req . result ) ;
} ) ;
} ) ;
}
} ,
clear : function ( ) {
if ( this . hook . deleting . subscribers . length ) {
// People listens to when("deleting") event. Must implement delete using Collection.delete() that will
// call the CRUD event. Only Collection.delete() will knows which objects that are actually deleted.
return this . toCollection ( ) . delete ( ) ;
} else {
return this . _idbstore ( READWRITE , function ( resolve , reject , idbstore ) {
var req = idbstore . clear ( ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = wrap ( function ( ) {
resolve ( req . result ) ;
} ) ;
} ) ;
}
} ,
update : function ( keyOrObject , modifications ) {
if ( _typeof ( modifications ) !== 'object' || isArray ( modifications ) ) throw new exceptions . InvalidArgument ( "Modifications must be an object." ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( _typeof ( keyOrObject ) === 'object' && ! isArray ( keyOrObject ) ) {
// object to modify. Also modify given object with the modifications:
keys ( modifications ) . forEach ( function ( keyPath ) {
setByKeyPath ( keyOrObject , keyPath , modifications [ keyPath ] ) ;
} ) ;
var key = getByKeyPath ( keyOrObject , this . schema . primKey . keyPath ) ;
if ( key === undefined ) return rejection ( new exceptions . InvalidArgument ( "Given object does not contain its primary key" ) ) ;
return this . where ( ":id" ) . equals ( key ) . modify ( modifications ) ;
} else {
// key to modify
return this . where ( ":id" ) . equals ( keyOrObject ) . modify ( modifications ) ;
}
}
} ) ; //
//
//
// Transaction Class
//
//
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function Transaction ( mode , storeNames , dbschema , parent ) {
var _this = this ; /// <summary>
/// Transaction class. Represents a database transaction. All operations on db goes through a Transaction.
/// </summary>
/// <param name="mode" type="String">Any of "readwrite" or "readonly"</param>
/// <param name="storeNames" type="Array">Array of table names to operate on</param>
this . db = db ;
this . mode = mode ;
this . storeNames = storeNames ;
this . idbtrans = null ;
this . on = Events ( this , "complete" , "error" , "abort" ) ;
this . parent = parent || null ;
this . active = true ;
this . _reculock = 0 ;
this . _blockedFuncs = [ ] ;
this . _resolve = null ;
this . _reject = null ;
this . _waitingFor = null ;
this . _waitingQueue = null ;
this . _spinCount = 0 ; // Just for debugging waitFor()
this . _completion = new Promise ( function ( resolve , reject ) {
_this . _resolve = resolve ;
_this . _reject = reject ;
} ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
this . _completion . then ( function ( ) {
_this . active = false ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
_this . on . complete . fire ( ) ;
} , function ( e ) {
var wasActive = _this . active ;
_this . active = false ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
_this . on . error . fire ( e ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
_this . parent ? _this . parent . _reject ( e ) : wasActive && _this . idbtrans && _this . idbtrans . abort ( ) ;
return rejection ( e ) ; // Indicate we actually DO NOT catch this error.
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
props ( Transaction . prototype , {
//
// Transaction Protected Methods (not required by API users, but needed internally and eventually by dexie extensions)
//
_lock : function ( ) {
assert ( ! PSD . global ) ; // Locking and unlocking reuires to be within a PSD scope.
// Temporary set all requests into a pending queue if they are called before database is ready.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
++ this . _reculock ; // Recursive read/write lock pattern using PSD (Promise Specific Data) instead of TLS (Thread Local Storage)
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( this . _reculock === 1 && ! PSD . global ) PSD . lockOwnerFor = this ;
return this ;
} ,
_unlock : function ( ) {
assert ( ! PSD . global ) ; // Locking and unlocking reuires to be within a PSD scope.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( -- this . _reculock === 0 ) {
if ( ! PSD . global ) PSD . lockOwnerFor = null ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
while ( this . _blockedFuncs . length > 0 && ! this . _locked ( ) ) {
var fnAndPSD = this . _blockedFuncs . shift ( ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
usePSD ( fnAndPSD [ 1 ] , fnAndPSD [ 0 ] ) ;
} catch ( e ) { }
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return this ;
} ,
_locked : function ( ) {
// Checks if any write-lock is applied on this transaction.
// To simplify the Dexie API for extension implementations, we support recursive locks.
// This is accomplished by using "Promise Specific Data" (PSD).
// PSD data is bound to a Promise and any child Promise emitted through then() or resolve( new Promise() ).
// PSD is local to code executing on top of the call stacks of any of any code executed by Promise():
// * callback given to the Promise() constructor (function (resolve, reject){...})
// * callbacks given to then()/catch()/finally() methods (function (value){...})
// If creating a new independant Promise instance from within a Promise call stack, the new Promise will derive the PSD from the call stack of the parent Promise.
// Derivation is done so that the inner PSD __proto__ points to the outer PSD.
// PSD.lockOwnerFor will point to current transaction object if the currently executing PSD scope owns the lock.
return this . _reculock && PSD . lockOwnerFor !== this ;
} ,
create : function ( idbtrans ) {
var _this = this ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( ! this . mode ) return this ;
assert ( ! this . idbtrans ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
if ( ! idbtrans && ! idbdb ) {
switch ( dbOpenError && dbOpenError . name ) {
case "DatabaseClosedError" :
// Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open()
throw new exceptions . DatabaseClosed ( dbOpenError ) ;
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
case "MissingAPIError" :
// Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open()
throw new exceptions . MissingAPI ( dbOpenError . message , dbOpenError ) ;
2018-11-11 20:49:26 +01:00
default :
2018-11-21 01:42:52 +01:00
// Make it clear that the user operation was not what caused the error - the error had occurred earlier on db.open()!
throw new exceptions . OpenFailed ( dbOpenError ) ;
2018-11-11 20:49:26 +01:00
}
}
2018-11-21 01:42:52 +01:00
if ( ! this . active ) throw new exceptions . TransactionInactive ( ) ;
assert ( this . _completion . _state === null ) ;
idbtrans = this . idbtrans = idbtrans || idbdb . transaction ( safariMultiStoreFix ( this . storeNames ) , this . mode ) ;
idbtrans . onerror = wrap ( function ( ev ) {
preventDefault ( ev ) ; // Prohibit default bubbling to window.error
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
_this . _reject ( idbtrans . error ) ;
} ) ;
idbtrans . onabort = wrap ( function ( ev ) {
preventDefault ( ev ) ;
_this . active && _this . _reject ( new exceptions . Abort ( idbtrans . error ) ) ;
_this . active = false ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
_this . on ( "abort" ) . fire ( ev ) ;
} ) ;
idbtrans . oncomplete = wrap ( function ( ) {
_this . active = false ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
_this . _resolve ( ) ;
} ) ;
return this ;
} ,
_promise : function ( mode , fn , bWriteLock ) {
var _this = this ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( mode === READWRITE && this . mode !== READWRITE ) return rejection ( new exceptions . ReadOnly ( "Transaction is readonly" ) ) ;
if ( ! this . active ) return rejection ( new exceptions . TransactionInactive ( ) ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( this . _locked ( ) ) {
return new Promise ( function ( resolve , reject ) {
_this . _blockedFuncs . push ( [ function ( ) {
_this . _promise ( mode , fn , bWriteLock ) . then ( resolve , reject ) ;
} , PSD ] ) ;
} ) ;
} else if ( bWriteLock ) {
return newScope ( function ( ) {
var p = new Promise ( function ( resolve , reject ) {
_this . _lock ( ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var rv = fn ( resolve , reject , _this ) ;
if ( rv && rv . then ) rv . then ( resolve , reject ) ;
} ) ;
p . finally ( function ( ) {
return _this . _unlock ( ) ;
} ) ;
p . _lib = true ;
return p ;
} ) ;
} else {
var p = new Promise ( function ( resolve , reject ) {
var rv = fn ( resolve , reject , _this ) ;
if ( rv && rv . then ) rv . then ( resolve , reject ) ;
} ) ;
p . _lib = true ;
return p ;
}
} ,
_root : function ( ) {
return this . parent ? this . parent . _root ( ) : this ;
} ,
waitFor : function ( promise ) {
// Always operate on the root transaction (in case this is a sub stransaction)
var root = this . _root ( ) ; // For stability reasons, convert parameter to promise no matter what type is passed to waitFor().
// (We must be able to call .then() on it.)
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
promise = Promise . resolve ( promise ) ;
2018-11-05 23:32:33 +01:00
2018-11-21 01:42:52 +01:00
if ( root . _waitingFor ) {
// Already called waitFor(). Wait for both to complete.
root . _waitingFor = root . _waitingFor . then ( function ( ) {
return promise ;
} ) ;
} else {
// We're not in waiting state. Start waiting state.
root . _waitingFor = promise ;
root . _waitingQueue = [ ] ; // Start interacting with indexedDB until promise completes:
2018-11-11 20:49:26 +01:00
2018-11-21 01:42:52 +01:00
var store = root . idbtrans . objectStore ( root . storeNames [ 0 ] ) ;
2018-11-06 23:27:57 +01:00
2018-11-21 01:42:52 +01:00
( function spin ( ) {
++ root . _spinCount ; // For debugging only
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
while ( root . _waitingQueue . length ) {
root . _waitingQueue . shift ( ) ( ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( root . _waitingFor ) store . get ( - Infinity ) . onsuccess = spin ;
} ) ( ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var currentWaitPromise = root . _waitingFor ;
return new Promise ( function ( resolve , reject ) {
promise . then ( function ( res ) {
return root . _waitingQueue . push ( wrap ( resolve . bind ( null , res ) ) ) ;
} , function ( err ) {
return root . _waitingQueue . push ( wrap ( reject . bind ( null , err ) ) ) ;
} ) . finally ( function ( ) {
if ( root . _waitingFor === currentWaitPromise ) {
// No one added a wait after us. Safe to stop the spinning.
root . _waitingFor = null ;
}
} ) ;
} ) ;
} ,
//
// Transaction Public Properties and Methods
//
abort : function ( ) {
this . active && this . _reject ( new exceptions . Abort ( ) ) ;
this . active = false ;
} ,
tables : {
get : deprecated ( "Transaction.tables" , function ( ) {
return allTables ;
} )
} ,
table : function ( name ) {
var table = db . table ( name ) ; // Don't check that table is part of transaction. It must fail lazily!
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return new Table ( name , table . schema , this ) ;
}
} ) ; //
//
//
// WhereClause
//
//
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function WhereClause ( table , index , orCollection ) {
/// <param name="table" type="Table"></param>
/// <param name="index" type="String" optional="true"></param>
/// <param name="orCollection" type="Collection" optional="true"></param>
this . _ctx = {
table : table ,
index : index === ":id" ? null : index ,
or : orCollection
} ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
props ( WhereClause . prototype , function ( ) {
// WhereClause private methods
function fail ( collectionOrWhereClause , err , T ) {
var collection = collectionOrWhereClause instanceof WhereClause ? new Collection ( collectionOrWhereClause ) : collectionOrWhereClause ;
collection . _ctx . error = T ? new T ( err ) : new TypeError ( err ) ;
return collection ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function emptyCollection ( whereClause ) {
return new Collection ( whereClause , function ( ) {
return IDBKeyRange . only ( "" ) ;
} ) . limit ( 0 ) ;
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
function upperFactory ( dir ) {
return dir === "next" ? function ( s ) {
return s . toUpperCase ( ) ;
} : function ( s ) {
return s . toLowerCase ( ) ;
} ;
2018-11-09 02:45:37 +01:00
}
2018-11-21 01:42:52 +01:00
function lowerFactory ( dir ) {
return dir === "next" ? function ( s ) {
return s . toLowerCase ( ) ;
} : function ( s ) {
return s . toUpperCase ( ) ;
} ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function nextCasing ( key , lowerKey , upperNeedle , lowerNeedle , cmp , dir ) {
var length = Math . min ( key . length , lowerNeedle . length ) ;
var llp = - 1 ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 ; i < length ; ++ i ) {
var lwrKeyChar = lowerKey [ i ] ;
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
if ( lwrKeyChar !== lowerNeedle [ i ] ) {
if ( cmp ( key [ i ] , upperNeedle [ i ] ) < 0 ) return key . substr ( 0 , i ) + upperNeedle [ i ] + upperNeedle . substr ( i + 1 ) ;
if ( cmp ( key [ i ] , lowerNeedle [ i ] ) < 0 ) return key . substr ( 0 , i ) + lowerNeedle [ i ] + upperNeedle . substr ( i + 1 ) ;
if ( llp >= 0 ) return key . substr ( 0 , llp ) + lowerKey [ llp ] + upperNeedle . substr ( llp + 1 ) ;
return null ;
2018-10-31 17:00:31 +01:00
}
2018-11-21 01:42:52 +01:00
if ( cmp ( key [ i ] , lwrKeyChar ) < 0 ) llp = i ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( length < lowerNeedle . length && dir === "next" ) return key + upperNeedle . substr ( key . length ) ;
if ( length < key . length && dir === "prev" ) return key . substr ( 0 , upperNeedle . length ) ;
return llp < 0 ? null : key . substr ( 0 , llp ) + lowerNeedle [ llp ] + upperNeedle . substr ( llp + 1 ) ;
}
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
function addIgnoreCaseAlgorithm ( whereClause , match , needles , suffix ) {
/// <param name="needles" type="Array" elementType="String"></param>
var upper ,
lower ,
compare ,
upperNeedles ,
lowerNeedles ,
direction ,
nextKeySuffix ,
needlesLen = needles . length ;
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
if ( ! needles . every ( function ( s ) {
return typeof s === 'string' ;
} ) ) {
return fail ( whereClause , STRING _EXPECTED ) ;
2018-11-09 02:45:37 +01:00
}
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
function initDirection ( dir ) {
upper = upperFactory ( dir ) ;
lower = lowerFactory ( dir ) ;
compare = dir === "next" ? simpleCompare : simpleCompareReverse ;
var needleBounds = needles . map ( function ( needle ) {
return {
lower : lower ( needle ) ,
upper : upper ( needle )
} ;
} ) . sort ( function ( a , b ) {
return compare ( a . lower , b . lower ) ;
} ) ;
upperNeedles = needleBounds . map ( function ( nb ) {
return nb . upper ;
} ) ;
lowerNeedles = needleBounds . map ( function ( nb ) {
return nb . lower ;
} ) ;
direction = dir ;
nextKeySuffix = dir === "next" ? "" : suffix ;
}
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
initDirection ( "next" ) ;
var c = new Collection ( whereClause , function ( ) {
return IDBKeyRange . bound ( upperNeedles [ 0 ] , lowerNeedles [ needlesLen - 1 ] + suffix ) ;
} ) ;
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
c . _ondirectionchange = function ( direction ) {
// This event onlys occur before filter is called the first time.
initDirection ( direction ) ;
} ;
2018-11-11 00:08:00 +01:00
2018-11-21 01:42:52 +01:00
var firstPossibleNeedle = 0 ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
c . _addAlgorithm ( function ( cursor , advance , resolve ) {
/// <param name="cursor" type="IDBCursor"></param>
/// <param name="advance" type="Function"></param>
/// <param name="resolve" type="Function"></param>
var key = cursor . key ;
if ( typeof key !== 'string' ) return false ;
var lowerKey = lower ( key ) ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( match ( lowerKey , lowerNeedles , firstPossibleNeedle ) ) {
return true ;
} else {
var lowestPossibleCasing = null ;
2018-11-09 18:44:13 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = firstPossibleNeedle ; i < needlesLen ; ++ i ) {
var casing = nextCasing ( key , lowerKey , upperNeedles [ i ] , lowerNeedles [ i ] , compare , direction ) ;
if ( casing === null && lowestPossibleCasing === null ) firstPossibleNeedle = i + 1 ; else if ( lowestPossibleCasing === null || compare ( lowestPossibleCasing , casing ) > 0 ) {
lowestPossibleCasing = casing ;
}
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( lowestPossibleCasing !== null ) {
advance ( function ( ) {
cursor . continue ( lowestPossibleCasing + nextKeySuffix ) ;
2018-11-09 02:45:37 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} else {
advance ( resolve ) ;
2018-11-09 02:45:37 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return false ;
}
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return c ;
} //
// WhereClause public methods
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return {
between : function ( lower , upper , includeLower , includeUpper ) {
/// <summary>
/// Filter out records whose where-field lays between given lower and upper values. Applies to Strings, Numbers and Dates.
/// </summary>
/// <param name="lower"></param>
/// <param name="upper"></param>
/// <param name="includeLower" optional="true">Whether items that equals lower should be included. Default true.</param>
/// <param name="includeUpper" optional="true">Whether items that equals upper should be included. Default false.</param>
/// <returns type="Collection"></returns>
includeLower = includeLower !== false ; // Default to true
includeUpper = includeUpper === true ; // Default to false
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
if ( cmp ( lower , upper ) > 0 || cmp ( lower , upper ) === 0 && ( includeLower || includeUpper ) && ! ( includeLower && includeUpper ) ) return emptyCollection ( this ) ; // Workaround for idiotic W3C Specification that DataError must be thrown if lower > upper. The natural result would be to return an empty collection.
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return new Collection ( this , function ( ) {
return IDBKeyRange . bound ( lower , upper , ! includeLower , ! includeUpper ) ;
} ) ;
} catch ( e ) {
return fail ( this , INVALID _KEY _ARGUMENT ) ;
}
} ,
equals : function ( value ) {
return new Collection ( this , function ( ) {
return IDBKeyRange . only ( value ) ;
} ) ;
} ,
above : function ( value ) {
return new Collection ( this , function ( ) {
return IDBKeyRange . lowerBound ( value , true ) ;
} ) ;
} ,
aboveOrEqual : function ( value ) {
return new Collection ( this , function ( ) {
return IDBKeyRange . lowerBound ( value ) ;
} ) ;
} ,
below : function ( value ) {
return new Collection ( this , function ( ) {
return IDBKeyRange . upperBound ( value , true ) ;
} ) ;
} ,
belowOrEqual : function ( value ) {
return new Collection ( this , function ( ) {
return IDBKeyRange . upperBound ( value ) ;
} ) ;
} ,
startsWith : function ( str ) {
/// <param name="str" type="String"></param>
if ( typeof str !== 'string' ) return fail ( this , STRING _EXPECTED ) ;
return this . between ( str , str + maxString , true , true ) ;
} ,
startsWithIgnoreCase : function ( str ) {
/// <param name="str" type="String"></param>
if ( str === "" ) return this . startsWith ( str ) ;
return addIgnoreCaseAlgorithm ( this , function ( x , a ) {
return x . indexOf ( a [ 0 ] ) === 0 ;
} , [ str ] , maxString ) ;
} ,
equalsIgnoreCase : function ( str ) {
/// <param name="str" type="String"></param>
return addIgnoreCaseAlgorithm ( this , function ( x , a ) {
return x === a [ 0 ] ;
} , [ str ] , "" ) ;
} ,
anyOfIgnoreCase : function ( ) {
var set = getArrayOf . apply ( NO _CHAR _ARRAY , arguments ) ;
if ( set . length === 0 ) return emptyCollection ( this ) ;
return addIgnoreCaseAlgorithm ( this , function ( x , a ) {
return a . indexOf ( x ) !== - 1 ;
} , set , "" ) ;
} ,
startsWithAnyOfIgnoreCase : function ( ) {
var set = getArrayOf . apply ( NO _CHAR _ARRAY , arguments ) ;
if ( set . length === 0 ) return emptyCollection ( this ) ;
return addIgnoreCaseAlgorithm ( this , function ( x , a ) {
return a . some ( function ( n ) {
return x . indexOf ( n ) === 0 ;
} ) ;
} , set , maxString ) ;
} ,
anyOf : function ( ) {
var set = getArrayOf . apply ( NO _CHAR _ARRAY , arguments ) ;
var compare = ascending ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
set . sort ( compare ) ;
} catch ( e ) {
return fail ( this , INVALID _KEY _ARGUMENT ) ;
2018-10-31 17:00:31 +01:00
}
2018-11-21 01:42:52 +01:00
if ( set . length === 0 ) return emptyCollection ( this ) ;
var c = new Collection ( this , function ( ) {
return IDBKeyRange . bound ( set [ 0 ] , set [ set . length - 1 ] ) ;
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
c . _ondirectionchange = function ( direction ) {
compare = direction === "next" ? ascending : descending ;
set . sort ( compare ) ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var i = 0 ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
c . _addAlgorithm ( function ( cursor , advance , resolve ) {
var key = cursor . key ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
while ( compare ( key , set [ i ] ) > 0 ) {
// The cursor has passed beyond this key. Check next.
++ i ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( i === set . length ) {
// There is no next. Stop searching.
advance ( resolve ) ;
return false ;
}
}
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
if ( compare ( key , set [ i ] ) === 0 ) {
// The current cursor value should be included and we should continue a single step in case next item has the same key or possibly our next key in set.
return true ;
} else {
// cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.
advance ( function ( ) {
cursor . continue ( set [ i ] ) ;
} ) ;
return false ;
}
} ) ;
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
return c ;
} ,
notEqual : function ( value ) {
return this . inAnyRange ( [ [ minKey , value ] , [ value , maxKey ] ] , {
includeLowers : false ,
includeUppers : false
} ) ;
} ,
noneOf : function ( ) {
var set = getArrayOf . apply ( NO _CHAR _ARRAY , arguments ) ;
if ( set . length === 0 ) return new Collection ( this ) ; // Return entire collection.
2018-11-09 02:45:37 +01:00
2018-11-21 01:42:52 +01:00
try {
set . sort ( ascending ) ;
} catch ( e ) {
return fail ( this , INVALID _KEY _ARGUMENT ) ;
} // Transform ["a","b","c"] to a set of ranges for between/above/below: [[minKey,"a"], ["a","b"], ["b","c"], ["c",maxKey]]
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var ranges = set . reduce ( function ( res , val ) {
return res ? res . concat ( [ [ res [ res . length - 1 ] [ 1 ] , val ] ] ) : [ [ minKey , val ] ] ;
} , null ) ;
ranges . push ( [ set [ set . length - 1 ] , maxKey ] ) ;
return this . inAnyRange ( ranges , {
includeLowers : false ,
includeUppers : false
} ) ;
} ,
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
/ * * F i l t e r o u t v a l u e s w i t h i n g g i v e n s e t o f r a n g e s .
* Example , give children and elders a rebate of 50 % :
*
* db . friends . where ( 'age' ) . inAnyRange ( [ [ 0 , 18 ] , [ 65 , Infinity ] ] ) . modify ( { Rebate : 1 / 2 } ) ;
*
* @ param { ( string | number | Date | Array ) [ ] [ ] } ranges
* @ param { { includeLowers : boolean , includeUppers : boolean } } options
* /
inAnyRange : function ( ranges , options ) {
if ( ranges . length === 0 ) return emptyCollection ( this ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( ! ranges . every ( function ( range ) {
return range [ 0 ] !== undefined && range [ 1 ] !== undefined && ascending ( range [ 0 ] , range [ 1 ] ) <= 0 ;
} ) ) {
return fail ( this , "First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower" , exceptions . InvalidArgument ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var includeLowers = ! options || options . includeLowers !== false ; // Default to true
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var includeUppers = options && options . includeUppers === true ; // Default to false
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function addRange ( ranges , newRange ) {
for ( var i = 0 , l = ranges . length ; i < l ; ++ i ) {
var range = ranges [ i ] ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( cmp ( newRange [ 0 ] , range [ 1 ] ) < 0 && cmp ( newRange [ 1 ] , range [ 0 ] ) > 0 ) {
range [ 0 ] = min ( range [ 0 ] , newRange [ 0 ] ) ;
range [ 1 ] = max ( range [ 1 ] , newRange [ 1 ] ) ;
break ;
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
if ( i === l ) ranges . push ( newRange ) ;
return ranges ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var sortDirection = ascending ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function rangeSorter ( a , b ) {
return sortDirection ( a [ 0 ] , b [ 0 ] ) ;
} // Join overlapping ranges
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var set ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
try {
set = ranges . reduce ( addRange , [ ] ) ;
set . sort ( rangeSorter ) ;
} catch ( ex ) {
return fail ( this , INVALID _KEY _ARGUMENT ) ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
var i = 0 ;
var keyIsBeyondCurrentEntry = includeUppers ? function ( key ) {
return ascending ( key , set [ i ] [ 1 ] ) > 0 ;
} : function ( key ) {
return ascending ( key , set [ i ] [ 1 ] ) >= 0 ;
} ;
var keyIsBeforeCurrentEntry = includeLowers ? function ( key ) {
return descending ( key , set [ i ] [ 0 ] ) > 0 ;
} : function ( key ) {
return descending ( key , set [ i ] [ 0 ] ) >= 0 ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function keyWithinCurrentRange ( key ) {
return ! keyIsBeyondCurrentEntry ( key ) && ! keyIsBeforeCurrentEntry ( key ) ;
2018-10-31 17:00:31 +01:00
}
2018-11-21 01:42:52 +01:00
var checkKey = keyIsBeyondCurrentEntry ;
var c = new Collection ( this , function ( ) {
return IDBKeyRange . bound ( set [ 0 ] [ 0 ] , set [ set . length - 1 ] [ 1 ] , ! includeLowers , ! includeUppers ) ;
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
c . _ondirectionchange = function ( direction ) {
if ( direction === "next" ) {
checkKey = keyIsBeyondCurrentEntry ;
sortDirection = ascending ;
} else {
checkKey = keyIsBeforeCurrentEntry ;
sortDirection = descending ;
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
set . sort ( rangeSorter ) ;
} ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
c . _addAlgorithm ( function ( cursor , advance , resolve ) {
var key = cursor . key ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
while ( checkKey ( key ) ) {
// The cursor has passed beyond this key. Check next.
++ i ;
if ( i === set . length ) {
// There is no next. Stop searching.
advance ( resolve ) ;
return false ;
}
}
if ( keyWithinCurrentRange ( key ) ) {
// The current cursor value should be included and we should continue a single step in case next item has the same key or possibly our next key in set.
return true ;
} else if ( cmp ( key , set [ i ] [ 1 ] ) === 0 || cmp ( key , set [ i ] [ 0 ] ) === 0 ) {
// includeUpper or includeLower is false so keyWithinCurrentRange() returns false even though we are at range border.
// Continue to next key but don't include this one.
return false ;
} else {
// cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.
advance ( function ( ) {
if ( sortDirection === ascending ) cursor . continue ( set [ i ] [ 0 ] ) ; else cursor . continue ( set [ i ] [ 1 ] ) ;
} ) ;
return false ;
}
} ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return c ;
} ,
startsWithAnyOf : function ( ) {
var set = getArrayOf . apply ( NO _CHAR _ARRAY , arguments ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! set . every ( function ( s ) {
return typeof s === 'string' ;
} ) ) {
return fail ( this , "startsWithAnyOf() only works with strings" ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( set . length === 0 ) return emptyCollection ( this ) ;
return this . inAnyRange ( set . map ( function ( str ) {
return [ str , str + maxString ] ;
} ) ) ;
2018-11-14 17:32:35 +01:00
}
} ;
2018-11-21 01:42:52 +01:00
} ) ; //
//
//
// Collection Class
//
//
//
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function Collection ( whereClause , keyRangeGenerator ) {
/// <summary>
///
/// </summary>
/// <param name="whereClause" type="WhereClause">Where clause instance</param>
/// <param name="keyRangeGenerator" value="function(){ return IDBKeyRange.bound(0,1);}" optional="true"></param>
var keyRange = null ,
error = null ;
if ( keyRangeGenerator ) try {
keyRange = keyRangeGenerator ( ) ;
} catch ( ex ) {
error = ex ;
}
var whereCtx = whereClause . _ctx ,
table = whereCtx . table ;
this . _ctx = {
table : table ,
index : whereCtx . index ,
isPrimKey : ! whereCtx . index || table . schema . primKey . keyPath && whereCtx . index === table . schema . primKey . name ,
range : keyRange ,
keysOnly : false ,
dir : "next" ,
unique : "" ,
algorithm : null ,
filter : null ,
replayFilter : null ,
justLimit : true ,
isMatch : null ,
offset : 0 ,
limit : Infinity ,
error : error ,
or : whereCtx . or ,
valueMapper : table . hook . reading . fire
} ;
2018-11-14 17:32:35 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function isPlainKeyRange ( ctx , ignoreLimitFilter ) {
return ! ( ctx . filter || ctx . algorithm || ctx . or ) && ( ignoreLimitFilter ? ctx . justLimit : ! ctx . replayFilter ) ;
2018-11-14 17:32:35 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
props ( Collection . prototype , function ( ) {
//
// Collection Private Functions
//
function addFilter ( ctx , fn ) {
ctx . filter = combine ( ctx . filter , fn ) ;
}
function addReplayFilter ( ctx , factory , isLimitFilter ) {
var curr = ctx . replayFilter ;
ctx . replayFilter = curr ? function ( ) {
return combine ( curr ( ) , factory ( ) ) ;
} : factory ;
ctx . justLimit = isLimitFilter && ! curr ;
}
function addMatchFilter ( ctx , fn ) {
ctx . isMatch = combine ( ctx . isMatch , fn ) ;
}
/ * * @ p a r a m c t x {
* isPrimKey : boolean ,
* table : Table ,
* index : string
* }
* @ param store IDBObjectStore
* * /
function getIndexOrStore ( ctx , store ) {
if ( ctx . isPrimKey ) return store ;
var indexSpec = ctx . table . schema . idxByName [ ctx . index ] ;
if ( ! indexSpec ) throw new exceptions . Schema ( "KeyPath " + ctx . index + " on object store " + store . name + " is not indexed" ) ;
return store . index ( indexSpec . name ) ;
}
/ * * @ p a r a m c t x {
* isPrimKey : boolean ,
* table : Table ,
* index : string ,
* keysOnly : boolean ,
* range ? : IDBKeyRange ,
* dir : "next" | "prev"
* }
* /
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
function openCursor ( ctx , store ) {
var idxOrStore = getIndexOrStore ( ctx , store ) ;
return ctx . keysOnly && 'openKeyCursor' in idxOrStore ? idxOrStore . openKeyCursor ( ctx . range || null , ctx . dir + ctx . unique ) : idxOrStore . openCursor ( ctx . range || null , ctx . dir + ctx . unique ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function iter ( ctx , fn , resolve , reject , idbstore ) {
var filter = ctx . replayFilter ? combine ( ctx . filter , ctx . replayFilter ( ) ) : ctx . filter ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! ctx . or ) {
iterate ( openCursor ( ctx , idbstore ) , combine ( ctx . algorithm , filter ) , fn , resolve , reject , ! ctx . keysOnly && ctx . valueMapper ) ;
} else ( function ( ) {
var set = { } ;
var resolved = 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function resolveboth ( ) {
if ( ++ resolved === 2 ) resolve ( ) ; // Seems like we just support or btwn max 2 expressions, but there are no limit because we do recursion.
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function union ( item , cursor , advance ) {
if ( ! filter || filter ( cursor , advance , resolveboth , reject ) ) {
var primaryKey = cursor . primaryKey ;
var key = '' + primaryKey ;
if ( key === '[object ArrayBuffer]' ) key = '' + new Uint8Array ( primaryKey ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! hasOwn ( set , key ) ) {
set [ key ] = true ;
fn ( item , cursor , advance ) ;
}
}
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
ctx . or . _iterate ( union , resolveboth , reject , idbstore ) ;
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
iterate ( openCursor ( ctx , idbstore ) , ctx . algorithm , union , resolveboth , reject , ! ctx . keysOnly && ctx . valueMapper ) ;
} ) ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-10-31 17:00:31 +01:00
2018-11-21 01:42:52 +01:00
return {
//
// Collection Protected Functions
//
_read : function ( fn , cb ) {
var ctx = this . _ctx ;
return ctx . error ? ctx . table . _trans ( null , rejection . bind ( null , ctx . error ) ) : ctx . table . _idbstore ( READONLY , fn ) . then ( cb ) ;
} ,
_write : function ( fn ) {
var ctx = this . _ctx ;
return ctx . error ? ctx . table . _trans ( null , rejection . bind ( null , ctx . error ) ) : ctx . table . _idbstore ( READWRITE , fn , "locked" ) ; // When doing write operations on collections, always lock the operation so that upcoming operations gets queued.
} ,
_addAlgorithm : function ( fn ) {
var ctx = this . _ctx ;
ctx . algorithm = combine ( ctx . algorithm , fn ) ;
} ,
_iterate : function ( fn , resolve , reject , idbstore ) {
return iter ( this . _ctx , fn , resolve , reject , idbstore ) ;
} ,
clone : function ( props$$1 ) {
var rv = Object . create ( this . constructor . prototype ) ,
ctx = Object . create ( this . _ctx ) ;
if ( props$$1 ) extend ( ctx , props$$1 ) ;
rv . _ctx = ctx ;
return rv ;
} ,
raw : function ( ) {
this . _ctx . valueMapper = null ;
return this ;
} ,
//
// Collection Public methods
//
each : function ( fn ) {
var ctx = this . _ctx ;
return this . _read ( function ( resolve , reject , idbstore ) {
iter ( ctx , fn , resolve , reject , idbstore ) ;
} ) ;
} ,
count : function ( cb ) {
var ctx = this . _ctx ;
if ( isPlainKeyRange ( ctx , true ) ) {
// This is a plain key range. We can use the count() method if the index.
return this . _read ( function ( resolve , reject , idbstore ) {
var idx = getIndexOrStore ( ctx , idbstore ) ;
var req = ctx . range ? idx . count ( ctx . range ) : idx . count ( ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = function ( e ) {
resolve ( Math . min ( e . target . result , ctx . limit ) ) ;
} ;
} , cb ) ;
} else {
// Algorithms, filters or expressions are applied. Need to count manually.
var count = 0 ;
return this . _read ( function ( resolve , reject , idbstore ) {
iter ( ctx , function ( ) {
++ count ;
return false ;
} , function ( ) {
resolve ( count ) ;
} , reject , idbstore ) ;
} , cb ) ;
}
} ,
sortBy : function ( keyPath , cb ) {
/// <param name="keyPath" type="String"></param>
var parts = keyPath . split ( '.' ) . reverse ( ) ,
lastPart = parts [ 0 ] ,
lastIndex = parts . length - 1 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function getval ( obj , i ) {
if ( i ) return getval ( obj [ parts [ i ] ] , i - 1 ) ;
return obj [ lastPart ] ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var order = this . _ctx . dir === "next" ? 1 : - 1 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function sorter ( a , b ) {
var aVal = getval ( a , lastIndex ) ,
bVal = getval ( b , lastIndex ) ;
return aVal < bVal ? - order : aVal > bVal ? order : 0 ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return this . toArray ( function ( a ) {
return a . sort ( sorter ) ;
} ) . then ( cb ) ;
} ,
toArray : function ( cb ) {
var ctx = this . _ctx ;
return this . _read ( function ( resolve , reject , idbstore ) {
if ( hasGetAll && ctx . dir === 'next' && isPlainKeyRange ( ctx , true ) && ctx . limit > 0 ) {
// Special optimation if we could use IDBObjectStore.getAll() or
// IDBKeyRange.getAll():
var readingHook = ctx . table . hook . reading . fire ;
var idxOrStore = getIndexOrStore ( ctx , idbstore ) ;
var req = ctx . limit < Infinity ? idxOrStore . getAll ( ctx . range , ctx . limit ) : idxOrStore . getAll ( ctx . range ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = readingHook === mirror ? eventSuccessHandler ( resolve ) : eventSuccessHandler ( function ( res ) {
try {
resolve ( res . map ( readingHook ) ) ;
} catch ( e ) {
reject ( e ) ;
}
} ) ;
} else {
// Getting array through a cursor.
var a = [ ] ;
iter ( ctx , function ( item ) {
a . push ( item ) ;
} , function arrayComplete ( ) {
resolve ( a ) ;
} , reject , idbstore ) ;
}
} , cb ) ;
} ,
offset : function ( offset ) {
var ctx = this . _ctx ;
if ( offset <= 0 ) return this ;
ctx . offset += offset ; // For count()
if ( isPlainKeyRange ( ctx ) ) {
addReplayFilter ( ctx , function ( ) {
var offsetLeft = offset ;
return function ( cursor , advance ) {
if ( offsetLeft === 0 ) return true ;
if ( offsetLeft === 1 ) {
-- offsetLeft ;
return false ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
advance ( function ( ) {
cursor . advance ( offsetLeft ) ;
offsetLeft = 0 ;
} ) ;
return false ;
} ;
} ) ;
} else {
addReplayFilter ( ctx , function ( ) {
var offsetLeft = offset ;
return function ( ) {
return -- offsetLeft < 0 ;
} ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return this ;
} ,
limit : function ( numRows ) {
this . _ctx . limit = Math . min ( this . _ctx . limit , numRows ) ; // For count()
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
addReplayFilter ( this . _ctx , function ( ) {
var rowsLeft = numRows ;
return function ( cursor , advance , resolve ) {
if ( -- rowsLeft <= 0 ) advance ( resolve ) ; // Stop after this item has been included
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return rowsLeft >= 0 ; // If numRows is already below 0, return false because then 0 was passed to numRows initially. Otherwise we wouldnt come here.
} ;
} , true ) ;
return this ;
} ,
until : function ( filterFunction , bIncludeStopEntry ) {
addFilter ( this . _ctx , function ( cursor , advance , resolve ) {
if ( filterFunction ( cursor . value ) ) {
advance ( resolve ) ;
return bIncludeStopEntry ;
} else {
return true ;
}
} ) ;
return this ;
} ,
first : function ( cb ) {
return this . limit ( 1 ) . toArray ( function ( a ) {
return a [ 0 ] ;
} ) . then ( cb ) ;
} ,
last : function ( cb ) {
return this . reverse ( ) . first ( cb ) ;
} ,
filter : function ( filterFunction ) {
/// <param name="jsFunctionFilter" type="Function">function(val){return true/false}</param>
addFilter ( this . _ctx , function ( cursor ) {
return filterFunction ( cursor . value ) ;
} ) ; // match filters not used in Dexie.js but can be used by 3rd part libraries to test a
// collection for a match without querying DB. Used by Dexie.Observable.
addMatchFilter ( this . _ctx , filterFunction ) ;
return this ;
} ,
and : function ( filterFunction ) {
return this . filter ( filterFunction ) ;
} ,
or : function ( indexName ) {
return new WhereClause ( this . _ctx . table , indexName , this ) ;
} ,
reverse : function ( ) {
this . _ctx . dir = this . _ctx . dir === "prev" ? "next" : "prev" ;
if ( this . _ondirectionchange ) this . _ondirectionchange ( this . _ctx . dir ) ;
return this ;
} ,
desc : function ( ) {
return this . reverse ( ) ;
} ,
eachKey : function ( cb ) {
var ctx = this . _ctx ;
ctx . keysOnly = ! ctx . isMatch ;
return this . each ( function ( val , cursor ) {
cb ( cursor . key , cursor ) ;
} ) ;
} ,
eachUniqueKey : function ( cb ) {
this . _ctx . unique = "unique" ;
return this . eachKey ( cb ) ;
} ,
eachPrimaryKey : function ( cb ) {
var ctx = this . _ctx ;
ctx . keysOnly = ! ctx . isMatch ;
return this . each ( function ( val , cursor ) {
cb ( cursor . primaryKey , cursor ) ;
} ) ;
} ,
keys : function ( cb ) {
var ctx = this . _ctx ;
ctx . keysOnly = ! ctx . isMatch ;
var a = [ ] ;
return this . each ( function ( item , cursor ) {
a . push ( cursor . key ) ;
} ) . then ( function ( ) {
return a ;
} ) . then ( cb ) ;
} ,
primaryKeys : function ( cb ) {
var ctx = this . _ctx ;
if ( hasGetAll && ctx . dir === 'next' && isPlainKeyRange ( ctx , true ) && ctx . limit > 0 ) {
// Special optimation if we could use IDBObjectStore.getAllKeys() or
// IDBKeyRange.getAllKeys():
return this . _read ( function ( resolve , reject , idbstore ) {
var idxOrStore = getIndexOrStore ( ctx , idbstore ) ;
var req = ctx . limit < Infinity ? idxOrStore . getAllKeys ( ctx . range , ctx . limit ) : idxOrStore . getAllKeys ( ctx . range ) ;
req . onerror = eventRejectHandler ( reject ) ;
req . onsuccess = eventSuccessHandler ( resolve ) ;
} ) . then ( cb ) ;
}
ctx . keysOnly = ! ctx . isMatch ;
var a = [ ] ;
return this . each ( function ( item , cursor ) {
a . push ( cursor . primaryKey ) ;
} ) . then ( function ( ) {
return a ;
} ) . then ( cb ) ;
} ,
uniqueKeys : function ( cb ) {
this . _ctx . unique = "unique" ;
return this . keys ( cb ) ;
} ,
firstKey : function ( cb ) {
return this . limit ( 1 ) . keys ( function ( a ) {
return a [ 0 ] ;
} ) . then ( cb ) ;
} ,
lastKey : function ( cb ) {
return this . reverse ( ) . firstKey ( cb ) ;
} ,
distinct : function ( ) {
var ctx = this . _ctx ,
idx = ctx . index && ctx . table . schema . idxByName [ ctx . index ] ;
if ( ! idx || ! idx . multi ) return this ; // distinct() only makes differencies on multiEntry indexes.
var set = { } ;
addFilter ( this . _ctx , function ( cursor ) {
var strKey = cursor . primaryKey . toString ( ) ; // Converts any Date to String, String to String, Number to String and Array to comma-separated string
var found = hasOwn ( set , strKey ) ;
set [ strKey ] = true ;
return ! found ;
} ) ;
return this ;
} ,
//
// Methods that mutate storage
//
modify : function ( changes ) {
var self = this ,
ctx = this . _ctx ,
hook = ctx . table . hook ,
updatingHook = hook . updating . fire ,
deletingHook = hook . deleting . fire ;
return this . _write ( function ( resolve , reject , idbstore , trans ) {
var modifyer ;
if ( typeof changes === 'function' ) {
// Changes is a function that may update, add or delete propterties or even require a deletion the object itself (delete this.item)
if ( updatingHook === nop && deletingHook === nop ) {
// Noone cares about what is being changed. Just let the modifier function be the given argument as is.
modifyer = changes ;
} else {
// People want to know exactly what is being modified or deleted.
// Let modifyer be a proxy function that finds out what changes the caller is actually doing
// and call the hooks accordingly!
modifyer = function ( item ) {
var origItem = deepClone ( item ) ; // Clone the item first so we can compare laters.
if ( changes . call ( this , item , this ) === false ) return false ; // Call the real modifyer function (If it returns false explicitely, it means it dont want to modify anyting on this object)
if ( ! hasOwn ( this , "value" ) ) {
// The real modifyer function requests a deletion of the object. Inform the deletingHook that a deletion is taking place.
deletingHook . call ( this , this . primKey , item , trans ) ;
} else {
// No deletion. Check what was changed
var objectDiff = getObjectDiff ( origItem , this . value ) ;
var additionalChanges = updatingHook . call ( this , objectDiff , this . primKey , origItem , trans ) ;
if ( additionalChanges ) {
// Hook want to apply additional modifications. Make sure to fullfill the will of the hook.
item = this . value ;
keys ( additionalChanges ) . forEach ( function ( keyPath ) {
setByKeyPath ( item , keyPath , additionalChanges [ keyPath ] ) ; // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath
} ) ;
}
}
} ;
}
} else if ( updatingHook === nop ) {
// changes is a set of {keyPath: value} and no one is listening to the updating hook.
var keyPaths = keys ( changes ) ;
var numKeys = keyPaths . length ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
modifyer = function ( item ) {
var anythingModified = false ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 ; i < numKeys ; ++ i ) {
var keyPath = keyPaths [ i ] ,
val = changes [ keyPath ] ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( getByKeyPath ( item , keyPath ) !== val ) {
setByKeyPath ( item , keyPath , val ) ; // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
anythingModified = true ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return anythingModified ;
} ;
} else {
// changes is a set of {keyPath: value} and people are listening to the updating hook so we need to call it and
// allow it to add additional modifications to make.
var origChanges = changes ;
changes = shallowClone ( origChanges ) ; // Let's work with a clone of the changes keyPath/value set so that we can restore it in case a hook extends it.
modifyer = function ( item ) {
var anythingModified = false ;
var additionalChanges = updatingHook . call ( this , changes , this . primKey , deepClone ( item ) , trans ) ;
if ( additionalChanges ) extend ( changes , additionalChanges ) ;
keys ( changes ) . forEach ( function ( keyPath ) {
var val = changes [ keyPath ] ;
if ( getByKeyPath ( item , keyPath ) !== val ) {
setByKeyPath ( item , keyPath , val ) ;
anythingModified = true ;
}
} ) ;
if ( additionalChanges ) changes = shallowClone ( origChanges ) ; // Restore original changes for next iteration
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return anythingModified ;
} ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var count = 0 ;
var successCount = 0 ;
var iterationComplete = false ;
var failures = [ ] ;
var failKeys = [ ] ;
var currentKey = null ;
function modifyItem ( item , cursor ) {
currentKey = cursor . primaryKey ;
var thisContext = {
primKey : cursor . primaryKey ,
value : item ,
onsuccess : null ,
onerror : null
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function onerror ( e ) {
failures . push ( e ) ;
failKeys . push ( thisContext . primKey ) ;
checkFinished ( ) ;
return true ; // Catch these errors and let a final rejection decide whether or not to abort entire transaction
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( modifyer . call ( thisContext , item , thisContext ) !== false ) {
var bDelete = ! hasOwn ( thisContext , "value" ) ;
++ count ;
tryCatch ( function ( ) {
var req = bDelete ? cursor . delete ( ) : cursor . update ( thisContext . value ) ;
req . _hookCtx = thisContext ;
req . onerror = hookedEventRejectHandler ( onerror ) ;
req . onsuccess = hookedEventSuccessHandler ( function ( ) {
++ successCount ;
checkFinished ( ) ;
} ) ;
} , onerror ) ;
} else if ( thisContext . onsuccess ) {
// Hook will expect either onerror or onsuccess to always be called!
thisContext . onsuccess ( thisContext . value ) ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function doReject ( e ) {
if ( e ) {
failures . push ( e ) ;
failKeys . push ( currentKey ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return reject ( new ModifyError ( "Error modifying one or more objects" , failures , successCount , failKeys ) ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function checkFinished ( ) {
if ( iterationComplete && successCount + failures . length === count ) {
if ( failures . length > 0 ) doReject ( ) ; else resolve ( successCount ) ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
self . clone ( ) . raw ( ) . _iterate ( modifyItem , function ( ) {
iterationComplete = true ;
checkFinished ( ) ;
} , doReject , idbstore ) ;
} ) ;
} ,
'delete' : function ( ) {
var _this = this ;
var ctx = this . _ctx ,
range = ctx . range ,
deletingHook = ctx . table . hook . deleting . fire ,
hasDeleteHook = deletingHook !== nop ;
if ( ! hasDeleteHook && isPlainKeyRange ( ctx ) && ( ctx . isPrimKey && ! hangsOnDeleteLargeKeyRange || ! range ) ) {
// May use IDBObjectStore.delete(IDBKeyRange) in this case (Issue #208)
// For chromium, this is the way most optimized version.
// For IE/Edge, this could hang the indexedDB engine and make operating system instable
// (https://gist.github.com/dfahlander/5a39328f029de18222cf2125d56c38f7)
return this . _write ( function ( resolve , reject , idbstore ) {
// Our API contract is to return a count of deleted items, so we have to count() before delete().
var onerror = eventRejectHandler ( reject ) ,
countReq = range ? idbstore . count ( range ) : idbstore . count ( ) ;
countReq . onerror = onerror ;
countReq . onsuccess = function ( ) {
var count = countReq . result ;
tryCatch ( function ( ) {
var delReq = range ? idbstore . delete ( range ) : idbstore . clear ( ) ;
delReq . onerror = onerror ;
delReq . onsuccess = function ( ) {
return resolve ( count ) ;
} ;
} , function ( err ) {
return reject ( err ) ;
} ) ;
} ;
} ) ;
} // Default version to use when collection is not a vanilla IDBKeyRange on the primary key.
// Divide into chunks to not starve RAM.
// If has delete hook, we will have to collect not just keys but also objects, so it will use
// more memory and need lower chunk size.
var CHUNKSIZE = hasDeleteHook ? 2000 : 10000 ;
return this . _write ( function ( resolve , reject , idbstore , trans ) {
var totalCount = 0 ; // Clone collection and change its table and set a limit of CHUNKSIZE on the cloned Collection instance.
var collection = _this . clone ( {
keysOnly : ! ctx . isMatch && ! hasDeleteHook
} ) // load just keys (unless filter() or and() or deleteHook has subscribers)
. distinct ( ) // In case multiEntry is used, never delete same key twice because resulting count
. limit ( CHUNKSIZE ) . raw ( ) ; // Don't filter through reading-hooks (like mapped classes etc)
var keysOrTuples = [ ] ; // We're gonna do things on as many chunks that are needed.
// Use recursion of nextChunk function:
var nextChunk = function ( ) {
return collection . each ( hasDeleteHook ? function ( val , cursor ) {
// Somebody subscribes to hook('deleting'). Collect all primary keys and their values,
// so that the hook can be called with its values in bulkDelete().
keysOrTuples . push ( [ cursor . primaryKey , cursor . value ] ) ;
} : function ( val , cursor ) {
// No one subscribes to hook('deleting'). Collect only primary keys:
keysOrTuples . push ( cursor . primaryKey ) ;
} ) . then ( function ( ) {
// Chromium deletes faster when doing it in sort order.
hasDeleteHook ? keysOrTuples . sort ( function ( a , b ) {
return ascending ( a [ 0 ] , b [ 0 ] ) ;
} ) : keysOrTuples . sort ( ascending ) ;
return bulkDelete ( idbstore , trans , keysOrTuples , hasDeleteHook , deletingHook ) ;
} ) . then ( function ( ) {
var count = keysOrTuples . length ;
totalCount += count ;
keysOrTuples = [ ] ;
return count < CHUNKSIZE ? totalCount : nextChunk ( ) ;
} ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
resolve ( nextChunk ( ) ) ;
} ) ;
}
} ;
} ) ; //
//
//
// ------------------------- Help functions ---------------------------
//
//
//
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function lowerVersionFirst ( a , b ) {
return a . _cfg . version - b . _cfg . version ;
}
function setApiOnPlace ( objs , tableNames , dbschema ) {
tableNames . forEach ( function ( tableName ) {
var schema = dbschema [ tableName ] ;
objs . forEach ( function ( obj ) {
if ( ! ( tableName in obj ) ) {
if ( obj === Transaction . prototype || obj instanceof Transaction ) {
// obj is a Transaction prototype (or prototype of a subclass to Transaction)
// Make the API a getter that returns this.table(tableName)
setProp ( obj , tableName , {
get : function ( ) {
return this . table ( tableName ) ;
}
} ) ;
} else {
// Table will not be bound to a transaction (will use Dexie.currentTransaction)
obj [ tableName ] = new Table ( tableName , schema ) ;
}
}
} ) ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function removeTablesApi ( objs ) {
objs . forEach ( function ( obj ) {
for ( var key in obj ) {
if ( obj [ key ] instanceof Table ) delete obj [ key ] ;
2018-11-14 17:32:35 +01:00
}
} ) ;
}
2018-11-21 01:42:52 +01:00
function iterate ( req , filter , fn , resolve , reject , valueMapper ) {
// Apply valueMapper (hook('reading') or mappped class)
var mappedFn = valueMapper ? function ( x , c , a ) {
return fn ( valueMapper ( x ) , c , a ) ;
} : fn ; // Wrap fn with PSD and microtick stuff from Promise.
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var wrappedFn = wrap ( mappedFn , reject ) ;
if ( ! req . onerror ) req . onerror = eventRejectHandler ( reject ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( filter ) {
req . onsuccess = trycatcher ( function filter _record ( ) {
var cursor = req . result ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( cursor ) {
var c = function ( ) {
cursor . continue ( ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( filter ( cursor , function ( advancer ) {
c = advancer ;
} , resolve , reject ) ) wrappedFn ( cursor . value , cursor , function ( advancer ) {
c = advancer ;
} ) ;
c ( ) ;
} else {
resolve ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} , reject ) ;
} else {
req . onsuccess = trycatcher ( function filter _record ( ) {
var cursor = req . result ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( cursor ) {
var c = function ( ) {
cursor . continue ( ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
wrappedFn ( cursor . value , cursor , function ( advancer ) {
c = advancer ;
} ) ;
c ( ) ;
} else {
resolve ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} , reject ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function parseIndexSyntax ( indexes ) {
/// <param name="indexes" type="String"></param>
/// <returns type="Array" elementType="IndexSpec"></returns>
var rv = [ ] ;
indexes . split ( ',' ) . forEach ( function ( index ) {
index = index . trim ( ) ;
var name = index . replace ( /([&*]|\+\+)/g , "" ) ; // Remove "&", "++" and "*"
// Let keyPath of "[a+b]" be ["a","b"]:
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var keyPath = /^\[/ . test ( name ) ? name . match ( /^\[(.*)\]$/ ) [ 1 ] . split ( '+' ) : name ;
rv . push ( new IndexSpec ( name , keyPath || null , /\&/ . test ( index ) , /\*/ . test ( index ) , /\+\+/ . test ( index ) , isArray ( keyPath ) , /\./ . test ( index ) ) ) ;
} ) ;
return rv ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function cmp ( key1 , key2 ) {
return indexedDB . cmp ( key1 , key2 ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function min ( a , b ) {
return cmp ( a , b ) < 0 ? a : b ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function max ( a , b ) {
return cmp ( a , b ) > 0 ? a : b ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function ascending ( a , b ) {
return indexedDB . cmp ( a , b ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function descending ( a , b ) {
return indexedDB . cmp ( b , a ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function simpleCompare ( a , b ) {
return a < b ? - 1 : a === b ? 0 : 1 ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function simpleCompareReverse ( a , b ) {
return a > b ? - 1 : a === b ? 0 : 1 ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function combine ( filter1 , filter2 ) {
return filter1 ? filter2 ? function ( ) {
return filter1 . apply ( this , arguments ) && filter2 . apply ( this , arguments ) ;
} : filter1 : filter2 ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function readGlobalSchema ( ) {
db . verno = idbdb . version / 10 ;
db . _dbSchema = globalSchema = { } ;
dbStoreNames = slice ( idbdb . objectStoreNames , 0 ) ;
if ( dbStoreNames . length === 0 ) return ; // Database contains no stores.
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var trans = idbdb . transaction ( safariMultiStoreFix ( dbStoreNames ) , 'readonly' ) ;
dbStoreNames . forEach ( function ( storeName ) {
var store = trans . objectStore ( storeName ) ,
keyPath = store . keyPath ,
dotted = keyPath && typeof keyPath === 'string' && keyPath . indexOf ( '.' ) !== - 1 ;
var primKey = new IndexSpec ( keyPath , keyPath || "" , false , false , ! ! store . autoIncrement , keyPath && typeof keyPath !== 'string' , dotted ) ;
var indexes = [ ] ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var j = 0 ; j < store . indexNames . length ; ++ j ) {
var idbindex = store . index ( store . indexNames [ j ] ) ;
keyPath = idbindex . keyPath ;
dotted = keyPath && typeof keyPath === 'string' && keyPath . indexOf ( '.' ) !== - 1 ;
var index = new IndexSpec ( idbindex . name , keyPath , ! ! idbindex . unique , ! ! idbindex . multiEntry , false , keyPath && typeof keyPath !== 'string' , dotted ) ;
indexes . push ( index ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
globalSchema [ storeName ] = new TableSchema ( storeName , primKey , indexes , { } ) ;
} ) ;
setApiOnPlace ( [ allTables ] , keys ( globalSchema ) , globalSchema ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function adjustToExistingIndexNames ( schema , idbtrans ) {
/// <summary>
/// Issue #30 Problem with existing db - adjust to existing index names when migrating from non-dexie db
/// </summary>
/// <param name="schema" type="Object">Map between name and TableSchema</param>
/// <param name="idbtrans" type="IDBTransaction"></param>
var storeNames = idbtrans . db . objectStoreNames ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 ; i < storeNames . length ; ++ i ) {
var storeName = storeNames [ i ] ;
var store = idbtrans . objectStore ( storeName ) ;
hasGetAll = 'getAll' in store ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var j = 0 ; j < store . indexNames . length ; ++ j ) {
var indexName = store . indexNames [ j ] ;
var keyPath = store . index ( indexName ) . keyPath ;
var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice ( keyPath ) . join ( '+' ) + "]" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( schema [ storeName ] ) {
var indexSpec = schema [ storeName ] . idxByName [ dexieName ] ;
if ( indexSpec ) indexSpec . name = indexName ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
}
} // Bug with getAll() on Safari ver<604 on Workers only, see discussion following PR #579
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( /Safari/ . test ( navigator . userAgent ) && ! /(Chrome\/|Edge\/)/ . test ( navigator . userAgent ) && _global . WorkerGlobalScope && _global instanceof _global . WorkerGlobalScope && [ ] . concat ( navigator . userAgent . match ( /Safari\/(\d*)/ ) ) [ 1 ] < 604 ) {
hasGetAll = false ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function fireOnBlocked ( ev ) {
db . on ( "blocked" ) . fire ( ev ) ; // Workaround (not fully*) for missing "versionchange" event in IE,Edge and Safari:
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
connections . filter ( function ( c ) {
return c . name === db . name && c !== db && ! c . _vcFired ;
} ) . map ( function ( c ) {
return c . on ( "versionchange" ) . fire ( ev ) ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
extend ( this , {
Collection : Collection ,
Table : Table ,
Transaction : Transaction ,
Version : Version ,
WhereClause : WhereClause
} ) ;
init ( ) ;
addons . forEach ( function ( fn ) {
fn ( db ) ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function parseType ( type ) {
if ( typeof type === 'function' ) {
return new type ( ) ;
} else if ( isArray ( type ) ) {
return [ parseType ( type [ 0 ] ) ] ;
} else if ( type && _typeof ( type ) === 'object' ) {
var rv = { } ;
applyStructure ( rv , type ) ;
return rv ;
} else {
return type ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function applyStructure ( obj , structure ) {
keys ( structure ) . forEach ( function ( member ) {
var value = parseType ( structure [ member ] ) ;
obj [ member ] = value ;
} ) ;
return obj ;
}
function hookedEventSuccessHandler ( resolve ) {
// wrap() is needed when calling hooks because the rare scenario of:
// * hook does a db operation that fails immediately (IDB throws exception)
// For calling db operations on correct transaction, wrap makes sure to set PSD correctly.
// wrap() will also execute in a virtual tick.
// * If not wrapped in a virtual tick, direct exception will launch a new physical tick.
// * If this was the last event in the bulk, the promise will resolve after a physical tick
// and the transaction will have committed already.
// If no hook, the virtual tick will be executed in the reject()/resolve of the final promise,
// because it is always marked with _lib = true when created using Transaction._promise().
return wrap ( function ( event ) {
var req = event . target ,
ctx = req . _hookCtx ,
// Contains the hook error handler. Put here instead of closure to boost performance.
result = ctx . value || req . result ,
// Pass the object value on updates. The result from IDB is the primary key.
hookSuccessHandler = ctx && ctx . onsuccess ;
hookSuccessHandler && hookSuccessHandler ( result ) ;
resolve && resolve ( result ) ;
} , resolve ) ;
}
function eventRejectHandler ( reject ) {
return wrap ( function ( event ) {
preventDefault ( event ) ;
reject ( event . target . error ) ;
return false ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function eventSuccessHandler ( resolve ) {
return wrap ( function ( event ) {
resolve ( event . target . result ) ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function hookedEventRejectHandler ( reject ) {
return wrap ( function ( event ) {
// See comment on hookedEventSuccessHandler() why wrap() is needed only when supporting hooks.
var req = event . target ,
err = req . error ,
ctx = req . _hookCtx ,
// Contains the hook error handler. Put here instead of closure to boost performance.
hookErrorHandler = ctx && ctx . onerror ;
hookErrorHandler && hookErrorHandler ( err ) ;
preventDefault ( event ) ;
reject ( err ) ;
return false ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function preventDefault ( event ) {
if ( event . stopPropagation ) event . stopPropagation ( ) ;
if ( event . preventDefault ) event . preventDefault ( ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function awaitIterator ( iterator ) {
var callNext = function ( result ) {
return iterator . next ( result ) ;
} ,
doThrow = function ( error ) {
return iterator . throw ( error ) ;
} ,
onSuccess = step ( callNext ) ,
onError = step ( doThrow ) ;
function step ( getNext ) {
return function ( val ) {
var next = getNext ( val ) ,
value = next . value ;
return next . done ? value : ! value || typeof value . then !== 'function' ? isArray ( value ) ? Promise . all ( value ) . then ( onSuccess , onError ) : onSuccess ( value ) : value . then ( onSuccess , onError ) ;
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return step ( callNext ) ( ) ;
} //
// IndexSpec struct
//
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function IndexSpec ( name , keyPath , unique , multi , auto , compound , dotted ) {
/// <param name="name" type="String"></param>
/// <param name="keyPath" type="String"></param>
/// <param name="unique" type="Boolean"></param>
/// <param name="multi" type="Boolean"></param>
/// <param name="auto" type="Boolean"></param>
/// <param name="compound" type="Boolean"></param>
/// <param name="dotted" type="Boolean"></param>
this . name = name ;
this . keyPath = keyPath ;
this . unique = unique ;
this . multi = multi ;
this . auto = auto ;
this . compound = compound ;
this . dotted = dotted ;
var keyPathSrc = typeof keyPath === 'string' ? keyPath : keyPath && '[' + [ ] . join . call ( keyPath , '+' ) + ']' ;
this . src = ( unique ? '&' : '' ) + ( multi ? '*' : '' ) + ( auto ? "++" : "" ) + keyPathSrc ;
} //
// TableSchema struct
//
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function TableSchema ( name , primKey , indexes , instanceTemplate ) {
/// <param name="name" type="String"></param>
/// <param name="primKey" type="IndexSpec"></param>
/// <param name="indexes" type="Array" elementType="IndexSpec"></param>
/// <param name="instanceTemplate" type="Object"></param>
this . name = name ;
this . primKey = primKey || new IndexSpec ( ) ;
this . indexes = indexes || [ new IndexSpec ( ) ] ;
this . instanceTemplate = instanceTemplate ;
this . mappedClass = null ;
this . idxByName = arrayToObject ( indexes , function ( index ) {
return [ index . name , index ] ;
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function safariMultiStoreFix ( storeNames ) {
return storeNames . length === 1 ? storeNames [ 0 ] : storeNames ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function getNativeGetDatabaseNamesFn ( indexedDB ) {
var fn = indexedDB && ( indexedDB . getDatabaseNames || indexedDB . webkitGetDatabaseNames ) ;
return fn && fn . bind ( indexedDB ) ;
} // Export Error classes
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
props ( Dexie , fullNameExceptions ) ; // Dexie.XXXError = class XXXError {...};
//
// Static methods and properties
//
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
props ( Dexie , {
//
// Static delete() method.
//
delete : function ( databaseName ) {
var db = new Dexie ( databaseName ) ,
promise = db . delete ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
promise . onblocked = function ( fn ) {
db . on ( "blocked" , fn ) ;
return this ;
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
return promise ;
} ,
//
// Static exists() method.
//
exists : function ( name ) {
return new Dexie ( name ) . open ( ) . then ( function ( db ) {
db . close ( ) ;
return true ;
} ) . catch ( Dexie . NoSuchDatabaseError , function ( ) {
return false ;
} ) ;
} ,
//
// Static method for retrieving a list of all existing databases at current host.
//
getDatabaseNames : function ( cb ) {
var getDatabaseNames = getNativeGetDatabaseNamesFn ( Dexie . dependencies . indexedDB ) ;
return getDatabaseNames ? new Promise ( function ( resolve , reject ) {
var req = getDatabaseNames ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
req . onsuccess = function ( event ) {
resolve ( slice ( event . target . result , 0 ) ) ; // Converst DOMStringList to Array<String>
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
req . onerror = eventRejectHandler ( reject ) ;
} ) . then ( cb ) : dbNamesDB . dbnames . toCollection ( ) . primaryKeys ( cb ) ;
} ,
defineClass : function ( ) {
// Default constructor able to copy given properties into this object.
function Class ( properties ) {
/// <param name="properties" type="Object" optional="true">Properties to initialize object with.
/// </param>
if ( properties ) extend ( this , properties ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return Class ;
} ,
applyStructure : applyStructure ,
ignoreTransaction : function ( scopeFunc ) {
// In case caller is within a transaction but needs to create a separate transaction.
// Example of usage:
//
// Let's say we have a logger function in our app. Other application-logic should be unaware of the
// logger function and not need to include the 'logentries' table in all transaction it performs.
// The logging should always be done in a separate transaction and not be dependant on the current
// running transaction context. Then you could use Dexie.ignoreTransaction() to run code that starts a new transaction.
//
// Dexie.ignoreTransaction(function() {
// db.logentries.add(newLogEntry);
// });
//
// Unless using Dexie.ignoreTransaction(), the above example would try to reuse the current transaction
// in current Promise-scope.
//
// An alternative to Dexie.ignoreTransaction() would be setImmediate() or setTimeout(). The reason we still provide an
// API for this because
// 1) The intention of writing the statement could be unclear if using setImmediate() or setTimeout().
// 2) setTimeout() would wait unnescessary until firing. This is however not the case with setImmediate().
// 3) setImmediate() is not supported in the ES standard.
// 4) You might want to keep other PSD state that was set in a parent PSD, such as PSD.letThrough.
return PSD . trans ? usePSD ( PSD . transless , scopeFunc ) : // Use the closest parent that was non-transactional.
scopeFunc ( ) ; // No need to change scope because there is no ongoing transaction.
} ,
vip : function ( fn ) {
// To be used by subscribers to the on('ready') event.
// This will let caller through to access DB even when it is blocked while the db.ready() subscribers are firing.
// This would have worked automatically if we were certain that the Provider was using Dexie.Promise for all asyncronic operations. The promise PSD
// from the provider.connect() call would then be derived all the way to when provider would call localDatabase.applyChanges(). But since
// the provider more likely is using non-promise async APIs or other thenable implementations, we cannot assume that.
// Note that this method is only useful for on('ready') subscribers that is returning a Promise from the event. If not using vip()
// the database could deadlock since it wont open until the returned Promise is resolved, and any non-VIPed operation started by
// the caller will not resolve until database is opened.
return newScope ( function ( ) {
PSD . letThrough = true ; // Make sure we are let through if still blocking db due to onready is firing.
return fn ( ) ;
} ) ;
} ,
async : function ( generatorFn ) {
return function ( ) {
try {
var rv = awaitIterator ( generatorFn . apply ( this , arguments ) ) ;
if ( ! rv || typeof rv . then !== 'function' ) return Promise . resolve ( rv ) ;
return rv ;
} catch ( e ) {
return rejection ( e ) ;
}
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
} ,
spawn : function ( generatorFn , args , thiz ) {
try {
var rv = awaitIterator ( generatorFn . apply ( thiz , args || [ ] ) ) ;
if ( ! rv || typeof rv . then !== 'function' ) return Promise . resolve ( rv ) ;
return rv ;
} catch ( e ) {
return rejection ( e ) ;
}
} ,
// Dexie.currentTransaction property
currentTransaction : {
get : function ( ) {
return PSD . trans || null ;
}
} ,
waitFor : function ( promiseOrFunction , optionalTimeout ) {
// If a function is provided, invoke it and pass the returning value to Transaction.waitFor()
var promise = Promise . resolve ( typeof promiseOrFunction === 'function' ? Dexie . ignoreTransaction ( promiseOrFunction ) : promiseOrFunction ) . timeout ( optionalTimeout || 60000 ) ; // Default the timeout to one minute. Caller may specify Infinity if required.
// Run given promise on current transaction. If no current transaction, just return a Dexie promise based
// on given value.
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return PSD . trans ? PSD . trans . waitFor ( promise ) : promise ;
} ,
// Export our Promise implementation since it can be handy as a standalone Promise implementation
Promise : Promise ,
// Dexie.debug proptery:
// Dexie.debug = false
// Dexie.debug = true
// Dexie.debug = "dexie" - don't hide dexie's stack frames.
debug : {
get : function ( ) {
return debug ;
} ,
set : function ( value ) {
setDebug ( value , value === 'dexie' ? function ( ) {
return true ;
} : dexieStackFrameFilter ) ;
}
} ,
// Export our derive/extend/override methodology
derive : derive ,
extend : extend ,
props : props ,
override : override ,
// Export our Events() function - can be handy as a toolkit
Events : Events ,
// Utilities
getByKeyPath : getByKeyPath ,
setByKeyPath : setByKeyPath ,
delByKeyPath : delByKeyPath ,
shallowClone : shallowClone ,
deepClone : deepClone ,
getObjectDiff : getObjectDiff ,
asap : asap ,
maxKey : maxKey ,
minKey : minKey ,
// Addon registry
addons : [ ] ,
// Global DB connection list
connections : connections ,
MultiModifyError : exceptions . Modify ,
errnames : errnames ,
// Export other static classes
IndexSpec : IndexSpec ,
TableSchema : TableSchema ,
//
// Dependencies
//
// These will automatically work in browsers with indexedDB support, or where an indexedDB polyfill has been included.
//
// In node.js, however, these properties must be set "manually" before instansiating a new Dexie().
// For node.js, you need to require indexeddb-js or similar and then set these deps.
//
dependencies : function ( ) {
try {
return {
// Required:
indexedDB : _global . indexedDB || _global . mozIndexedDB || _global . webkitIndexedDB || _global . msIndexedDB ,
IDBKeyRange : _global . IDBKeyRange || _global . webkitIDBKeyRange
} ;
} catch ( e ) {
return {
indexedDB : null ,
IDBKeyRange : null
} ;
}
} ( ) ,
// API Version Number: Type Number, make sure to always set a version number that can be comparable correctly. Example: 0.9, 0.91, 0.92, 1.0, 1.01, 1.1, 1.2, 1.21, etc.
semVer : DEXIE _VERSION ,
version : DEXIE _VERSION . split ( '.' ) . map ( function ( n ) {
return parseInt ( n ) ;
} ) . reduce ( function ( p , c , i ) {
return p + c / Math . pow ( 10 , i * 2 ) ;
} ) ,
// https://github.com/dfahlander/Dexie.js/issues/186
// typescript compiler tsc in mode ts-->es5 & commonJS, will expect require() to return
// x.default. Workaround: Set Dexie.default = Dexie.
default : Dexie ,
// Make it possible to import {Dexie} (non-default import)
// Reason 1: May switch to that in future.
// Reason 2: We declare it both default and named exported in d.ts to make it possible
// to let addons extend the Dexie interface with Typescript 2.1 (works only when explicitely
// exporting the symbol, not just default exporting)
Dexie : Dexie
} ) ; // Map DOMErrors and DOMExceptions to corresponding Dexie errors. May change in Dexie v2.0.
Promise . rejectionMapper = mapError ; // Initialize dbNamesDB (won't ever be opened on chromium browsers')
dbNamesDB = new Dexie ( '__dbnames' ) ;
dbNamesDB . version ( 1 ) . stores ( {
dbnames : 'name'
} ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
( function ( ) {
// Migrate from Dexie 1.x database names stored in localStorage:
var DBNAMES = 'Dexie.DatabaseNames' ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
try {
if ( ( typeof localStorage === "undefined" ? "undefined" : _typeof ( localStorage ) ) !== undefined && _global . document !== undefined ) {
// Have localStorage and is not executing in a worker. Lets migrate from Dexie 1.x.
JSON . parse ( localStorage . getItem ( DBNAMES ) || "[]" ) . forEach ( function ( name ) {
return dbNamesDB . dbnames . put ( {
name : name
} ) . catch ( nop ) ;
} ) ;
localStorage . removeItem ( DBNAMES ) ;
}
} catch ( _e ) { }
} ) ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _default = Dexie ;
exports . default = _default ;
2018-12-06 22:49:49 +01:00
} , { } ] , "../../../../brain/tools/utilities/DBUtils.js" : [ function ( require , module , exports ) {
"use strict" ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = exports . FINAL _KEY = exports . COUNT = void 0 ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
var _DataUtils = _interopRequireWildcard ( require ( "../utilities/DataUtils" ) ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
var _dexie = _interopRequireDefault ( require ( "dexie" ) ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
var DataEvent = _interopRequireWildcard ( require ( "../events/DataEvent" ) ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
var COUNT ;
exports . COUNT = COUNT ;
var FINAL _KEY ;
exports . FINAL _KEY = FINAL _KEY ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
var DBUtils =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function DBUtils ( ) {
_classCallCheck ( this , DBUtils ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
this . dataUtils = new _DataUtils . default ( ) ;
this . db = new _dexie . default ( "fipamo_posts" ) ;
this . db . version ( 1 ) . stores ( {
postList : 'id,post'
} ) ;
this . db . postList . toArray ( function ( array ) {
exports . COUNT = COUNT = array . length ;
exports . FINAL _KEY = FINAL _KEY = array [ COUNT - 1 ] . id ;
} ) ;
} //--------------------------
// methods
//--------------------------
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
_createClass ( DBUtils , [ {
key : "modify" ,
value : function modify ( id , postData ) {
var self = this ;
var freshID ;
return new Promise ( function ( resolve , reject ) {
if ( id == null ) {
self . db . postList . put ( postData ) . then ( function ( fresh ) {
freshID = fresh ;
} ) . catch ( function ( e ) {
var err = {
message : "PUT ERROR" ,
error : e
} ;
} ) ;
} else {
self . db . postList . update ( Number ( id ) , {
post : postData
} ) . then ( function ( updated ) { } ) . catch ( function ( e ) {
var err = {
message : "UPDATE ERROR" ,
error : e
} ;
} ) ;
}
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
self . db . postList . toArray ( function ( array ) {
self . syncRemote ( array , freshID ) . then ( function ( response ) {
resolve ( {
response : response
} ) ;
} ) . catch ( function ( err ) {
reject ( {
err : err
} ) ;
} ) ;
} ) ;
} ) ;
2018-11-22 02:08:53 +01:00
}
2018-12-06 22:49:49 +01:00
} , {
key : "syncLocal" ,
value : function syncLocal ( array ) {
var self = this ;
return new Promise ( function ( resolve , reject ) {
self . db . postList . clear ( ) . then ( function ( result ) {
self . db . postList . bulkAdd ( array ) . then ( function ( key ) {
self . db . postList . toArray ( function ( array ) {
var event = DataEvent . LOCAL _DB _READY ;
resolve ( {
event : event
} ) ;
} ) ;
} ) . catch ( _dexie . default . BulkError , function ( e ) {
reject ( {
e : e
} ) ;
} ) ;
} ) ;
} ) ;
2018-11-22 02:08:53 +01:00
}
2018-12-06 22:49:49 +01:00
} , {
key : "syncRemote" ,
value : function syncRemote ( db , newPostId ) {
var self = this ;
return new Promise ( function ( resolve , reject ) {
self . dataUtils . request ( '/api/post/sync' , DataEvent . POSTS _SYNCED , _DataUtils . REQUEST _TYPE _POST , _DataUtils . CONTENT _TYPE _JSON , db ) . then ( function ( response ) {
var bounce = {
message : response ,
newPost : newPostId
} ;
resolve ( bounce ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
2018-11-22 02:08:53 +01:00
}
2018-12-06 22:49:49 +01:00
} , {
key : "getPost" ,
value : function getPost ( id ) {
var self = this ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
if ( id == null ) {
return new Promise ( function ( resolve , reject ) {
self . db . postList . toArray ( function ( array ) {
resolve ( array ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
} else {
return new Promise ( function ( resolve , reject ) {
self . db . postList . get ( Number ( id ) ) . then ( function ( obj ) {
resolve ( obj ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
2018-11-22 02:08:53 +01:00
}
2018-12-06 22:49:49 +01:00
}
} , {
key : "archivePost" ,
value : function archivePost ( id , archive ) {
var self = this ;
return new Promise ( function ( resolve , reject ) {
self . db . postList . update ( Number ( id ) , {
post : archive
} ) . then ( function ( deleted ) {
self . db . postList . toArray ( function ( array ) {
self . syncRemote ( array , null ) . then ( function ( response ) {
resolve ( {
response : response
} ) ;
} ) . catch ( function ( err ) {
reject ( {
err : err
} ) ;
} ) ;
} ) ;
} ) . catch ( function ( e ) {
console . log ( "ERROR" , e ) ;
} ) ;
} ) ;
} //--------------------------
// event handlers
//--------------------------
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
} ] ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
return DBUtils ;
} ( ) ;
2018-11-22 02:08:53 +01:00
2018-12-06 22:49:49 +01:00
exports . default = DBUtils ;
} , { "../utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "dexie" : "../../../../node_modules/dexie/dist/dexie.es.js" , "../events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" } ] , "../../../../node_modules/uuid/lib/rng-browser.js" : [ function ( require , module , exports ) {
2018-11-26 23:14:13 +01:00
// Unique ID creation requires a high quality random # generator. In the
// browser this is a little complicated due to unknown quality of Math.random()
// and inconsistent support for the `crypto` API. We do the best we can via
// feature-detection
// getRandomValues needs to be invoked in a context where "this" is a Crypto
// implementation. Also, find the complete implementation of crypto on IE11.
var getRandomValues = ( typeof ( crypto ) != 'undefined' && crypto . getRandomValues && crypto . getRandomValues . bind ( crypto ) ) ||
( typeof ( msCrypto ) != 'undefined' && typeof window . msCrypto . getRandomValues == 'function' && msCrypto . getRandomValues . bind ( msCrypto ) ) ;
if ( getRandomValues ) {
// WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
var rnds8 = new Uint8Array ( 16 ) ; // eslint-disable-line no-undef
module . exports = function whatwgRNG ( ) {
getRandomValues ( rnds8 ) ;
return rnds8 ;
} ;
} else {
// Math.random()-based (RNG)
//
// If all else fails, use Math.random(). It's fast, but is of unspecified
// quality.
var rnds = new Array ( 16 ) ;
module . exports = function mathRNG ( ) {
for ( var i = 0 , r ; i < 16 ; i ++ ) {
if ( ( i & 0x03 ) === 0 ) r = Math . random ( ) * 0x100000000 ;
rnds [ i ] = r >>> ( ( i & 0x03 ) << 3 ) & 0xff ;
}
return rnds ;
} ;
}
} , { } ] , "../../../../node_modules/uuid/lib/bytesToUuid.js" : [ function ( require , module , exports ) {
/ * *
* Convert array of 16 byte values to UUID string format of the form :
* XXXXXXXX - XXXX - XXXX - XXXX - XXXXXXXXXXXX
* /
var byteToHex = [ ] ;
for ( var i = 0 ; i < 256 ; ++ i ) {
byteToHex [ i ] = ( i + 0x100 ) . toString ( 16 ) . substr ( 1 ) ;
}
function bytesToUuid ( buf , offset ) {
var i = offset || 0 ;
var bth = byteToHex ;
// join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
return ( [ bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] , '-' ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] , '-' ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] , '-' ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] , '-' ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] ,
bth [ buf [ i ++ ] ] , bth [ buf [ i ++ ] ] ] ) . join ( '' ) ;
}
module . exports = bytesToUuid ;
} , { } ] , "../../../../node_modules/uuid/v4.js" : [ function ( require , module , exports ) {
var rng = require ( './lib/rng' ) ;
var bytesToUuid = require ( './lib/bytesToUuid' ) ;
function v4 ( options , buf , offset ) {
var i = buf && offset || 0 ;
if ( typeof ( options ) == 'string' ) {
buf = options === 'binary' ? new Array ( 16 ) : null ;
options = null ;
}
options = options || { } ;
var rnds = options . random || ( options . rng || rng ) ( ) ;
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
rnds [ 6 ] = ( rnds [ 6 ] & 0x0f ) | 0x40 ;
rnds [ 8 ] = ( rnds [ 8 ] & 0x3f ) | 0x80 ;
// Copy bytes to buffer, if provided
if ( buf ) {
for ( var ii = 0 ; ii < 16 ; ++ ii ) {
buf [ i + ii ] = rnds [ ii ] ;
}
}
return buf || bytesToUuid ( rnds ) ;
}
module . exports = v4 ;
} , { "./lib/rng" : "../../../../node_modules/uuid/lib/rng-browser.js" , "./lib/bytesToUuid" : "../../../../node_modules/uuid/lib/bytesToUuid.js" } ] , "actions/PostActions.js" : [ function ( require , module , exports ) {
2018-11-21 01:42:52 +01:00
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _DataUtils = _interopRequireWildcard ( require ( "../../../../../brain//tools/utilities/DataUtils" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _StringUtils = _interopRequireDefault ( require ( "../../../../../brain//tools/utilities/StringUtils" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-26 23:14:13 +01:00
var _DateUtils = _interopRequireDefault ( require ( "../../../../../brain/tools/utilities/DateUtils" ) ) ;
2018-12-04 03:19:10 +01:00
var _DBUtils = _interopRequireDefault ( require ( "../../../../../brain/tools/utilities/DBUtils" ) ) ;
2018-11-21 01:42:52 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-14 17:32:35 +01:00
2018-11-26 23:14:13 +01:00
var uuidv4 = require ( 'uuid/v4' ) ;
2018-11-21 01:42:52 +01:00
var PostActions =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function PostActions ( ) {
_classCallCheck ( this , PostActions ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
this . dataUtils = new _DataUtils . default ( ) ;
2018-11-26 23:14:13 +01:00
this . dateUtils = new _DateUtils . default ( ) ;
2018-12-04 03:19:10 +01:00
this . dbUtils = new _DBUtils . default ( ) ;
2018-11-21 01:42:52 +01:00
} //--------------------------
// methods
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_createClass ( PostActions , [ {
2018-11-22 02:08:53 +01:00
key : "update" ,
2018-11-26 23:14:13 +01:00
value : function update ( id , data , files , lastKey ) {
2018-11-22 02:08:53 +01:00
var self = this ;
2018-12-04 03:19:10 +01:00
var freshData ;
2018-11-22 02:08:53 +01:00
return new Promise ( function ( resolve , reject ) {
var txt = document . createElement ( "textarea" ) ;
txt . innerHTML = document . getElementById ( 'edit-post-text' ) . innerHTML ;
var html = txt . value ;
html = html . replace ( /<\/?span[^>]*>/g , "" ) ; //removes highightjs styling
2018-12-06 22:49:49 +01:00
html = html . replace ( /<\/?br[^>]*>/g , "\n" ) ; //convert back to encoded line break for storage
2018-11-22 02:08:53 +01:00
data . title = document . getElementById ( 'post_title' ) . value ;
data . slug = new _StringUtils . default ( ) . cleanString ( document . getElementById ( 'post_title' ) . value ) ;
2018-12-06 22:49:49 +01:00
data . plaintext = html ;
data . html = html ;
2018-11-22 02:08:53 +01:00
data . created = document . getElementById ( 'post-date' ) . value ;
data . tags = document . getElementById ( 'post_tags' ) . value ;
data . page = document . getElementById ( 'option-page' ) . getAttribute ( 'data-active' ) ;
data . featured = document . getElementById ( 'option-feature' ) . getAttribute ( 'data-active' ) ;
data . published = document . getElementById ( 'option-published' ) . getAttribute ( 'data-active' ) ;
2018-11-26 23:14:13 +01:00
if ( files . length != 0 ) {
for ( var i = 0 ; i < files . length ; i ++ ) {
var file = files [ i ] ; // Check the file type.
if ( ! file . type . match ( 'image.*' ) ) {
continue ;
}
2018-11-27 23:19:57 +01:00
data . feature = "/content/blog-images/" + self . dateUtils . getDate ( 'year' , new Date ( ) ) + "/" + self . dateUtils . getDate ( 'month' , new Date ( ) ) + "/" + file . name ;
2018-11-26 23:14:13 +01:00
}
2018-12-04 03:19:10 +01:00
} else {
if ( typeof data . feature == 'undefined' ) data . feature = "" ;
2018-11-26 23:14:13 +01:00
}
if ( id == null ) {
2018-12-04 03:19:10 +01:00
freshData = {
2018-11-26 23:14:13 +01:00
id : lastKey + 1 ,
post : {
uuid : uuidv4 ( ) ,
title : data . title ,
slug : data . slug ,
plaintext : data . plaintext ,
html : data . html ,
feature : data . feature ,
created : data . created ,
tags : data . tags ,
page : data . page ,
featured : data . featured ,
published : data . published ,
2018-12-04 03:19:10 +01:00
deleted : "" ,
2018-11-26 23:14:13 +01:00
author : "user"
}
2018-12-04 03:19:10 +01:00
} ;
2018-11-26 23:14:13 +01:00
} else {
2018-12-04 03:19:10 +01:00
freshData = data ;
2018-11-26 23:14:13 +01:00
}
2018-11-27 23:19:57 +01:00
2018-12-04 03:19:10 +01:00
self . dbUtils . modify ( id , freshData ) . then ( function ( response ) {
resolve ( response ) ;
2018-11-27 23:19:57 +01:00
} ) . catch ( function ( err ) {
2018-12-04 03:19:10 +01:00
reject ( err ) ;
2018-11-27 23:19:57 +01:00
} ) ;
2018-11-22 02:08:53 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
} , {
key : "deletePost" ,
2018-12-04 03:19:10 +01:00
value : function deletePost ( id , body ) {
2018-11-21 01:42:52 +01:00
var self = this ;
2018-12-04 03:19:10 +01:00
body . deleted = new Date ( ) . toString ( ) ;
2018-11-21 01:42:52 +01:00
return new Promise ( function ( resolve , reject ) {
2018-12-04 03:19:10 +01:00
self . dbUtils . archivePost ( id , body ) . then ( function ( response ) {
console . log ( response ) ;
resolve ( response ) ;
2018-11-21 01:42:52 +01:00
} ) . catch ( function ( err ) {
2018-12-04 03:19:10 +01:00
console . log ( err ) ;
reject ( error ) ;
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-27 23:19:57 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} //--------------------------
// event handlers
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} ] ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return PostActions ;
} ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . default = PostActions ;
2018-12-06 22:49:49 +01:00
} , { "../../../../../brain//tools/utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "../../../../../brain//tools/utilities/StringUtils" : "../../../../brain/tools/utilities/StringUtils.js" , "../../../../../brain/tools/utilities/DateUtils" : "../../../../brain/tools/utilities/DateUtils.js" , "../../../../../brain/tools/utilities/DBUtils" : "../../../../brain/tools/utilities/DBUtils.js" , "uuid/v4" : "../../../../node_modules/uuid/v4.js" } ] , "../../../../brain/tools/events/EditorEvent.js" : [ function ( require , module , exports ) {
2018-11-21 01:42:52 +01:00
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = exports . EDITOR _UPDATE = exports . EDITOR _SAVE = exports . EDITOR _UPLOAD _POST _IMAGE = exports . EDITOR _DELETE = void 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var EDITOR _DELETE = 'editorDelete' ;
exports . EDITOR _DELETE = EDITOR _DELETE ;
var EDITOR _UPLOAD _POST _IMAGE = 'editorUploadImage' ;
exports . EDITOR _UPLOAD _POST _IMAGE = EDITOR _UPLOAD _POST _IMAGE ;
var EDITOR _SAVE = 'editorSave' ;
exports . EDITOR _SAVE = EDITOR _SAVE ;
var EDITOR _UPDATE = 'editorUpdate' ;
exports . EDITOR _UPDATE = EDITOR _UPDATE ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var EditorEvent = function EditorEvent ( ) {
_classCallCheck ( this , EditorEvent ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _default = new EditorEvent ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . default = _default ;
} , { } ] , "../../../../node_modules/tiny-date-picker/dist/tiny-date-picker.js" : [ function ( require , module , exports ) {
var define ;
var global = arguments [ 3 ] ;
( function ( global , factory ) {
typeof exports === 'object' && typeof module !== 'undefined' ? module . exports = factory ( ) :
typeof define === 'function' && define . amd ? define ( factory ) :
( global . TinyDatePicker = factory ( ) ) ;
} ( this , ( function ( ) { 'use strict' ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* @ file A generic set of mutation - free date functions .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* now returns the current date without any time values
*
* @ returns { Date }
* /
function now ( ) {
var dt = new Date ( ) ;
dt . setHours ( 0 , 0 , 0 , 0 ) ;
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* dateEq compares two dates
*
* @ param { Date } date1 the first date
* @ param { Date } date2 the second date
* @ returns { boolean }
* /
function datesEq ( date1 , date2 ) {
return ( date1 && date1 . toDateString ( ) ) === ( date2 && date2 . toDateString ( ) ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* shiftDay shifts the specified date by n days
*
* @ param { Date } dt
* @ param { number } n
* @ returns { Date }
* /
function shiftDay ( dt , n ) {
dt = new Date ( dt ) ;
dt . setDate ( dt . getDate ( ) + n ) ;
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* shiftMonth shifts the specified date by a specified number of months
*
* @ param { Date } dt
* @ param { number } n
* @ param { boolean } wrap optional , if true , does not change year
* value , defaults to false
* @ returns { Date }
* /
function shiftMonth ( dt , n , wrap ) {
dt = new Date ( dt ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var dayOfMonth = dt . getDate ( ) ;
var month = dt . getMonth ( ) + n ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dt . setDate ( 1 ) ;
dt . setMonth ( wrap ? ( 12 + month ) % 12 : month ) ;
dt . setDate ( dayOfMonth ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// If dayOfMonth = 31, but the target month only has 30 or 29 or whatever...
// head back to the max of the target month
if ( dt . getDate ( ) < dayOfMonth ) {
dt . setDate ( 0 ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* shiftYear shifts the specified date by n years
*
* @ param { Date } dt
* @ param { number } n
* @ returns { Date }
* /
function shiftYear ( dt , n ) {
dt = new Date ( dt ) ;
dt . setFullYear ( dt . getFullYear ( ) + n ) ;
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* setYear changes the specified date to the specified year
*
* @ param { Date } dt
* @ param { number } year
* /
function setYear ( dt , year ) {
dt = new Date ( dt ) ;
dt . setFullYear ( year ) ;
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* setMonth changes the specified date to the specified month
*
* @ param { Date } dt
* @ param { number } month
* /
function setMonth ( dt , month ) {
return shiftMonth ( dt , month - dt . getMonth ( ) ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* dateOrParse creates a function which , given a date or string , returns a date
*
* @ param { function } parse the function used to parse strings
* @ returns { function }
* /
function dateOrParse ( parse ) {
return function ( dt ) {
return dropTime ( typeof dt === 'string' ? parse ( dt ) : dt ) ;
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* constrainDate returns dt or min / max depending on whether dt is out of bounds ( inclusive )
*
* @ export
* @ param { Date } dt
* @ param { Date } min
* @ param { Date } max
* @ returns { Date }
* /
function constrainDate ( dt , min , max ) {
return ( dt < min ) ? min :
( dt > max ) ? max :
dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function dropTime ( dt ) {
dt = new Date ( dt ) ;
dt . setHours ( 0 , 0 , 0 , 0 ) ;
return dt ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Utility functions for function manipulation .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* bufferFn buffers calls to fn so they only happen every ms milliseconds
*
* @ param { number } ms number of milliseconds
* @ param { function } fn the function to be buffered
* @ returns { function }
* /
function bufferFn ( ms , fn ) {
var timeout = undefined ;
return function ( ) {
clearTimeout ( timeout ) ;
timeout = setTimeout ( fn , ms ) ;
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* noop is a function which does nothing at all .
* /
function noop ( ) { }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* copy properties from object o2 to object o1 .
*
* @ params { Object } o1
* @ params { Object } o2
* @ returns { Object }
* /
function cp ( ) {
var args = arguments ;
var o1 = args [ 0 ] ;
for ( var i = 1 ; i < args . length ; ++ i ) {
var o2 = args [ i ] || { } ;
for ( var key in o2 ) {
o1 [ key ] = o2 [ key ] ;
2018-11-14 17:32:35 +01:00
}
}
2018-11-21 01:42:52 +01:00
return o1 ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Responsible for sanitizing and creating date picker options .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var english = {
days : [ 'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' ] ,
months : [
'January' ,
'February' ,
'March' ,
'April' ,
'May' ,
'June' ,
'July' ,
'August' ,
'September' ,
'October' ,
'November' ,
'December' ,
] ,
today : 'Today' ,
clear : 'Clear' ,
close : 'Close' ,
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* DatePickerOptions constructs a new date picker options object , overriding
* default values with any values specified in opts .
*
* @ param { DatePickerOptions } opts
* @ returns { DatePickerOptions }
* /
function DatePickerOptions ( opts ) {
opts = opts || { } ;
opts = cp ( defaults ( ) , opts ) ;
var parse = dateOrParse ( opts . parse ) ;
opts . lang = cp ( english , opts . lang ) ;
opts . parse = parse ;
opts . inRange = makeInRangeFn ( opts ) ;
opts . min = parse ( opts . min || shiftYear ( now ( ) , - 100 ) ) ;
opts . max = parse ( opts . max || shiftYear ( now ( ) , 100 ) ) ;
opts . hilightedDate = opts . parse ( opts . hilightedDate ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return opts ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function defaults ( ) {
return {
lang : english ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// Possible values: dp-modal, dp-below, dp-permanent
mode : 'dp-modal' ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// The date to hilight initially if the date picker has no
// initial value.
hilightedDate : now ( ) ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
format : function ( dt ) {
return ( dt . getMonth ( ) + 1 ) + '/' + dt . getDate ( ) + '/' + dt . getFullYear ( ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
parse : function ( str ) {
var date = new Date ( str ) ;
return isNaN ( date ) ? now ( ) : date ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dateClass : function ( ) { } ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
inRange : function ( ) {
return true ;
}
} ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function makeInRangeFn ( opts ) {
var inRange = opts . inRange ; // Cache this version, and return a variant
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return function ( dt , dp ) {
return inRange ( dt , dp ) && opts . min <= dt && opts . max >= dt ;
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Helper functions for dealing with dom elements .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var Key = {
left : 37 ,
up : 38 ,
right : 39 ,
down : 40 ,
enter : 13 ,
esc : 27 ,
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* on attaches an event handler to the specified element , and returns an
* off function which can be used to remove the handler .
*
* @ param { string } evt the name of the event to handle
* @ param { HTMLElement } el the element to attach to
* @ param { function } handler the event handler
* @ returns { function } the off function
* /
function on ( evt , el , handler ) {
el . addEventListener ( evt , handler , true ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return function ( ) {
el . removeEventListener ( evt , handler , true ) ;
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var CustomEvent = shimCustomEvent ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function shimCustomEvent ( ) {
var CustomEvent = window . CustomEvent ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( typeof CustomEvent !== 'function' ) {
CustomEvent = function ( event , params ) {
params = params || { bubbles : false , cancelable : false , detail : undefined } ;
var evt = document . createEvent ( 'CustomEvent' ) ;
evt . initCustomEvent ( event , params . bubbles , params . cancelable , params . detail ) ;
return evt ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
CustomEvent . prototype = window . Event . prototype ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return CustomEvent ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Manages the calendar / day - picker view .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var dayPicker = {
onKeyDown : keyDown ,
onClick : {
'dp-day' : selectDay ,
'dp-next' : gotoNextMonth ,
'dp-prev' : gotoPrevMonth ,
'dp-today' : selectToday ,
'dp-clear' : clear ,
'dp-close' : close ,
'dp-cal-month' : showMonthPicker ,
'dp-cal-year' : showYearPicker ,
} ,
render : render
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* view renders the calendar ( day picker ) as an HTML string .
*
* @ param { DatePickerContext } context the date picker being rendered
* @ returns { string }
* /
function render ( dp ) {
var opts = dp . opts ;
var lang = opts . lang ;
var state = dp . state ;
var dayNames = lang . days ;
var dayOffset = opts . dayOffset || 0 ;
var selectedDate = state . selectedDate ;
var hilightedDate = state . hilightedDate ;
var hilightedMonth = hilightedDate . getMonth ( ) ;
var today = now ( ) . getTime ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<div class="dp-cal">' +
'<header class="dp-cal-header">' +
'<button tabindex="-1" type="button" class="dp-prev">Prev</button>' +
'<button tabindex="-1" type="button" class="dp-cal-month">' +
lang . months [ hilightedMonth ] +
'</button>' +
'<button tabindex="-1" type="button" class="dp-cal-year">' +
hilightedDate . getFullYear ( ) +
'</button>' +
'<button tabindex="-1" type="button" class="dp-next">Next</button>' +
'</header>' +
'<div class="dp-days">' +
dayNames . map ( function ( name , i ) {
return (
'<span class="dp-col-header">' + dayNames [ ( i + dayOffset ) % dayNames . length ] + '</span>'
) ;
} ) . join ( '' ) +
mapDays ( hilightedDate , dayOffset , function ( date ) {
var isNotInMonth = date . getMonth ( ) !== hilightedMonth ;
var isDisabled = ! opts . inRange ( date ) ;
var isToday = date . getTime ( ) === today ;
var className = 'dp-day' ;
className += ( isNotInMonth ? ' dp-edge-day' : '' ) ;
className += ( datesEq ( date , hilightedDate ) ? ' dp-current' : '' ) ;
className += ( datesEq ( date , selectedDate ) ? ' dp-selected' : '' ) ;
className += ( isDisabled ? ' dp-day-disabled' : '' ) ;
className += ( isToday ? ' dp-day-today' : '' ) ;
className += ' ' + opts . dateClass ( date , dp ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<button tabindex="-1" type="button" class="' + className + '" data-date="' + date . getTime ( ) + '">' +
date . getDate ( ) +
'</button>'
) ;
} ) +
'</div>' +
'<footer class="dp-cal-footer">' +
'<button tabindex="-1" type="button" class="dp-today">' + lang . today + '</button>' +
'<button tabindex="-1" type="button" class="dp-clear">' + lang . clear + '</button>' +
'<button tabindex="-1" type="button" class="dp-close">' + lang . close + '</button>' +
'</footer>' +
'</div>'
) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* keyDown handles the key down event for the day - picker
*
* @ param { Event } e
* @ param { DatePickerContext } dp
* /
function keyDown ( e , dp ) {
var key = e . keyCode ;
var shiftBy =
( key === Key . left ) ? - 1 :
( key === Key . right ) ? 1 :
( key === Key . up ) ? - 7 :
( key === Key . down ) ? 7 :
0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( key === Key . esc ) {
dp . close ( ) ;
} else if ( shiftBy ) {
e . preventDefault ( ) ;
dp . setState ( {
hilightedDate : shiftDay ( dp . state . hilightedDate , shiftBy )
} ) ;
2018-11-14 17:32:35 +01:00
}
}
2018-11-21 01:42:52 +01:00
function selectToday ( e , dp ) {
dp . setState ( {
selectedDate : now ( ) ,
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function clear ( e , dp ) {
dp . setState ( {
selectedDate : null ,
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function close ( e , dp ) {
dp . close ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function showMonthPicker ( e , dp ) {
dp . setState ( {
view : 'month'
2018-11-14 17:32:35 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
function showYearPicker ( e , dp ) {
dp . setState ( {
view : 'year'
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function gotoNextMonth ( e , dp ) {
var hilightedDate = dp . state . hilightedDate ;
dp . setState ( {
hilightedDate : shiftMonth ( hilightedDate , 1 )
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function gotoPrevMonth ( e , dp ) {
var hilightedDate = dp . state . hilightedDate ;
dp . setState ( {
hilightedDate : shiftMonth ( hilightedDate , - 1 )
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function selectDay ( e , dp ) {
dp . setState ( {
selectedDate : new Date ( parseInt ( e . target . getAttribute ( 'data-date' ) ) ) ,
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function mapDays ( currentDate , dayOffset , fn ) {
var result = '' ;
var iter = new Date ( currentDate ) ;
iter . setDate ( 1 ) ;
iter . setDate ( 1 - iter . getDay ( ) + dayOffset ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// If we are showing monday as the 1st of the week,
// and the monday is the 2nd of the month, the sunday won't
// show, so we need to shift backwards
if ( dayOffset && iter . getDate ( ) === dayOffset + 1 ) {
iter . setDate ( dayOffset - 6 ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
// We are going to have 6 weeks always displayed to keep a consistent
// calendar size
for ( var day = 0 ; day < ( 6 * 7 ) ; ++ day ) {
result += fn ( iter ) ;
iter . setDate ( iter . getDate ( ) + 1 ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return result ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Manages the month - picker view .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var monthPicker = {
onKeyDown : keyDown$1 ,
onClick : {
'dp-month' : onChooseMonth
} ,
render : render$1
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function onChooseMonth ( e , dp ) {
dp . setState ( {
hilightedDate : setMonth ( dp . state . hilightedDate , parseInt ( e . target . getAttribute ( 'data-month' ) ) ) ,
view : 'day' ,
2018-11-14 17:32:35 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* render renders the month picker as an HTML string
*
* @ param { DatePickerContext } dp the date picker context
* @ returns { string }
* /
function render$1 ( dp ) {
var opts = dp . opts ;
var lang = opts . lang ;
var months = lang . months ;
var currentDate = dp . state . hilightedDate ;
var currentMonth = currentDate . getMonth ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<div class="dp-months">' +
months . map ( function ( month , i ) {
var className = 'dp-month' ;
className += ( currentMonth === i ? ' dp-current' : '' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<button tabindex="-1" type="button" class="' + className + '" data-month="' + i + '">' +
month +
'</button>'
) ;
} ) . join ( '' ) +
'</div>'
) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* keyDown handles keydown events that occur in the month picker
*
* @ param { Event } e
* @ param { DatePickerContext } dp
* /
function keyDown$1 ( e , dp ) {
var key = e . keyCode ;
var shiftBy =
( key === Key . left ) ? - 1 :
( key === Key . right ) ? 1 :
( key === Key . up ) ? - 3 :
( key === Key . down ) ? 3 :
0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( key === Key . esc ) {
dp . setState ( {
view : 'day' ,
2018-11-14 17:32:35 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} else if ( shiftBy ) {
e . preventDefault ( ) ;
dp . setState ( {
hilightedDate : shiftMonth ( dp . state . hilightedDate , shiftBy , true )
} ) ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* @ file Manages the year - picker view .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var yearPicker = {
render : render$2 ,
onKeyDown : keyDown$2 ,
onClick : {
'dp-year' : onChooseYear
} ,
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* view renders the year picker as an HTML string .
*
* @ param { DatePickerContext } dp the date picker context
* @ returns { string }
* /
function render$2 ( dp ) {
var state = dp . state ;
var currentYear = state . hilightedDate . getFullYear ( ) ;
var selectedYear = state . selectedDate . getFullYear ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<div class="dp-years">' +
mapYears ( dp , function ( year ) {
var className = 'dp-year' ;
className += ( year === currentYear ? ' dp-current' : '' ) ;
className += ( year === selectedYear ? ' dp-selected' : '' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return (
'<button tabindex="-1" type="button" class="' + className + '" data-year="' + year + '">' +
year +
'</button>'
) ;
} ) +
'</div>'
) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function onChooseYear ( e , dp ) {
dp . setState ( {
hilightedDate : setYear ( dp . state . hilightedDate , parseInt ( e . target . getAttribute ( 'data-year' ) ) ) ,
view : 'day' ,
} ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function keyDown$2 ( e , dp ) {
var key = e . keyCode ;
var opts = dp . opts ;
var shiftBy =
( key === Key . left || key === Key . up ) ? 1 :
( key === Key . right || key === Key . down ) ? - 1 :
0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( key === Key . esc ) {
dp . setState ( {
view : 'day' ,
} ) ;
} else if ( shiftBy ) {
e . preventDefault ( ) ;
var shiftedYear = shiftYear ( dp . state . hilightedDate , shiftBy ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . setState ( {
hilightedDate : constrainDate ( shiftedYear , opts . min , opts . max ) ,
2018-11-14 17:32:35 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function mapYears ( dp , fn ) {
var result = '' ;
var max = dp . opts . max . getFullYear ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = max ; i >= dp . opts . min . getFullYear ( ) ; -- i ) {
result += fn ( i ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return result ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* @ file Defines the base date picker behavior , overridden by various modes .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var views = {
day : dayPicker ,
year : yearPicker ,
month : monthPicker
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function BaseMode ( input , emit , opts ) {
var detatchInputEvents ; // A function that detaches all events from the input
var closing = false ; // A hack to prevent calendar from re-opening when closing.
var selectedDate ; // The currently selected date
var dp = {
// The root DOM element for the date picker, initialized on first open.
el : undefined ,
opts : opts ,
shouldFocusOnBlur : true ,
shouldFocusOnRender : true ,
state : initialState ( ) ,
adjustPosition : noop ,
containerHTML : '<div class="dp"></div>' ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
attachToDom : function ( ) {
document . body . appendChild ( dp . el ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
updateInput : function ( selectedDate ) {
var e = new CustomEvent ( 'change' , { bubbles : true } ) ;
e . simulated = true ;
input . value = selectedDate ? opts . format ( selectedDate ) : '' ;
input . dispatchEvent ( e ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
computeSelectedDate : function ( ) {
return opts . parse ( input . value ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
currentView : function ( ) {
return views [ dp . state . view ] ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
open : function ( ) {
if ( closing ) {
return ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! dp . el ) {
dp . el = createContainerElement ( opts , dp . containerHTML ) ;
attachContainerEvents ( dp ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
selectedDate = constrainDate ( dp . computeSelectedDate ( ) , opts . min , opts . max ) ;
dp . state . hilightedDate = selectedDate || opts . hilightedDate ;
dp . state . view = 'day' ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . attachToDom ( ) ;
dp . render ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
emit ( 'open' ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
isVisible : function ( ) {
return ! ! dp . el && ! ! dp . el . parentNode ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
hasFocus : function ( ) {
var focused = document . activeElement ;
return dp . el &&
dp . el . contains ( focused ) &&
focused . className . indexOf ( 'dp-focuser' ) < 0 ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
shouldHide : function ( ) {
return dp . isVisible ( ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
close : function ( becauseOfBlur ) {
var el = dp . el ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! dp . isVisible ( ) ) {
return ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( el ) {
var parent = el . parentNode ;
parent && parent . removeChild ( el ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
closing = true ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( becauseOfBlur && dp . shouldFocusOnBlur ) {
focusInput ( input ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// When we close, the input often gains refocus, which
// can then launch the date picker again, so we buffer
// a bit and don't show the date picker within N ms of closing
setTimeout ( function ( ) {
closing = false ;
} , 100 ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
emit ( 'close' ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
destroy : function ( ) {
dp . close ( ) ;
detatchInputEvents ( ) ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
render : function ( ) {
if ( ! dp . el ) {
return ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var hadFocus = dp . hasFocus ( ) ;
var html = dp . currentView ( ) . render ( dp ) ;
html && ( dp . el . firstChild . innerHTML = html ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . adjustPosition ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( hadFocus || dp . shouldFocusOnRender ) {
focusCurrent ( dp ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// Conceptually similar to setState in React, updates
// the view state and re-renders.
setState : function ( state ) {
for ( var key in state ) {
dp . state [ key ] = state [ key ] ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
emit ( 'statechange' ) ;
dp . render ( ) ;
} ,
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
detatchInputEvents = attachInputEvents ( input , dp ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// Builds the initial view state
// selectedDate is a special case and causes changes to hilightedDate
// hilightedDate is set on open, so remains undefined initially
// view is the current view (day, month, year)
function initialState ( ) {
return {
get selectedDate ( ) {
return selectedDate ;
} ,
set selectedDate ( dt ) {
if ( dt && ! opts . inRange ( dt ) ) {
return ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( dt ) {
selectedDate = new Date ( dt ) ;
dp . state . hilightedDate = selectedDate ;
} else {
selectedDate = dt ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . updateInput ( selectedDate ) ;
emit ( 'select' ) ;
dp . close ( ) ;
} ,
view : 'day' ,
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return dp ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function createContainerElement ( opts , containerHTML ) {
var el = document . createElement ( 'div' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
el . className = opts . mode ;
el . innerHTML = containerHTML ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return el ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function attachInputEvents ( input , dp ) {
var bufferShow = bufferFn ( 5 , function ( ) {
if ( dp . shouldHide ( ) ) {
dp . close ( ) ;
} else {
dp . open ( ) ;
2018-11-14 17:32:35 +01:00
}
} ) ;
2018-11-21 01:42:52 +01:00
var off = [
on ( 'blur' , input , bufferFn ( 150 , function ( ) {
if ( ! dp . hasFocus ( ) ) {
dp . close ( true ) ;
}
} ) ) ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
on ( 'mousedown' , input , function ( ) {
if ( input === document . activeElement ) {
bufferShow ( ) ;
}
} ) ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
on ( 'focus' , input , bufferShow ) ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
on ( 'input' , input , function ( e ) {
var date = dp . opts . parse ( e . target . value ) ;
isNaN ( date ) || dp . setState ( {
hilightedDate : date
} ) ;
} ) ,
] ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// Unregister all events that were registered above.
return function ( ) {
off . forEach ( function ( f ) {
f ( ) ;
} ) ;
2018-11-14 17:32:35 +01:00
} ;
}
2018-11-21 01:42:52 +01:00
function focusCurrent ( dp ) {
var current = dp . el . querySelector ( '.dp-current' ) ;
return current && current . focus ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function attachContainerEvents ( dp ) {
var el = dp . el ;
var calEl = el . querySelector ( '.dp' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// Hack to get iOS to show active CSS states
el . ontouchstart = noop ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function onClick ( e ) {
e . target . className . split ( ' ' ) . forEach ( function ( evt ) {
var handler = dp . currentView ( ) . onClick [ evt ] ;
handler && handler ( e , dp ) ;
2018-11-14 17:32:35 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
// The calender fires a blur event *every* time we redraw
// this means we need to buffer the blur event to see if
// it still has no focus after redrawing, and only then
// do we return focus to the input. A possible other approach
// would be to set context.redrawing = true on redraw and
// set it to false in the blur event.
on ( 'blur' , calEl , bufferFn ( 150 , function ( ) {
if ( ! dp . hasFocus ( ) ) {
dp . close ( true ) ;
}
} ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
on ( 'keydown' , el , function ( e ) {
if ( e . keyCode === Key . enter ) {
onClick ( e ) ;
2018-11-14 17:32:35 +01:00
} else {
2018-11-21 01:42:52 +01:00
dp . currentView ( ) . onKeyDown ( e , dp ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// If the user clicks in non-focusable space, but
// still within the date picker, we don't want to
// hide, so we need to hack some things...
on ( 'mousedown' , calEl , function ( e ) {
e . target . focus && e . target . focus ( ) ; // IE hack
if ( document . activeElement !== e . target ) {
e . preventDefault ( ) ;
focusCurrent ( dp ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
on ( 'click' , el , onClick ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function focusInput ( input ) {
// When the modal closes, we need to focus the original input so the
// user can continue tabbing from where they left off.
input . focus ( ) ;
// iOS zonks out if we don't blur the input, so...
if ( /iPad|iPhone|iPod/ . test ( navigator . userAgent ) && ! window . MSStream ) {
input . blur ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* @ file Defines the modal date picker behavior .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function ModalMode ( input , emit , opts ) {
var dp = BaseMode ( input , emit , opts ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
// In modal mode, users really shouldn't be able to type in
// the input, as all input is done via the calendar.
input . readonly = true ;
// In modal mode, we need to know when the user has tabbed
// off the end of the calendar, and set focus to the original
// input. To do this, we add a special element to the DOM.
// When the user tabs off the bottom of the calendar, they
// will tab onto this element.
dp . containerHTML += '<a href="#" class="dp-focuser">.</a>' ;
return dp ;
}
/ * *
* @ file Defines the dropdown date picker behavior .
* /
function DropdownMode ( input , emit , opts ) {
var dp = BaseMode ( input , emit , opts ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . shouldFocusOnBlur = false ;
Object . defineProperty ( dp , 'shouldFocusOnRender' , {
get : function ( ) {
return input !== document . activeElement ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . adjustPosition = function ( ) {
autoPosition ( input , dp ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return dp ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function autoPosition ( input , dp ) {
var inputPos = input . getBoundingClientRect ( ) ;
var win = window ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
adjustCalY ( dp , inputPos , win ) ;
adjustCalX ( dp , inputPos , win ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . el . style . visibility = '' ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function adjustCalX ( dp , inputPos , win ) {
var cal = dp . el ;
var scrollLeft = win . pageXOffset ;
var inputLeft = inputPos . left + scrollLeft ;
var maxRight = win . innerWidth + scrollLeft ;
var offsetWidth = cal . offsetWidth ;
var calRight = inputLeft + offsetWidth ;
var shiftedLeft = maxRight - offsetWidth ;
var left = calRight > maxRight && shiftedLeft > 0 ? shiftedLeft : inputLeft ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
cal . style . left = left + 'px' ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function adjustCalY ( dp , inputPos , win ) {
var cal = dp . el ;
var scrollTop = win . pageYOffset ;
var inputTop = scrollTop + inputPos . top ;
var calHeight = cal . offsetHeight ;
var belowTop = inputTop + inputPos . height + 8 ;
var aboveTop = inputTop - calHeight - 8 ;
var isAbove = ( aboveTop > 0 && belowTop + calHeight > scrollTop + win . innerHeight ) ;
var top = isAbove ? aboveTop : belowTop ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( cal . classList ) {
cal . classList . toggle ( 'dp-is-above' , isAbove ) ;
cal . classList . toggle ( 'dp-is-below' , ! isAbove ) ;
}
cal . style . top = top + 'px' ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* @ file Defines the permanent date picker behavior .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function PermanentMode ( root , emit , opts ) {
var dp = BaseMode ( root , emit , opts ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . close = noop ;
dp . destroy = noop ;
dp . updateInput = noop ;
dp . shouldFocusOnRender = opts . shouldFocusOnRender ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . computeSelectedDate = function ( ) {
return opts . hilightedDate ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . attachToDom = function ( ) {
root . appendChild ( dp . el ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
dp . open ( ) ;
return dp ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Defines the various date picker modes ( modal , dropdown , permanent )
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function Mode ( input , emit , opts ) {
input = input && input . tagName ? input : document . querySelector ( input ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( opts . mode === 'dp-modal' ) {
return ModalMode ( input , emit , opts ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( opts . mode === 'dp-below' ) {
return DropdownMode ( input , emit , opts ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( opts . mode === 'dp-permanent' ) {
return PermanentMode ( input , emit , opts ) ;
}
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file Defines simple event emitter behavior .
* /
/ * *
* Emitter constructs a new emitter object which has on / off methods .
*
* @ returns { EventEmitter }
* /
function Emitter ( ) {
var handlers = { } ;
function onOne ( name , handler ) {
( handlers [ name ] = ( handlers [ name ] || [ ] ) ) . push ( handler ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
function onMany ( fns ) {
for ( var name in fns ) {
onOne ( name , fns [ name ] ) ;
}
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return {
on : function ( name , handler ) {
if ( handler ) {
onOne ( name , handler ) ;
} else {
onMany ( name ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return this ;
} ,
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
emit : function ( name , arg ) {
( handlers [ name ] || [ ] ) . forEach ( function ( handler ) {
handler ( name , arg ) ;
2018-11-14 17:32:35 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
} ,
off : function ( name , handler ) {
if ( ! name ) {
handlers = { } ;
} else if ( ! handler ) {
handlers [ name ] = [ ] ;
} else {
handlers [ name ] = ( handlers [ name ] || [ ] ) . filter ( function ( h ) {
return h !== handler ;
} ) ;
}
return this ;
}
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
/ * *
* @ file The root date picker file , defines public exports for the library .
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* The date picker language configuration
* @ typedef { Object } LangOptions
* @ property { Array . < string > } [ days ] - Days of the week
* @ property { Array . < string > } [ months ] - Months of the year
* @ property { string } today - The label for the 'today' button
* @ property { string } close - The label for the 'close' button
* @ property { string } clear - The label for the 'clear' button
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* The configuration options for a date picker .
*
* @ typedef { Object } DatePickerOptions
* @ property { LangOptions } [ lang ] - Configures the label text , defaults to English
* @ property { ( 'dp-modal' | 'dp-below' | 'dp-permanent' ) } [ mode ] - The date picker mode , defaults to 'dp-modal'
* @ property { ( string | Date ) } [ hilightedDate ] - The date to hilight if no date is selected
* @ property { function ( string | Date ) : Date } [ parse ] - Parses a date , the complement of the "format" function
* @ property { function ( Date ) : string } [ format ] - Formats a date for displaying to user
* @ property { function ( Date ) : string } [ dateClass ] - Associates a custom CSS class with a date
* @ property { function ( Date ) : boolean } [ inRange ] - Indicates whether or not a date is selectable
* @ property { ( string | Date ) } [ min ] - The minimum selectable date ( inclusive , default 100 years ago )
* @ property { ( string | Date ) } [ max ] - The maximum selectable date ( inclusive , default 100 years from now )
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* The state values for the date picker
*
* @ typedef { Object } DatePickerState
* @ property { string } view - The current view 'day' | 'month' | 'year'
* @ property { Date } selectedDate - The date which has been selected by the user
* @ property { Date } hilightedDate - The date which is currently hilighted / active
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* An instance of TinyDatePicker
*
* @ typedef { Object } DatePicker
* @ property { DatePickerState } state - The values currently displayed .
* @ property { function } on - Adds an event handler
* @ property { function } off - Removes an event handler
* @ property { function } setState - Changes the current state of the date picker
* @ property { function } open - Opens the date picker
* @ property { function } close - Closes the date picker
* @ property { function } destroy - Destroys the date picker ( removing all handlers from the input , too )
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* TinyDatePicker constructs a new date picker for the specified input
*
* @ param { HTMLElement | string } input The input or CSS selector associated with the datepicker
* @ param { DatePickerOptions } opts The options for initializing the date picker
* @ returns { DatePicker }
* /
function TinyDatePicker ( input , opts ) {
var emitter = Emitter ( ) ;
var options = DatePickerOptions ( opts ) ;
var mode = Mode ( input , emit , options ) ;
var me = {
get state ( ) {
return mode . state ;
} ,
on : emitter . on ,
off : emitter . off ,
setState : mode . setState ,
open : mode . open ,
close : mode . close ,
destroy : mode . destroy ,
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function emit ( evt ) {
emitter . emit ( evt , me ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return me ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return TinyDatePicker ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} ) ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} , { } ] , "../../../../node_modules/caret-pos/lib/esm2015/main.js" : [ function ( require , module , exports ) {
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . getOffset = exports . offset = exports . position = void 0 ;
var attributes = [ 'borderBottomWidth' , 'borderLeftWidth' , 'borderRightWidth' , 'borderTopStyle' , 'borderRightStyle' , 'borderBottomStyle' , 'borderLeftStyle' , 'borderTopWidth' , 'boxSizing' , 'fontFamily' , 'fontSize' , 'fontWeight' , 'height' , 'letterSpacing' , 'lineHeight' , 'marginBottom' , 'marginLeft' , 'marginRight' , 'marginTop' , 'outlineWidth' , 'overflow' , 'overflowX' , 'overflowY' , 'paddingBottom' , 'paddingLeft' , 'paddingRight' , 'paddingTop' , 'textAlign' , 'textOverflow' , 'textTransform' , 'whiteSpace' , 'wordBreak' , 'wordWrap' ] ;
/ * *
* Create a mirror
*
* @ param { Element } element The element
* @ param { string } html The html
*
* @ return { object } The mirror object
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var createMirror = function createMirror ( element , html ) {
/ * *
* The mirror element
* /
var mirror = document . createElement ( 'div' ) ;
/ * *
* Create the CSS for the mirror object
*
* @ return { object } The style object
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var mirrorCss = function mirrorCss ( ) {
var css = {
position : 'absolute' ,
left : - 9999 ,
top : 0 ,
zIndex : - 2000
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( element . tagName === 'TEXTAREA' ) {
attributes . push ( 'width' ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
attributes . forEach ( function ( attr ) {
css [ attr ] = getComputedStyle ( element ) [ attr ] ;
2018-11-14 17:32:35 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
return css ;
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
/ * *
* Initialize the mirror
*
* @ param { string } html The html
*
* @ return { void }
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var initialize = function initialize ( html ) {
var styles = mirrorCss ( ) ;
Object . keys ( styles ) . forEach ( function ( key ) {
mirror . style [ key ] = styles [ key ] ;
} ) ;
mirror . innerHTML = html ;
element . parentNode . insertBefore ( mirror , element . nextSibling ) ;
} ;
/ * *
* Get the rect
*
* @ return { Rect } The bounding rect
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var rect = function rect ( ) {
var marker = mirror . ownerDocument . getElementById ( 'caret-position-marker' ) ;
var boundingRect = {
left : marker . offsetLeft ,
top : marker . offsetTop ,
height : marker . offsetHeight
} ;
mirror . parentNode . removeChild ( mirror ) ;
return boundingRect ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
initialize ( html ) ;
return {
rect : rect
} ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) {
return typeof obj ;
} : function ( obj ) {
return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ;
} ;
/ * *
* Check if a DOM Element is content editable
*
* @ param { Element } element The DOM element
*
* @ return { bool } If it is content editable
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var isContentEditable = function isContentEditable ( element ) {
return ! ! ( element . contentEditable && element . contentEditable === 'true' ) ;
} ;
/ * *
* Get the context from settings passed in
*
* @ param { object } settings The settings object
*
* @ return { object } window and document
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getContext = function getContext ( ) {
var settings = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
var customPos = settings . customPos ,
iframe = settings . iframe ,
noShadowCaret = settings . noShadowCaret ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( iframe ) {
return {
iframe : iframe ,
window : iframe . contentWindow ,
document : iframe . contentDocument || iframe . contentWindow . document ,
noShadowCaret : noShadowCaret ,
customPos : customPos
} ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return {
window : window ,
document : document ,
noShadowCaret : noShadowCaret ,
customPos : customPos
} ;
} ;
/ * *
* Get the offset of an element
*
* @ param { Element } element The DOM element
* @ param { object } ctx The context
*
* @ return { object } top and left
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getOffset = function getOffset ( element , ctx ) {
var win = ctx && ctx . window || window ;
var doc = ctx && ctx . document || document ;
var rect = element . getBoundingClientRect ( ) ;
var docEl = doc . documentElement ;
var scrollLeft = win . pageXOffset || docEl . scrollLeft ;
var scrollTop = win . pageYOffset || docEl . scrollTop ;
return {
top : rect . top + scrollTop ,
left : rect . left + scrollLeft
} ;
} ;
/ * *
* Check if a value is an object
*
* @ param { any } value The value to check
*
* @ return { bool } If it is an object
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . getOffset = getOffset ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var isObject = function isObject ( value ) {
return ( typeof value === 'undefined' ? 'undefined' : _typeof ( value ) ) === 'object' && value !== null ;
} ;
/ * *
* Create a Input caret object .
*
* @ param { Element } element The element
* @ param { Object } ctx The context
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var createInputCaret = function createInputCaret ( element , ctx ) {
/ * *
* Get the current position
*
* @ returns { int } The caret position
* /
var getPos = function getPos ( ) {
return element . selectionStart ;
} ;
/ * *
* Set the position
*
* @ param { int } pos The position
*
* @ return { Element } The element
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var setPos = function setPos ( pos ) {
element . setSelectionRange ( pos , pos ) ;
return element ;
} ;
/ * *
* The offset
*
* @ param { int } pos The position
*
* @ return { object } The offset
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getOffset$$1 = function getOffset$$1 ( pos ) {
var rect = getOffset ( element ) ;
var position = getPosition ( pos ) ;
2018-11-14 17:32:35 +01:00
return {
2018-11-21 01:42:52 +01:00
top : rect . top + position . top + ctx . document . body . scrollTop ,
left : rect . left + position . left + ctx . document . body . scrollLeft ,
height : position . height
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
} ;
/ * *
* Get the current position
*
* @ param { int } pos The position
*
* @ return { object } The position
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getPosition = function getPosition ( pos ) {
var format = function format ( val ) {
var value = val . replace ( /<|>|`|"|&/g , '?' ) . replace ( /\r\n|\r|\n/g , '<br/>' ) ;
return value ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ctx . customPos || ctx . customPos === 0 ) {
pos = ctx . customPos ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var position = pos === undefined ? getPos ( ) : pos ;
var startRange = element . value . slice ( 0 , position ) ;
var endRange = element . value . slice ( position ) ;
var html = '<span style="position: relative; display: inline;">' + format ( startRange ) + '</span>' ;
html += '<span id="caret-position-marker" style="position: relative; display: inline;">|</span>' ;
html += '<span style="position: relative; display: inline;">' + format ( endRange ) + '</span>' ;
var mirror = createMirror ( element , html ) ;
var rect = mirror . rect ( ) ;
rect . pos = getPos ( ) ;
return rect ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return {
getPos : getPos ,
setPos : setPos ,
getOffset : getOffset$$1 ,
getPosition : getPosition
} ;
} ;
/ * *
* Create an Editable Caret
* @ param { Element } element The editable element
* @ param { object | null } ctx The context
*
* @ return { EditableCaret }
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var createEditableCaret = function createEditableCaret ( element , ctx ) {
/ * *
* Set the caret position
*
* @ param { int } pos The position to se
*
* @ return { Element } The element
* /
var setPos = function setPos ( pos ) {
var sel = ctx . window . getSelection ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( sel ) {
var offset = 0 ;
var found = false ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var find = function find ( position , parent ) {
for ( var i = 0 ; i < parent . childNodes . length ; i ++ ) {
var node = parent . childNodes [ i ] ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( found ) {
break ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( node . nodeType === 3 ) {
if ( offset + node . length >= position ) {
found = true ;
var range = ctx . document . createRange ( ) ;
range . setStart ( node , position - offset ) ;
sel . removeAllRanges ( ) ;
sel . addRange ( range ) ;
break ;
} else {
offset += node . length ;
}
} else {
find ( pos , node ) ;
}
}
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
find ( pos , element ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return element ;
} ;
/ * *
* Get the offset
*
* @ return { object } The offset
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getOffset = function getOffset ( ) {
var range = getRange ( ) ;
var offset = {
height : 0 ,
left : 0 ,
right : 0
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ! range ) {
return offset ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var hasCustomPos = ctx . customPos || ctx . customPos === 0 ; // endContainer in Firefox would be the element at the start of
// the line
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( range . endOffset - 1 > 0 && range . endContainer !== element || hasCustomPos ) {
var clonedRange = range . cloneRange ( ) ;
var fixedPosition = hasCustomPos ? ctx . customPos : range . endOffset ;
clonedRange . setStart ( range . endContainer , fixedPosition - 1 < 0 ? 0 : fixedPosition - 1 ) ;
clonedRange . setEnd ( range . endContainer , fixedPosition ) ;
var rect = clonedRange . getBoundingClientRect ( ) ;
offset = {
height : rect . height ,
left : rect . left + rect . width ,
top : rect . top
} ;
clonedRange . detach ( ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( ( ! offset || offset && offset . height === 0 ) && ! ctx . noShadowCaret ) {
var _clonedRange = range . cloneRange ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var shadowCaret = ctx . document . createTextNode ( '|' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_clonedRange . insertNode ( shadowCaret ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_clonedRange . selectNode ( shadowCaret ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _rect = _clonedRange . getBoundingClientRect ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
offset = {
height : _rect . height ,
left : _rect . left ,
top : _rect . top
} ;
shadowCaret . parentNode . removeChild ( shadowCaret ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_clonedRange . detach ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
if ( offset ) {
var doc = ctx . document . documentElement ;
offset . top += ctx . window . pageYOffset - ( doc . clientTop || 0 ) ;
offset . left += ctx . window . pageXOffset - ( doc . clientLeft || 0 ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return offset ;
} ;
/ * *
* Get the position
*
* @ return { object } The position
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getPosition = function getPosition ( ) {
var offset = getOffset ( ) ;
var pos = getPos ( ) ;
var rect = element . getBoundingClientRect ( ) ;
var inputOffset = {
top : rect . top + ctx . document . body . scrollTop ,
left : rect . left + ctx . document . body . scrollLeft
2018-11-14 17:32:35 +01:00
} ;
2018-11-21 01:42:52 +01:00
offset . left -= inputOffset . left ;
offset . top -= inputOffset . top ;
offset . pos = pos ;
return offset ;
} ;
/ * *
* Get the range
*
* @ return { Range | null }
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getRange = function getRange ( ) {
if ( ! ctx . window . getSelection ) {
return ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var sel = ctx . window . getSelection ( ) ;
return sel . rangeCount > 0 ? sel . getRangeAt ( 0 ) : null ;
} ;
/ * *
* Get the caret position
*
* @ return { int } The position
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var getPos = function getPos ( ) {
var range = getRange ( ) ;
var clonedRange = range . cloneRange ( ) ;
clonedRange . selectNodeContents ( element ) ;
clonedRange . setEnd ( range . endContainer , range . endOffset ) ;
var pos = clonedRange . toString ( ) . length ;
clonedRange . detach ( ) ;
return pos ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return {
getPos : getPos ,
setPos : setPos ,
getPosition : getPosition ,
getOffset : getOffset ,
getRange : getRange
} ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var createCaret = function createCaret ( element , ctx ) {
if ( isContentEditable ( element ) ) {
return createEditableCaret ( element , ctx ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return createInputCaret ( element , ctx ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var position = function position ( element , value ) {
var settings = arguments . length > 2 && arguments [ 2 ] !== undefined ? arguments [ 2 ] : { } ;
var options = settings ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( isObject ( value ) ) {
options = value ;
value = null ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var ctx = getContext ( options ) ;
var caret = createCaret ( element , ctx ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( value || value === 0 ) {
return caret . setPos ( value ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
return caret . getPosition ( ) ;
} ;
/ * *
*
* @ param { Element } element The DOM element
* @ param { number | undefined } value The value to set
* @ param { object } settings Any settings for context
* /
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . position = position ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var offset = function offset ( element , value ) {
var settings = arguments . length > 2 && arguments [ 2 ] !== undefined ? arguments [ 2 ] : { } ;
var options = settings ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( isObject ( value ) ) {
options = value ;
value = null ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var ctx = getContext ( options ) ;
var caret = createCaret ( element , ctx ) ;
return caret . getOffset ( value ) ;
} ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . offset = offset ;
} , { } ] , "../../../../brain/tools/ui/TextEditor.js" : [ function ( require , module , exports ) {
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var DataEvent = _interopRequireWildcard ( require ( "../events/DataEvent" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _DateUtils = _interopRequireDefault ( require ( "../utilities/DateUtils" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _caretPos = require ( "caret-pos" ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _EventEmitter2 = _interopRequireDefault ( require ( "../events/EventEmitter" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var EditorEvent = _interopRequireWildcard ( require ( "../events/EditorEvent" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _typeof ( obj ) { if ( typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ) { _typeof = function _typeof ( obj ) { return typeof obj ; } ; } else { _typeof = function _typeof ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ; } return _typeof ( obj ) ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _possibleConstructorReturn ( self , call ) { if ( call && ( _typeof ( call ) === "object" || typeof call === "function" ) ) { return call ; } return _assertThisInitialized ( self ) ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _getPrototypeOf ( o ) { _getPrototypeOf = Object . setPrototypeOf ? Object . getPrototypeOf : function _getPrototypeOf ( o ) { return o . _ _proto _ _ || Object . getPrototypeOf ( o ) ; } ; return _getPrototypeOf ( o ) ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _inherits ( subClass , superClass ) { if ( typeof superClass !== "function" && superClass !== null ) { throw new TypeError ( "Super expression must either be null or a function" ) ; } subClass . prototype = Object . create ( superClass && superClass . prototype , { constructor : { value : subClass , writable : true , configurable : true } } ) ; if ( superClass ) _setPrototypeOf ( subClass , superClass ) ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _setPrototypeOf ( o , p ) { _setPrototypeOf = Object . setPrototypeOf || function _setPrototypeOf ( o , p ) { o . _ _proto _ _ = p ; return o ; } ; return _setPrototypeOf ( o , p ) ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _assertThisInitialized ( self ) { if ( self === void 0 ) { throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ; } return self ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var TextEditor =
/*#__PURE__*/
function ( _EventEmitter ) {
_inherits ( TextEditor , _EventEmitter ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
/ * *
* Text Editor UI Component
* @ constructor
* @ param { object } textEditor - Text area that will edit text
* @ param { number } scrollLimit - YPos where editor position will become fixed
* /
//--------------------------
// constructor
//--------------------------
function TextEditor ( textEditor , scrollLimit ) {
var _this ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_classCallCheck ( this , TextEditor ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_this = _possibleConstructorReturn ( this , _getPrototypeOf ( TextEditor ) . call ( this ) ) ;
hljs . initHighlightingOnLoad ( ) ;
_this . dateUtils = new _DateUtils . default ( ) ;
_this . textEditor = textEditor ;
_this . fixLimit = scrollLimit ;
_this . caretPos = null ;
_this . url = '' ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var self = _assertThisInitialized ( _assertThisInitialized ( _this ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_this . setInputs ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
window . addEventListener ( "scroll" , function ( f ) {
var fixLimit = _this . fixLimit ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( window . pageYOffset >= fixLimit ) {
document . getElementById ( 'edit-control' ) . style . position = "fixed" ;
} else {
document . getElementById ( 'edit-control' ) . style . position = "relative" ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_this . refresh ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return _this ;
} //--------------------------
// methods
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_createClass ( TextEditor , [ {
key : "setInputs" ,
value : function setInputs ( ) {
var _this2 = this ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var self = this ;
var editorButtons = document . querySelectorAll ( '.editor-button' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , length = editorButtons . length ; i < length ; i ++ ) {
editorButtons [ i ] . addEventListener ( 'click' , function ( e ) {
return _this2 . handleEditorOption ( e ) ;
} , false ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
this . textEditor . addEventListener ( 'input' , function ( f ) {
if ( f . inputType == "insertParagraph" ) {
var caret = ( 0 , _caretPos . position ) ( self . textEditor ) . pos + 1 ;
var spiffed = hljs . highlight ( 'markdown' , self . textEditor . innerText ) . value ;
var temp = document . createElement ( "div" ) ;
temp . innerText = spiffed ;
self . textEditor . innerHTML = temp . innerText ;
( 0 , _caretPos . position ) ( self . textEditor , caret ) ;
} else {
self . refresh ( ) ;
}
2018-11-14 17:32:35 +01:00
} ) ;
}
2018-11-21 01:42:52 +01:00
} , {
key : "refresh" ,
value : function refresh ( ) {
var caret = ( 0 , _caretPos . position ) ( this . textEditor ) . pos ;
var spiffed = hljs . highlight ( 'markdown' , this . textEditor . innerText ) . value ;
2018-12-06 22:49:49 +01:00
spiffed = spiffed . replace ( new RegExp ( '\r?\n' , 'g' ) , '<br>' ) ;
2018-11-21 01:42:52 +01:00
var temp = document . createElement ( "div" ) ;
temp . innerText = spiffed ;
this . textEditor . innerHTML = temp . innerText ;
( 0 , _caretPos . position ) ( this . textEditor , caret ) ;
2018-12-06 22:49:49 +01:00
this . textEditor . style . maxWidth = '900px' ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} , {
key : "notify" ,
value : function notify ( type , data ) {
switch ( type ) {
case DataEvent . POST _UPDATED :
document . getElementById ( 'submit-update' ) . classList . add ( 'icon-hide' ) ;
document . getElementById ( 'submit-good' ) . classList . remove ( 'icon-hide' ) ;
document . getElementById ( 'edit-update' ) . classList . remove ( 'submit-start' ) ;
document . getElementById ( 'edit-update' ) . classList . add ( 'submit-cool' ) ;
setTimeout ( function ( f ) {
document . getElementById ( 'submit-update' ) . classList . remove ( 'icon-hide' ) ;
document . getElementById ( 'submit-good' ) . classList . add ( 'icon-hide' ) ;
document . getElementById ( 'edit-update' ) . classList . add ( 'submit-start' ) ;
document . getElementById ( 'edit-update' ) . classList . remove ( 'submit-cool' ) ;
} , 2000 ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case DataEvent . POST _ADDED :
// do nothing
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case EditorEvent . EDITOR _UPLOAD _POST _IMAGE :
( 0 , _caretPos . position ) ( this . textEditor , this . caretPos ) ;
var sel , range , pulled ;
sel = window . getSelection ( ) ; //console.log(sel)
//console.log(note.message)
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( sel . rangeCount ) {
range = sel . getRangeAt ( 0 ) ;
pulled = sel . getRangeAt ( 0 ) . toString ( ) ;
range . deleteContents ( ) ;
range . insertNode ( document . createTextNode ( "![image alt text](" + data + " 'image title')" ) ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
this . refresh ( ) ;
break ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} //--------------------------
// event handlers
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} , {
key : "handleEditorOption" ,
value : function handleEditorOption ( e ) {
e . preventDefault ( ) ;
var self = this ;
var sel , range , pulled ;
sel = window . getSelection ( ) ; //console.log(sel)
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( sel . rangeCount ) {
range = sel . getRangeAt ( 0 ) ;
pulled = sel . getRangeAt ( 0 ) . toString ( ) ;
range . deleteContents ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
switch ( e . target . id ) {
case "edit-bold" :
range . insertNode ( document . createTextNode ( "**" + pulled + "**" ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-italic" :
range . insertNode ( document . createTextNode ( "*" + pulled + "*" ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-strikethrough" :
range . insertNode ( document . createTextNode ( "<del>" + pulled + "</del>" ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-header1" :
range . insertNode ( document . createTextNode ( "# " + pulled ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-header2" :
range . insertNode ( document . createTextNode ( "## " + pulled ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-header3" :
range . insertNode ( document . createTextNode ( "### " + pulled ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-image" :
this . caretPos = ( 0 , _caretPos . position ) ( this . textEditor ) . pos ;
this . emitEvent ( EditorEvent . EDITOR _UPLOAD _POST _IMAGE ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "submit-save" :
case "edit-save" :
this . emitEvent ( EditorEvent . EDITOR _SAVE ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "submit-update" :
case "edit-update" :
this . emitEvent ( EditorEvent . EDITOR _UPDATE ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-link" :
range . insertNode ( document . createTextNode ( "[" + pulled + "](PASTE URL HERE)" ) ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "edit-delete" :
this . emitEvent ( EditorEvent . EDITOR _DELETE ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
default :
//range.insertNode(document.createTextNode("[" + self.url + "](PASTE URL HERE)"));
break ;
}
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
this . refresh ( ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} ] ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return TextEditor ;
} ( _EventEmitter2 . default ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _default = TextEditor ;
exports . default = _default ;
} , { "../events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" , "../utilities/DateUtils" : "../../../../brain/tools/utilities/DateUtils.js" , "caret-pos" : "../../../../node_modules/caret-pos/lib/esm2015/main.js" , "../events/EventEmitter" : "../../../../brain/tools/events/EventEmitter.js" , "../events/EditorEvent" : "../../../../brain/tools/events/EditorEvent.js" } ] , "controllers/PostEditor.js" : [ function ( require , module , exports ) {
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _DataUtils = _interopRequireWildcard ( require ( "../../../../../brain/tools/utilities/DataUtils" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var DataEvent = _interopRequireWildcard ( require ( "../../../../../brain/tools/events/DataEvent" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _PostActions = _interopRequireDefault ( require ( "../actions/PostActions" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var EditorEvent = _interopRequireWildcard ( require ( "../../../../../brain/tools/events/EditorEvent" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _tinyDatePicker = _interopRequireDefault ( require ( "tiny-date-picker" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _DateUtils = _interopRequireDefault ( require ( "../../../../../brain/tools/utilities/DateUtils" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _TextEditor = _interopRequireDefault ( require ( "../../../../../brain/tools/ui/TextEditor" ) ) ;
2018-11-14 17:32:35 +01:00
2018-12-04 03:19:10 +01:00
var _DBUtils = _interopRequireWildcard ( require ( "../../../../../brain/tools/utilities/DBUtils" ) ) ;
2018-11-21 01:42:52 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var PostEditor =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function PostEditor ( ) {
var _this = this ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_classCallCheck ( this , PostEditor ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var self = this ;
this . dataUtils = new _DataUtils . default ( ) ;
this . dateUtils = new _DateUtils . default ( ) ;
this . urlPieces = document . URL . split ( "/" ) ;
2018-12-04 03:19:10 +01:00
this . dbUtils = new _DBUtils . default ( ) ;
2018-11-21 01:42:52 +01:00
this . post = [ ] ;
2018-11-26 23:14:13 +01:00
this . postID = null ;
2018-12-04 03:19:10 +01:00
if ( document . getElementById ( 'post-edit-index' ) . getAttribute ( 'data-index' ) ) {
this . postID = document . getElementById ( 'post-edit-index' ) . getAttribute ( 'data-index' ) ;
this . dbUtils . getPost ( this . postID ) . then ( function ( body ) {
self . post = body . post ;
_this . start ( ) ;
} ) . catch ( function ( err ) { //console.log(err)
} ) ;
} else {
this . start ( ) ;
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( document . getElementById ( 'edit-post-text' ) ) {
this . editor = new _TextEditor . default ( document . getElementById ( 'edit-post-text' ) , document . getElementById ( 'header' ) . offsetHeight + document . getElementById ( 'post-header' ) . offsetHeight + document . getElementById ( 'post-feature' ) . offsetHeight ) ;
this . editor . addListener ( EditorEvent . EDITOR _DELETE , function ( f ) {
return _this . handleEditorOptions ( EditorEvent . EDITOR _DELETE ) ;
} , false ) ;
this . editor . addListener ( EditorEvent . EDITOR _UPLOAD _POST _IMAGE , function ( f ) {
return _this . handleEditorOptions ( EditorEvent . EDITOR _UPLOAD _POST _IMAGE ) ;
} , false ) ;
this . editor . addListener ( EditorEvent . EDITOR _UPDATE , function ( f ) {
return _this . handleEditorOptions ( EditorEvent . EDITOR _UPDATE ) ;
} , false ) ;
this . editor . addListener ( EditorEvent . EDITOR _SAVE , function ( f ) {
return _this . handleEditorOptions ( EditorEvent . EDITOR _SAVE ) ;
} , false ) ;
2018-11-27 19:48:02 +01:00
document . getElementById ( 'post-image-upload' ) . addEventListener ( 'change' , function ( e ) {
self . handleImageUpload ( e . target . id , e . target . files ) ;
2018-11-21 01:42:52 +01:00
} , false ) ;
( 0 , _tinyDatePicker . default ) ( document . getElementById ( 'post-date' ) , {
mode : 'dp-below' ,
format : function format ( date ) {
//return date;
return self . dateUtils . getDate ( 'origin' , date ) ;
}
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} //--------------------------
// methods
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_createClass ( PostEditor , [ {
key : "start" ,
value : function start ( ) {
var _this2 = this ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var self = this ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
if ( document . getElementById ( 'featured-image-drop' ) ) {
2018-11-27 19:48:02 +01:00
document . getElementById ( 'featured-image-drop' ) . addEventListener ( 'dragover' , this . handleImageActions , false ) ;
document . getElementById ( 'featured-image-drop' ) . addEventListener ( 'drop' , this . handleImageActions , false ) ;
document . getElementById ( 'featured-image-upload' ) . addEventListener ( 'change' , function ( e ) {
return _this2 . handleImageActions ( e ) ;
2018-11-26 23:14:13 +01:00
} , false ) ;
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
if ( document . getElementById ( 'new-feature-upload' ) ) {
document . getElementById ( 'new-feature-upload' ) . addEventListener ( 'click' , function ( e ) {
document . getElementById ( 'featured-image-upload' ) . click ( ) ;
2018-11-21 01:42:52 +01:00
} ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var optionButtons = document . querySelectorAll ( '.post-option-btn' ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
for ( var i = 0 , length = optionButtons . length ; i < length ; i ++ ) {
optionButtons [ i ] . addEventListener ( 'click' , function ( e ) {
return _this2 . handlePostOptions ( e ) ;
} , false ) ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
}
} //--------------------------
// event handlers
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} , {
key : "handlePostOptions" ,
value : function handlePostOptions ( e ) {
var currentOption ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
switch ( e . target . id ) {
case "option-page-icon" :
case "option-page" :
currentOption = document . getElementById ( 'option-page' ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "option-feature-icon" :
case "option-feature" :
currentOption = document . getElementById ( 'option-feature' ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case "option-published-icon" :
case "option-published" :
currentOption = document . getElementById ( 'option-published' ) ;
break ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
var active = currentOption . getAttribute ( 'data-active' ) ;
active == 'false' ? currentOption . setAttribute ( 'data-active' , 'true' ) : currentOption . setAttribute ( 'data-active' , 'false' ) ;
}
} , {
key : "handleEditorOptions" ,
value : function handleEditorOptions ( e ) {
2018-11-22 02:08:53 +01:00
var _this3 = this ;
2018-12-04 03:19:10 +01:00
var self = this ;
2018-11-21 01:42:52 +01:00
switch ( e ) {
case EditorEvent . EDITOR _SAVE :
2018-12-04 03:19:10 +01:00
new _PostActions . default ( ) . update ( this . postID , this . post , PostEditor . uploadFiles , _DBUtils . FINAL _KEY ) . then ( function ( response ) {
2018-11-26 23:14:13 +01:00
setTimeout ( function ( f ) {
2018-12-04 03:19:10 +01:00
self . dbUtils . getPost ( Number ( response . response . newPost ) ) . then ( function ( r ) {
2018-12-06 22:49:49 +01:00
window . location = "/@/dashboard/posts/edit/" + r . post . uuid ;
2018-11-26 23:14:13 +01:00
} ) ;
2018-12-04 03:19:10 +01:00
} , 100 ) ;
} ) . catch ( function ( err ) { //console.log("ERROR", err)
2018-11-26 23:14:13 +01:00
} ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-26 23:14:13 +01:00
case EditorEvent . EDITOR _UPDATE :
2018-12-04 03:19:10 +01:00
new _PostActions . default ( ) . update ( this . postID , this . post , PostEditor . uploadFiles , _DBUtils . FINAL _KEY ) . then ( function ( response ) {
2018-11-22 02:08:53 +01:00
_this3 . editor . notify ( DataEvent . POST _UPDATED , _this3 . postID ) ;
2018-12-04 03:19:10 +01:00
} ) . catch ( function ( err ) { //console.log("ERRORZ", err)
2018-11-21 01:42:52 +01:00
} ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case EditorEvent . EDITOR _DELETE :
if ( confirm ( 'Aye! You know you\'re deleting this post, right?' ) ) {
2018-12-04 03:19:10 +01:00
new _PostActions . default ( ) . deletePost ( this . postID , this . post ) . then ( function ( response ) {
setTimeout ( function ( f ) {
window . location = "/@/dashboard/posts/" ;
} , 100 ) ;
2018-11-21 01:42:52 +01:00
} ) . catch ( function ( err ) {
console . log ( err ) ;
} ) ;
} else { // Do nothing!
}
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
case EditorEvent . EDITOR _UPLOAD _POST _IMAGE :
2018-11-27 19:48:02 +01:00
document . getElementById ( 'post-image-upload' ) . click ( ) ;
2018-11-21 01:42:52 +01:00
break ;
}
}
} , {
2018-11-27 19:48:02 +01:00
key : "handleImageActions" ,
value : function handleImageActions ( e ) {
2018-11-21 01:42:52 +01:00
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
2018-11-27 19:48:02 +01:00
var self = this ;
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
switch ( e . type ) {
case "dragover" :
e . dataTransfer . dropEffect = 'copy' ; // Explicitly show this is a copy.
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
break ;
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
case "change" :
case "drop" :
e . type == "drop" ? PostEditor . uploadFiles = e . dataTransfer . files : PostEditor . uploadFiles = e . target . files ;
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
for ( var i = 0 , f ; f = PostEditor . uploadFiles [ i ] ; i ++ ) {
// Only process image files.
if ( ! f . type . match ( 'image.*' ) ) {
continue ;
}
var reader = new FileReader ( ) ; // Closure to capture the file information.
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
reader . onload = function ( theFile ) {
return function ( f ) {
// Render thumbnail.
var image = document . createElement ( 'img' ) ;
image . src = f . target . result ;
image . title = escape ( theFile . name ) ;
var span = document . createElement ( 'div' ) ;
span . innerHTML = [ '<img src="' , f . target . result , '" title="' , escape ( theFile . name ) , '"/>' ] . join ( '' ) ; //document.getElementById('featured-image-drop').insertBefore(span, null);
2018-11-14 17:32:35 +01:00
2018-11-27 19:48:02 +01:00
document . getElementById ( 'featured-image-drop' ) . innerHTML = '' ;
document . getElementById ( 'featured-image-drop' ) . appendChild ( image ) ;
} ;
} ( f ) ; // Read in the image file as a data URL.
reader . readAsDataURL ( f ) ;
}
if ( e . target . id == "featured-image-upload" ) this . handleImageUpload ( e . target . id , PostEditor . uploadFiles ) ;
break ;
}
}
} , {
key : "handleImageUpload" ,
value : function handleImageUpload ( type , files ) {
var url = "" ;
var eventType = "" ;
var self = this ;
type == "featured-image-upload" ? url = "/api/post/add-feature-image" : url = "/api/post/add-post-image" ;
type == "featured-image-upload" ? eventType = DataEvent . FEATURE _IMAGE _ADDED : eventType = DataEvent . POST _IMAGE _ADDED ;
var imageData = new FormData ( ) ;
for ( var i = 0 ; i < files . length ; i ++ ) {
var file = files [ i ] ; // Check the file type.
if ( ! file . type . match ( 'image.*' ) ) {
continue ;
}
type == "featured-image-upload" ? imageData . append ( 'feature_image' , file , file . name ) : imageData . append ( 'post_image' , file , file . name ) ;
2018-11-21 01:42:52 +01:00
}
2018-11-27 19:48:02 +01:00
this . dataUtils . request ( url , eventType , _DataUtils . REQUEST _TYPE _POST , _DataUtils . CONTENT _TYPE _FORM , imageData ) . then ( function ( response ) {
var r = JSON . parse ( response . request [ 'response' ] ) ;
if ( r . message == DataEvent . POST _IMAGE _ADDED ) self . editor . notify ( EditorEvent . EDITOR _UPLOAD _POST _IMAGE , r . url ) ;
2018-12-04 03:19:10 +01:00
} ) . catch ( function ( err ) { //console.log(err)
2018-11-27 19:48:02 +01:00
} ) ;
2018-11-21 01:42:52 +01:00
}
} ] ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return PostEditor ;
} ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . default = PostEditor ;
PostEditor . uploadFiles = [ ] ;
2018-12-11 18:35:29 +01:00
} , { "../../../../../brain/tools/utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "../../../../../brain/tools/events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" , "../actions/PostActions" : "actions/PostActions.js" , "../../../../../brain/tools/events/EditorEvent" : "../../../../brain/tools/events/EditorEvent.js" , "tiny-date-picker" : "../../../../node_modules/tiny-date-picker/dist/tiny-date-picker.js" , "../../../../../brain/tools/utilities/DateUtils" : "../../../../brain/tools/utilities/DateUtils.js" , "../../../../../brain/tools/ui/TextEditor" : "../../../../brain/tools/ui/TextEditor.js" , "../../../../../brain/tools/utilities/DBUtils" : "../../../../brain/tools/utilities/DBUtils.js" } ] , "controllers/PostIndex.js" : [ function ( require , module , exports ) {
2018-12-06 22:49:49 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-21 01:42:52 +01:00
var _PostEditor = _interopRequireDefault ( require ( "./PostEditor" ) ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var PostIndex =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function PostIndex ( page ) {
_classCallCheck ( this , PostIndex ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
this . currentPage = null ;
this . choosePage ( page ) ;
this . start ( ) ;
} //--------------------------
// methods
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_createClass ( PostIndex , [ {
key : "start" ,
value : function start ( ) {
var self = this ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} , {
key : "choosePage" ,
value : function choosePage ( page ) {
this . currentPage = '' ;
switch ( page ) {
case "edit" :
case "add" :
this . currentPage = new _PostEditor . default ( ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
default :
//just chill
break ;
}
} //--------------------------
// event handlers
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} ] ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return PostIndex ;
} ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . default = PostIndex ;
2018-12-19 18:56:18 +01:00
} , { "./PostEditor" : "controllers/PostEditor.js" } ] , "actions/SettingsActions.js" : [ function ( require , module , exports ) {
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
var _DataUtils = _interopRequireWildcard ( require ( "../../../../../brain//tools/utilities/DataUtils" ) ) ;
var _StringUtils = _interopRequireDefault ( require ( "../../../../../brain//tools/utilities/StringUtils" ) ) ;
var _DateUtils = _interopRequireDefault ( require ( "../../../../../brain/tools/utilities/DateUtils" ) ) ;
var DataEvent = _interopRequireWildcard ( require ( "../../../../../brain/tools/events/DataEvent" ) ) ;
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var SettingsActions =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function SettingsActions ( ) {
_classCallCheck ( this , SettingsActions ) ;
this . dataUtils = new _DataUtils . default ( ) ;
this . dateUtils = new _DateUtils . default ( ) ;
} //--------------------------
// methods
//--------------------------
_createClass ( SettingsActions , [ {
key : "save" ,
value : function save ( ) {
var self = this ;
var handle = document . getElementById ( 'settings-handle' ) . value ;
var email = document . getElementById ( 'settings-email' ) . value ;
var url = document . getElementById ( 'settings-url' ) . value ;
var title = document . getElementById ( 'settings-title' ) . value ;
var desc = document . getElementById ( 'settings-desc' ) . innerHTML ;
var privacy = document . getElementById ( 'privacy-toggle' ) . getAttribute ( 'data-private' ) ;
2019-01-03 17:17:02 +01:00
var background = document . getElementById ( 'background' ) . src ;
2018-12-19 18:56:18 +01:00
var selected = "" ;
var selects = document . querySelectorAll ( '.theme-select' ) ;
for ( var i = 0 , length = selects . length ; i < length ; i ++ ) {
if ( selects [ i ] . getAttribute ( 'data-enabled' ) == "true" ) selected = selects [ i ] . id ;
}
var settingsData = {
handle : handle ,
email : email ,
url : url ,
title : title ,
descriptions : desc ,
2019-01-03 17:17:02 +01:00
background : background ,
2018-12-19 18:56:18 +01:00
private : privacy ,
theme : selected
} ;
return new Promise ( function ( resolve , reject ) {
self . dataUtils . request ( '/api/settings/sync' , DataEvent . SETTINGS _UPDATED , _DataUtils . REQUEST _TYPE _POST , _DataUtils . CONTENT _TYPE _JSON , settingsData ) . then ( function ( response ) {
2019-01-03 18:04:00 +01:00
//console.log("RESPONSE", response)
2018-12-19 18:56:18 +01:00
resolve ( response ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
} //--------------------------
// event handlers
//--------------------------
} ] ) ;
return SettingsActions ;
} ( ) ;
exports . default = SettingsActions ;
} , { "../../../../../brain//tools/utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "../../../../../brain//tools/utilities/StringUtils" : "../../../../brain/tools/utilities/StringUtils.js" , "../../../../../brain/tools/utilities/DateUtils" : "../../../../brain/tools/utilities/DateUtils.js" , "../../../../../brain/tools/events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" } ] , "controllers/SettingsIndex.js" : [ function ( require , module , exports ) {
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
var _SettingsActions = _interopRequireDefault ( require ( "../actions/SettingsActions" ) ) ;
2018-12-20 19:50:28 +01:00
var _DataUtils = _interopRequireWildcard ( require ( "../../../../../brain/tools/utilities/DataUtils" ) ) ;
var DataEvent = _interopRequireWildcard ( require ( "../../../../../brain/tools/events/DataEvent" ) ) ;
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
2018-12-19 18:56:18 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var SettingsIndex =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function SettingsIndex ( ) {
_classCallCheck ( this , SettingsIndex ) ;
this . start ( ) ;
2018-12-20 19:50:28 +01:00
this . dataUtils = new _DataUtils . default ( ) ;
2018-12-19 18:56:18 +01:00
} //--------------------------
// methods
//--------------------------
_createClass ( SettingsIndex , [ {
key : "start" ,
value : function start ( ) {
2019-01-03 18:04:00 +01:00
var _this = this ;
var self = this ; //handle save button
2018-12-19 18:56:18 +01:00
document . getElementById ( 'save-toggle' ) . addEventListener ( 'click' , function ( f ) {
return new _SettingsActions . default ( ) . save ( ) . then ( function ( response ) {
console . log ( response ) ;
} ) . catch ( function ( err ) {
console . log ( err ) ;
} ) ;
2019-01-03 18:04:00 +01:00
} ) ; //handle set up image uploads
2018-12-20 19:50:28 +01:00
document . getElementById ( 'avatar' ) . addEventListener ( 'click' , function ( e ) {
document . getElementById ( 'avatar-upload' ) . click ( ) ;
} ) ;
2019-01-03 17:17:02 +01:00
document . getElementById ( 'background' ) . addEventListener ( 'click' , function ( e ) {
document . getElementById ( 'background-upload' ) . click ( ) ;
} ) ;
2018-12-20 19:50:28 +01:00
document . getElementById ( 'avatar-upload' ) . addEventListener ( 'change' , function ( e ) {
self . handleImageUpload ( e . target . id , e . target . files ) ;
} , false ) ;
2019-01-03 17:17:02 +01:00
document . getElementById ( 'background-upload' ) . addEventListener ( 'change' , function ( e ) {
self . handleImageUpload ( e . target . id , e . target . files ) ;
2019-01-03 18:04:00 +01:00
} , false ) ; //handle privacy toggle
document . getElementById ( "privacy-toggle" ) . addEventListener ( "click" , function ( e ) {
return _this . togglePrivacy ( e ) ;
} ) ; //handle theme toggle
var themeBtns = document . querySelectorAll ( '.theme-select' ) ;
for ( var i = 0 , length = themeBtns . length ; i < length ; i ++ ) {
themeBtns [ i ] . addEventListener ( 'click' , function ( e ) {
return _this . handleThemes ( e ) ;
} ) ;
}
2018-12-19 18:56:18 +01:00
} //--------------------------
// event handlers
//--------------------------
2019-01-03 18:04:00 +01:00
} , {
key : "togglePrivacy" ,
value : function togglePrivacy ( e ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
if ( e . target . getAttribute ( 'data-private' ) == "false" ) {
e . target . setAttribute ( 'data-private' , 'true' ) ;
e . target . innerHTML = "SITE IS PUBLIC" ;
} else {
e . target . setAttribute ( 'data-private' , 'false' ) ;
e . target . innerHTML = "SITE IS PRIVATE" ;
}
}
} , {
key : "handleThemes" ,
value : function handleThemes ( e ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
var themes = document . querySelectorAll ( '.theme-select' ) ;
for ( var i = 0 , length = themes . length ; i < length ; i ++ ) {
e . target . id == themes [ i ] . id ? themes [ i ] . setAttribute ( 'data-enabled' , 'true' ) : themes [ i ] . setAttribute ( 'data-enabled' , 'false' ) ;
}
}
2018-12-20 19:50:28 +01:00
} , {
key : "handleImageUpload" ,
value : function handleImageUpload ( type , files ) {
var url = "" ;
var eventType = "" ;
var self = this ;
2019-01-03 17:17:02 +01:00
type == "avatar-upload" ? url = "/api/settings/add-avatar" : url = "/api/settings/add-feature-background" ;
2018-12-20 19:50:28 +01:00
var imageData = new FormData ( ) ;
for ( var i = 0 ; i < files . length ; i ++ ) {
var file = files [ i ] ; // Check the file type.
if ( ! file . type . match ( 'image.*' ) ) {
continue ;
}
type == "avatar-upload" ? imageData . append ( 'avatar_upload' , file , file . name ) : imageData . append ( 'background_upload' , file , file . name ) ;
}
this . dataUtils . request ( url , eventType , _DataUtils . REQUEST _TYPE _POST , _DataUtils . CONTENT _TYPE _FORM , imageData ) . then ( function ( response ) {
var r = JSON . parse ( response . request [ 'response' ] ) ;
if ( r . message == DataEvent . AVATAR _UPLOADED ) {
document . getElementById ( 'avatar' ) . src = r . url ;
2019-01-03 17:17:02 +01:00
} else {
document . getElementById ( 'background' ) . src = r . url ;
2018-12-20 19:50:28 +01:00
}
} ) . catch ( function ( err ) { //console.log(err)
} ) ;
}
2018-12-19 18:56:18 +01:00
} ] ) ;
return SettingsIndex ;
} ( ) ;
exports . default = SettingsIndex ;
2018-12-20 19:50:28 +01:00
} , { "../actions/SettingsActions" : "actions/SettingsActions.js" , "../../../../../brain/tools/utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "../../../../../brain/tools/events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" } ] , "controllers/DashManager.js" : [ function ( require , module , exports ) {
2018-11-21 01:42:52 +01:00
"use strict" ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var _PostIndex = _interopRequireDefault ( require ( "./PostIndex" ) ) ;
2018-11-14 17:32:35 +01:00
2018-12-19 18:56:18 +01:00
var _SettingsIndex = _interopRequireDefault ( require ( "./SettingsIndex" ) ) ;
2018-11-21 01:42:52 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
var DashManager =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function DashManager ( ) {
_classCallCheck ( this , DashManager ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
this . currentDisplay = '' ;
this . urlPieces = document . URL . split ( "/" ) ;
this . chooseDisplay ( this . urlPieces [ 5 ] , this . urlPieces [ 6 ] ) ;
} //--------------------------
// methods
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
_createClass ( DashManager , [ {
key : "start" ,
value : function start ( ) {
var self = this ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
} , {
key : "chooseDisplay" ,
value : function chooseDisplay ( section , page ) {
this . currentDisplay = '' ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
switch ( section ) {
case 'posts' :
this . currentDisplay = new _PostIndex . default ( page ) ;
break ;
2018-11-14 17:32:35 +01:00
2018-12-19 18:56:18 +01:00
case 'settings' :
this . currentDisplay = new _SettingsIndex . default ( ) ;
break ;
2018-11-21 01:42:52 +01:00
default :
// just chill
break ;
2018-11-14 17:32:35 +01:00
}
2018-11-21 01:42:52 +01:00
this . start ( ) ;
} //--------------------------
// event handlers
//--------------------------
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
} ] ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
return DashManager ;
} ( ) ;
2018-11-14 17:32:35 +01:00
2018-11-21 01:42:52 +01:00
exports . default = DashManager ;
2018-12-19 18:56:18 +01:00
} , { "./PostIndex" : "controllers/PostIndex.js" , "./SettingsIndex" : "controllers/SettingsIndex.js" } ] , "Base.js" : [ function ( require , module , exports ) {
2018-11-14 17:32:35 +01:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = void 0 ;
var _DataUtils = _interopRequireWildcard ( require ( "../../../../brain/tools/utilities/DataUtils" ) ) ;
var DataEvent = _interopRequireWildcard ( require ( "../../../../brain/tools/events/DataEvent" ) ) ;
2018-11-21 01:42:52 +01:00
var _DashManager = _interopRequireDefault ( require ( "./controllers/DashManager" ) ) ;
2018-11-14 17:32:35 +01:00
2018-12-03 01:47:28 +01:00
var _DBUtils = _interopRequireDefault ( require ( "../../../../brain/tools/utilities/DBUtils" ) ) ;
2018-11-14 17:32:35 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } }
function _createClass ( Constructor , protoProps , staticProps ) { if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) _defineProperties ( Constructor , staticProps ) ; return Constructor ; }
var Base =
/*#__PURE__*/
function ( ) {
//--------------------------
// constructor
//--------------------------
function Base ( ) {
_classCallCheck ( this , Base ) ;
var self = this ;
2018-11-21 01:42:52 +01:00
this . dashManager = [ ] ;
2018-11-14 17:32:35 +01:00
this . dataUtils = new _DataUtils . default ( ) ;
2018-12-03 01:47:28 +01:00
this . dbUtils = new _DBUtils . default ( ) ;
2018-12-11 18:35:29 +01:00
this . settings = [ ] ;
2018-11-21 01:42:52 +01:00
this . storeLocalData ( ) ;
2018-11-14 17:32:35 +01:00
}
_createClass ( Base , [ {
key : "start" ,
value : function start ( ) {
2018-11-21 01:42:52 +01:00
this . dashManager = new _DashManager . default ( ) ;
2018-11-14 17:32:35 +01:00
} //--------------------------
// methods
//--------------------------
} , {
2018-11-21 01:42:52 +01:00
key : "storeLocalData" ,
value : function storeLocalData ( ) {
2018-11-14 17:32:35 +01:00
var self = this ;
2018-11-21 01:42:52 +01:00
this . dataUtils . request ( '/api/post/json' , DataEvent . SETTINGS _LOADED ) . then ( function ( response ) {
var posts = JSON . parse ( response . request [ 'response' ] ) ;
var list = [ ] ;
for ( var index = 0 ; index < posts . length ; index ++ ) {
list . push ( {
id : posts [ index ] . id ,
post : posts [ index ] . post
} ) ;
}
2018-10-31 17:00:31 +01:00
2018-12-04 03:19:10 +01:00
self . dbUtils . syncLocal ( list ) . then ( function ( r ) {
2018-12-03 01:47:28 +01:00
self . start ( ) ;
} ) . catch ( function ( err ) {
console . log ( err ) ;
2018-11-21 01:42:52 +01:00
} ) ;
} ) . catch ( function ( err ) {
console . log ( err ) ;
2018-10-31 17:00:31 +01:00
} ) ;
} //--------------------------
// event handlers
//--------------------------
} ] ) ;
return Base ;
} ( ) ;
exports . default = Base ;
2018-12-03 01:47:28 +01:00
} , { "../../../../brain/tools/utilities/DataUtils" : "../../../../brain/tools/utilities/DataUtils.js" , "../../../../brain/tools/events/DataEvent" : "../../../../brain/tools/events/DataEvent.js" , "./controllers/DashManager" : "controllers/DashManager.js" , "../../../../brain/tools/utilities/DBUtils" : "../../../../brain/tools/utilities/DBUtils.js" } ] , "Start.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
"use strict" ;
2018-11-14 17:32:35 +01:00
var _Base = _interopRequireDefault ( require ( "./Base" ) ) ;
2018-10-31 17:00:31 +01:00
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
document . addEventListener ( 'DOMContentLoaded' , function ( ) {
var base = new _Base . default ( ) ;
} , false ) ;
2018-11-14 17:32:35 +01:00
} , { "./Base" : "Base.js" } ] , "../../../../../../.nvm/versions/node/v8.12.0/lib/node_modules/parcel-bundler/src/builtins/hmr-runtime.js" : [ function ( require , module , exports ) {
2018-10-31 17:00:31 +01:00
var global = arguments [ 3 ] ;
var OVERLAY _ID = '__parcel__error__overlay__' ;
var OldModule = module . bundle . Module ;
function Module ( moduleName ) {
OldModule . call ( this , moduleName ) ;
this . hot = {
data : module . bundle . hotData ,
_acceptCallbacks : [ ] ,
_disposeCallbacks : [ ] ,
accept : function ( fn ) {
this . _acceptCallbacks . push ( fn || function ( ) { } ) ;
} ,
dispose : function ( fn ) {
this . _disposeCallbacks . push ( fn ) ;
}
} ;
module . bundle . hotData = null ;
}
module . bundle . Module = Module ;
var parent = module . bundle . parent ;
if ( ( ! parent || ! parent . isParcelRequire ) && typeof WebSocket !== 'undefined' ) {
var hostname = "" || location . hostname ;
var protocol = location . protocol === 'https:' ? 'wss' : 'ws' ;
2019-01-03 17:17:02 +01:00
var ws = new WebSocket ( protocol + '://' + hostname + ':' + "54297" + '/' ) ;
2018-10-31 17:00:31 +01:00
ws . onmessage = function ( event ) {
var data = JSON . parse ( event . data ) ;
if ( data . type === 'update' ) {
console . clear ( ) ;
data . assets . forEach ( function ( asset ) {
hmrApply ( global . parcelRequire , asset ) ;
} ) ;
data . assets . forEach ( function ( asset ) {
if ( ! asset . isNew ) {
hmrAccept ( global . parcelRequire , asset . id ) ;
}
} ) ;
}
if ( data . type === 'reload' ) {
ws . close ( ) ;
ws . onclose = function ( ) {
location . reload ( ) ;
} ;
}
if ( data . type === 'error-resolved' ) {
console . log ( '[parcel] ✨ Error resolved' ) ;
removeErrorOverlay ( ) ;
}
if ( data . type === 'error' ) {
console . error ( '[parcel] 🚨 ' + data . error . message + '\n' + data . error . stack ) ;
removeErrorOverlay ( ) ;
var overlay = createErrorOverlay ( data ) ;
document . body . appendChild ( overlay ) ;
}
} ;
}
function removeErrorOverlay ( ) {
var overlay = document . getElementById ( OVERLAY _ID ) ;
if ( overlay ) {
overlay . remove ( ) ;
}
}
function createErrorOverlay ( data ) {
var overlay = document . createElement ( 'div' ) ;
overlay . id = OVERLAY _ID ; // html encode message and stack trace
var message = document . createElement ( 'div' ) ;
var stackTrace = document . createElement ( 'pre' ) ;
message . innerText = data . error . message ;
stackTrace . innerText = data . error . stack ;
overlay . innerHTML = '<div style="background: black; font-size: 16px; color: white; position: fixed; height: 100%; width: 100%; top: 0px; left: 0px; padding: 30px; opacity: 0.85; font-family: Menlo, Consolas, monospace; z-index: 9999;">' + '<span style="background: red; padding: 2px 4px; border-radius: 2px;">ERROR</span>' + '<span style="top: 2px; margin-left: 5px; position: relative;">🚨</span>' + '<div style="font-size: 18px; font-weight: bold; margin-top: 20px;">' + message . innerHTML + '</div>' + '<pre>' + stackTrace . innerHTML + '</pre>' + '</div>' ;
return overlay ;
}
function getParents ( bundle , id ) {
var modules = bundle . modules ;
if ( ! modules ) {
return [ ] ;
}
var parents = [ ] ;
var k , d , dep ;
for ( k in modules ) {
for ( d in modules [ k ] [ 1 ] ) {
dep = modules [ k ] [ 1 ] [ d ] ;
if ( dep === id || Array . isArray ( dep ) && dep [ dep . length - 1 ] === id ) {
parents . push ( k ) ;
}
}
}
if ( bundle . parent ) {
parents = parents . concat ( getParents ( bundle . parent , id ) ) ;
}
return parents ;
}
function hmrApply ( bundle , asset ) {
var modules = bundle . modules ;
if ( ! modules ) {
return ;
}
if ( modules [ asset . id ] || ! bundle . parent ) {
var fn = new Function ( 'require' , 'module' , 'exports' , asset . generated . js ) ;
asset . isNew = ! modules [ asset . id ] ;
modules [ asset . id ] = [ fn , asset . deps ] ;
} else if ( bundle . parent ) {
hmrApply ( bundle . parent , asset ) ;
}
}
function hmrAccept ( bundle , id ) {
var modules = bundle . modules ;
if ( ! modules ) {
return ;
}
if ( ! modules [ id ] && bundle . parent ) {
return hmrAccept ( bundle . parent , id ) ;
}
var cached = bundle . cache [ id ] ;
bundle . hotData = { } ;
if ( cached ) {
cached . hot . data = bundle . hotData ;
}
if ( cached && cached . hot && cached . hot . _disposeCallbacks . length ) {
cached . hot . _disposeCallbacks . forEach ( function ( cb ) {
cb ( bundle . hotData ) ;
} ) ;
}
delete bundle . cache [ id ] ;
bundle ( id ) ;
cached = bundle . cache [ id ] ;
if ( cached && cached . hot && cached . hot . _acceptCallbacks . length ) {
cached . hot . _acceptCallbacks . forEach ( function ( cb ) {
cb ( ) ;
} ) ;
return true ;
}
return getParents ( global . parcelRequire , id ) . some ( function ( id ) {
return hmrAccept ( global . parcelRequire , id ) ;
} ) ;
}
2018-11-14 17:32:35 +01:00
} , { } ] } , { } , [ "../../../../../../.nvm/versions/node/v8.12.0/lib/node_modules/parcel-bundler/src/builtins/hmr-runtime.js" , "Start.js" ] , null )
2018-10-31 17:00:31 +01:00
//# sourceMappingURL=/dash/assets/js/dash.min.map