{"version":3,"sources":["webpack:///./packages/core/lib/netx-autocomplete.js","webpack:///./packages/core/lib/netx-session.js","webpack:///./packages/core/lib/netx-menu.js","webpack:///./packages/core/lib/netx-analytics.js","webpack:///./packages/core/lib/netx-react-view.tsx","webpack:///./packages/core/lib/netx-enablers.js","webpack:///./packages/core/lib/netx-plugins.js","webpack:///./packages/core/lib/netx-view.js","webpack:///./build-targets/theme/packages/core/lib/netx-view.js","webpack:///./packages/core/lib/netx-model.js","webpack:///./packages/core/lib/netx-collection.js","webpack:///./packages/core/lib/netx-multiView.js"],"names":["rpc","Rpc","inquiry","completion","q","extra","opts","view","d","$","Deferred","c","autocompletions","_","isFunction","sh","stringHandler","return","LVBHandler","INBHandler","Error","plugin","isUndefined","data","api","toLowerCase","r","filter","label","includes","map","extend","filterAutocompleteResults","resolve","query","args","a","reply","promise","getCompletion","type","tags","detectAutocomplete","el","autos","querySelectorAll","length","getAttribute","Session","Base","url","Netx","URL","xhrTrackProgress","getAdvertisedSamlServices","getPublicMethods","xhrLoadingMessages","xhrLoadedMessages","defaults","browserInfo","browserLimits","chrome","crios","firefox","msie","phantomjs","safari","trident","browserOk","loginMsg","loginMsgClass","password","publicMethods","sessionKey","token","username","loggedInAsOtherUser","samlServices","undefined","clientAttrs","methods","getSamlServices","testAuthentication","testSession","testToken","_tickle","triggerAnAPIError","parsers","this","set","SAMLServicesCollection","constructor","attrs","super","key","resetLogoutTimer","debounce","sessionTicklers","addSubModel","listenTo","dispatcher","expireSession","tickle","unset","shouldBeTickling","startTickling","stopTickling","custom","REQUIRE_LOGIN","router","console","error","getToken","updatePortalContext","lastTickled","inactivityStartTime","Date","now","document","addEventListener","visibilityStateChanged","bind","configured","DAM_URL","window","location","origin","remoteURL","apiEndpoint","testAjax","success","status","jqX","upload","uploadEndpoint","ajaxSetup","xhrFields","withCredentials","defer","result","err","remoteErr","message","alert","browserTestOk","trigger","warn","authenticated","get","getSessionDuration","asMinutes","defaultMinutes","minutes","Math","min","getPreference","getSessionTickleInterval","max","opt","ajax","cache","dataType","contentType","JSON","stringify","dataContext","jsonrpc","method","id","uniqueId","params","parseData","tem","ua","navigator","userAgent","N","appName","M","match","appVersion","join","split","limits","parseInt","getCookie","cookie","i","x","y","Cookies","substr","indexOf","replace","unescape","setCookie","cname","cvalue","exdays","path","expires","setTime","getTime","toUTCString","escape","deleteCookie","name","getKey","Backbone","history","fragment","setKey","deleteKey","isNull","deleteToken","setToken","toString","isValid","then","userSource","INTERNAL","login","getPublicProperty","reject","authConfig","TICKLE_SESSION","Object","keys","attributes","resetTickler","tickler","noInitialTickle","interval","setInterval","clearInterval","beTickling","timeoutMinutes","timer","clearTimeout","setTimeout","visibilityState","postponeSessionTimeout","duration","sessionExpired","pathname","sessionDuration","catch","__name__","Menu","actions","isMenu","__isMenu__","flatten","toActions","each","actionName","concat","isArray","action","Actions","Find","push","isString","promises","analyticOpts","portal","analytics","provider","trackingState","trackingCode","enabled","trackingId","Promise","all","ReactView","preRender","removing","rendered","state","render","Component","props","ReactDOM","postRender","resolveWith","renderedOnce","remove","unmountComponentAtNode","canEmail","v","assetSet","mediaServicesEnabled","mediaServices","share","brightCove","find","youTube","collectionNotEmpty","collection","getViewCollection","pager","canUseGridEditor","allowsDelete","model","allows","collectionl","categoryAndAssetCanEdit","asset","category","current","helpUrl","integrationsAvailable","isMobile","checkIsMobile","notMobile","readOnly","getViewModel","reviewEnabled","plugins","returnData","n","dataAlias","Destroy","$el","arguments","p","destroyPlugin","Initialize","initializePlugin","when","apply","instances","Update","updatePlugin","_destroy","instance","destroyMethod","call","ex","destroy","jQuery","idx","splice","options","multiple","pluginReturn","valid","userLevel","getUserLevel","enablerTest","tests","t","initializeMethod","_el","is","log","_$el","invokePluginMethod","methodName","_invoke","_update","updateMethod","update","Extend","k","pluginOptions","assign","extendPlugin","GetInstance","elementKey","Register","Remove","Invoke","getAll","BBView","View","ES6View","prototype","MenuTemplates","actionIconsInline","ActionsIconInlineTemplate","assetDetailActions","AssetDetailActionsTemplate","attributeColumnsContextMenu","AttributeColumnsContextMenuTemplate","attributeColumnsContextMenuItem","AttributeColumnsContextMenuItemTemplate","cartBarActions","CartBarActionsTemplate","context","ContextTemplate","headerActions","HeaderActionsTemplate","listHeaderActions","ListHeaderActionsTemplate","navTabs","NavTabsTemplate","podActions","PodActionsTemplate","sidebar","SidebarTemplate","sidebarActions","SidebarActionsTemplate","systemHeaderActions","SystemHeaderActionsTemplate","systemList","SystemListTemplate","systemTableActions","SystemTableActionsTemplate","isView","__isView__","querySelector","events","contextmenu","headerTitle","routeMatch","viewSpec","template","loadingClassObjects","loadingClassRemoveDelay","listenToCollection","modalOptions","properties","removeOnHide","removeOnSimpleHide","requireSync","showLoadingOnce","_loadedOnce","debouncedRender","configureSubmenus","viewStats","subViews","templateVars","Plugins","resizeListener","pluginObj","$pluginEl","initOpts","cb","resize","__resizeTriggers__","removeResize","i18nCountStr","isRouted","loadingMethods","stickyModal","_hiddenDeferred","whenHidden","_shownDeferred","whenShown","bindCollectionEvents","bindModelEvents","setModel","setCollection","onHiding","afterHidden","onShowing","afterShown","hiding","showing","isShown","hiddenByProxy","shownByProxy","__initializers__","forEach","func","addLoadingClasses_internal","thingSyncing","showNotLoaded","item","isSyncing","isObject","isNew","syncedOnce","thingListener","thingRequesting","xhr","isModel","isCollection","showLoading","addListeners","thing","_listenId","arg","stopListening","showLoaded","noDelay","thingToListenTo","addPagerView","pagers","pagerView","removeSubView","PagerView","$pager","default","PagerModel","addSubView","setElement","cid","removeAttribute","removeClass","invoke","addClass","beforeHidden","style","display","beforeShown","collectionUpdated","bindEvents","unbindEvents","test","hammer","Hammer","on","e","findContextMenu","srcEvent","breakItUp","processCallback","completeCallback","start","amount","increment","size","delay","self","brokenUp","amt","process","end","processed","cancel","preventDefault","stopPropagation","hide","eventStr","checkHasResults","syncing","isFiltered","setAttribute","hasAssets","getTotal","checkRemove","cleanUpActionEvents","actionEvents","event","els","removeEventListener","off","updateCount","configureActions","actionList","otherView","actionOpts","targetView","enabledActions","getEnabledActions","disabledActions","$actionEls","attr","enableAction","disableAction","menuActions","menusToConfigure","menuName","hasOwnProperty","configureMenu","isMenuView","hasClass","configureMenuView","delegateEvents","menuView","$menuEl","$menuToggle","siblings","allActions","enableIf","menuViews","configureSyncActions","syncActions","configureUserActions","userActions","confirmHide","unsavedView","unsavedChanges","confirmed","cancelled","rejectWith","isMultiView","isTabView","showTab","showView","$target","disabledClass","disable","actionEvent","disableTarget","target","doTemplate","additionalVars","templateDataSource","templateProps","enable","clickEvent","defaultPrevented","originalEvent","which","closest","performAction","tag","currentTarget","prop","simulateClickBody","endProgressSimulation","simulatingProgress","requestAnimationFrame","$pseudoProgressBar","width","$pseudoProgress","escapeKeyListener","insertContextMenu","getTemplateVars","simple","isBoolean","_simpleHide","preparingToHide","checkAndRemove","currentCollection","getTransient","hideDelayed","getExcludedViews","pluck","hasFunctionality","functionalityName","initializeActions","purge","classList","contains","menus","specificSyncActions","fake","has","testOnSync","Menus","isAppView","configureSpecificSyncActions","syncActionsListening","userActionsListening","getUser","initializeKeyListeners","menuOptions","className","menuCollection","useAdvancedMenu","menu","templateName","Views","AdvancedMenuView","MenuView","appendTo","canHide","css","click","getMenuPosition","insertMenu","vanish","mv","$parent","parent","removeInner","isCollectionView","isMyRoute","route","actionArgs","last","actionWrappers","wrapper","latest","navigate","link","unshift","whenImagesLoaded","removeAllSubViews","pseudoProgressInterval","destroyView","html","TIME_RENDERS","_render_started","createElement","tagName","innerHTML","localize","renderActions","$count","$childTargetEl","renderStats","imagesLoaded","triggerEvent","$trigger","renderElement","selector","the_html","the_el","new_html","module","templateKey","stamp","done","search","str","detail","trim","setFilterStr","filterStr","unbindCollectionEvents","renderOnSetCollection","silent","element","delegate","unbindModelEvents","renderOnSetModel","show","hidePromise","_view","resp","loadingClasses","simulateProgress","listenToOnce","assetIds","cartId","loadingChunk","add","pseudoProgressWidth","draw","toggle","count","i18n","defaultValue","static","proto","getPrototypeOf","__functionality__","unique","functionality","myProto","wrap","icons","initializedIcons","materialMenus","autoOpen","top","pageY","left","pageX","body","appendChild","pointerEvents","showTooltip","originalTitle","outerHTML","one","iconOpts","classes","entries","faIcon","icon","ajv","Ajv","allErrors","coerceTypes","$data","missingRefs","useDefaults","nullable","getDefaultsFromSchema","schema","BBModel","Model","ES6Model","Schema","validate","ValidateSchema","compile","errors","defineProperty","configurable","primary","idAttribute","__isModel__","_rpc","callsByName","read","titleAttribute","storeOptions","persist","_unsavedChanges","changedAttributes","collections","removeCollectionReference","addCollectionReference","perm","permitted","batchJobComplete","batchJob","batchJobError","batchJobProgress","progress","getAutocompleteLabel","getLabel","getRestLoadedMessage","getRestLoadingMessage","packAttrs","omit","clientSide","clone","ungooeyObj","gooAttrs","serverGoo","pick","goo","unpackAttrs","gooeyObj","clientGoo","parse","save","val","wait","_validate","details","validationError","serverAttrs","wrapError","patch","sync","addSubCollection","getDefaults","GetDefaults","getIndex","pollUntil","doneTest","eventPrefix","pollMethod","pollInterval","pollMethodOptions","fetch","_polling","finished","_stopPolling","toArray","loop","response","stopPolling","trackBatchJob","uuid","app","batchJobs","notifyWith","arg0","first","garbageCollect","subCollections","removeSubCollection","subModels","removeSubModel","subscribe","socket","roomName","websocket","subscriptionMessage","dto","unsubscribe","clear","garbageCollected","retVal","isPromise","TitleAttribute","idAttr","value","protectObjectProxy","writable","BBCollection","Collection","reset","models","filtering","modelRemoved","modelAdded","ES6Collection","_isModel","__isCollection__","sorter","localStorageKey","maxStore","stored","modelChanged","deferLocalStorage","loadLocalStorage","total","obj","_byId","modelId","addToLocalStorage","checkMaxStore","keyName","store","parseLocalStorageModelOut","isNumber","expire","items","removeFromLocalStorage","clearLocalStorage","regexp","RegExp","deepClone","deleteMultiple","ids","chain","getModelIdFromEvent","getLocalStorageSize","myTotal","localStorage","toFixed","assetCount","gotoPage","page","curPage","duplicateQueryPolicy","filtered","things","parseLocalStorageModelIn","parsed","makeUniqueName","prefix","index","translate","title","at","findWhere","firstPage","preferredFetchMethod","setSort","field","order","toSelectedItemFromAutocomplete","additionalAttrs","modelProto","isNaN","text","checkReachedBeginning","reachedBeginning","checkReachedEnd","reachedEnd","initializeLazyLoad","lazyStartIndex","lowestIndex","highestIndex","routesToPage","startIndexUpdated","lazyLoadItems","forward","pageSize","lazyLoadedForward","currentPage","merge","sort","diff","startIndex","selection","MultiView","__isMultiView__","viewCollection","AppViewsCollection","childView","viewClass","instantiateOnAdd","registeredViews","additionalViewClasses","confirmUnsavedChanges","emptyOnHide","hideOnEmpty","hideWhenChildViewRemoved","renderOnInstatiate","showOnAdd","registerView","instantiateView","removeChildView","cachedActiveView","viewQueue","_viewQueue","AppViewsQueueCollection","queueFor","_viewQueueParentView","EmptyTemplate","partial","viewInstantiated","viewRemoved","prev","_previousAttributes","newActions","prevActions","showActions","difference","newAction","prevAction","uniqueShowAction","isMyOriginalCollection","activeView","getActiveView","addChildView","toggleClass","switched","viewOnHiding","viewAfterHidden","viewOnShowing","viewAfterShown","childViews","viewOptions","append","confirmedUnsavedChanges","resetActiveView","lastViewSpec","currentViewSpec","hasUnsavedChanges","active","getFirstEnabledView","viewId","collectionLength","isViewActionValid","getViewByName","hideAllViews","loadedView","_loadingView","reflectLoadingTimeout","loadingView","setClassName","toCamelCase","viewChanging","viewReady","beforeShowView","minimumShowTime","deferredModules","showFirstEnabledView","showViewByName","transientOptions","blocking","viewActionSynced","activeViewMatch","viewToShow","currentView"],"mappings":"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","file":"37.bundle.min.js?2.23.2.92950101.1696963302561","sourcesContent":["/**\n * This is an attempt to abstract the complexities of our autocomplete plugins from netx.view\n * It became even more neccessary with the new version of select2 (which is very different but I think it is acutally a trully usable plugin finally)\n * The important thing is that now all autocomplete plugins can be self contained and our API can be agnostic\n * @class\n * @param {object} plugins Additonal plugin support\n * @todo Document the plugins object and what it has to return and why\n */\nimport Rpc from 'core-libs/backbone.rpc';\nimport {completions as autocompletions} from '@netx/core-app/properties/autocomplete';\n\n// Create and provide RPC with our api url\nvar rpc = new Rpc();\n\n/**\n * Makes the inquery to the server and returns results\n * It only cares about the plugin to get the return type method\n * @method\n * @private\n * @param {string} completion Completion type (category, asset, user, etc)\n * @param {string} q Search string\n * @param {object} extra Extra data to return with results\n * @param {object} opts Options to pass along (has the plugin name)\n * @param {Netx.View} view View that contains the autocomplete\n */\nexport const inquiry = function(completion, q, extra, opts, view) {\n\tvar d = new $.Deferred();\n\n\t//var plg = plugins[opts.plugin];\n\n\t// our completion\n\tvar c = autocompletions[completion];\n\tif (_.isFunction(c)) c = c(opts);\n\n\tlet sh = opts.stringHandler;\n\t// success handler\n\tswitch(c.return) {\n\t\tcase 'lvb':\n\t\t\tsh = opts.LVBHandler;\n\t\t\tbreak;\n\t\tcase 'inb':\n\t\t\tsh = opts.INBHandler;\n\t\t\tbreak;\n\t}\n\n\tif (!_.isFunction(sh)) {\n\t\tthrow new Error(\n\t\t\t'Handler not defined or is invalid for autocomplete: ' +\n\t\t\t\topts.plugin +\n\t\t\t\t' - \"' +\n\t\t\t\tcompletion +\n\t\t\t\t'\" : ' +\n\t\t\t\t(c.return == 'lvb' ? 'LVB' : 'String'),\n\t\t);\n\t}\n\n\t// It is always possible we got here with no query string\n\t// This kills the query\n\tif (q) {\n\t\t// Local data\n\t\tif (!_.isUndefined(c.data) && _.isUndefined(c.api)) {\n\t\t\t// convert the result into the right object with the handler sh(), then extend on any extra props in 'extra'\n\t\t\tq = q.toLowerCase();\n\t\t\tvar r = sh(\n\t\t\t\t_.filter(c.data, function(d) {\n\t\t\t\t\treturn d.label.toLowerCase().includes(q);\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// Append any extra data to results\n\t\t\tif (!_.isUndefined(extra)) {\n\t\t\t\tr = _.map(r, function(d) {\n\t\t\t\t\treturn _.extend(d, extra);\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Give the view a chance to filter\n\t\t\tif (view && _.isFunction(view.filterAutocompleteResults)) {\n\t\t\t\tr = view.filterAutocompleteResults(r, completion, q);\n\t\t\t}\n\t\t\treturn d.resolve(r);\n\t\t} else {\n\t\t\t// give rpc.query() an api endpoint name, some args, and a callback\n\t\t\trpc.query(\n\t\t\t\tc.api,\n\t\t\t\t_.map(c.args, function(a) {\n\t\t\t\t\treturn a == '_TERM_' ? q : a;\n\t\t\t\t}),\n\t\t\t\tfunction(reply) {\n\t\t\t\t\t// success handler\n\t\t\t\t\t// convert the result into the right object with the handler sh(), then extend on any extra props in 'extra'\n\t\t\t\t\tvar r = sh(reply);\n\t\t\t\t\t// Append any extra data to results\n\t\t\t\t\tif (!_.isUndefined(extra)) {\n\t\t\t\t\t\tr = _.map(r, function(d) {\n\t\t\t\t\t\t\treturn _.extend(d, extra);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t// Give the view a chance to filter\n\t\t\t\t\tif (view && _.isFunction(view.filterAutocompleteResults)) {\n\t\t\t\t\t\tr = view.filterAutocompleteResults(r, completion, q);\n\t\t\t\t\t}\n\t\t\t\t\treturn d.resolve(r);\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t} else {\n\t\td.resolve([]);\n\t}\n\treturn d.promise();\n};\n\nexport const getCompletion = function(opts) {\n\tswitch (opts.completion) {\n\t\tcase 'group':\n\t\t\treturn {\n\t\t\t\t...opts,\n\t\t\t\textra: {\n\t\t\t\t\ttype: 'group',\n\t\t\t\t},\n\t\t\t};\n\t\tcase 'tag':\n\t\t\treturn {\n\t\t\t\t...opts,\n\t\t\t\tcompletion: 'tag',\n\t\t\t\ttags: true,\n\t\t\t};\n\t\tcase 'user':\n\t\tcase 'users':\n\t\t\treturn {\n\t\t\t\t...opts,\n\t\t\t\tcompletion: 'user',\n\t\t\t\textra: {\n\t\t\t\t\ttype: 'user',\n\t\t\t\t},\n\t\t\t};\n\t\tcase 'user/group': // TODO: rename userOrGroup\n\t\tcase 'userOrGroup':\n\t\t\treturn {\n\t\t\t\t...opts,\n\t\t\t\tcompletion: 'userOrGroup',\n\t\t\t};\n\t}\n\n\treturn opts;\n};\n\n// detect data-autocomplete fields in this.el, and install automatically.\nexport const detectAutocomplete = function(el, type) {\n\tlet autos = [\n\t\t...el.querySelectorAll(\n\t\t\t'[data-autocomplete]:not([data-autocomplete-added])',\n\t\t),\n\t];\n\tif (\n\t\t!autos.length &&\n\t\tel.getAttribute('data-autocomplete') &&\n\t\t!el.getAttribute('data-autocomplete-added')\n\t) {\n\t\tautos = [el];\n\t}\n\n\treturn autos.filter(el => {\n\t\treturn type === el.getAttribute('data-autocomplete-plugin');\n\t});\n};\n","/**\n * Netx.Session manages a user authentication key and/or an access token.\n * It is the first object initialized, and it establishes authentication for the rest of X7.\n * @class\n */\n\nimport Base from './netx-model';\nimport SAMLServicesCollection from '@netx/core-auth/collections/samlServices';\nimport _ from 'underscore';\nimport {dispatcher} from '@netx/core/bootstrap';\nimport Backbone from 'backbone';\nimport Rpc from 'core-libs/backbone.rpc';\nimport {userSource} from '@netx/core-user/properties/user';\n\nimport authConfig from '@netx/core-auth/config';\n\nclass Session extends Base {\n\t/**\n\t * @type {Netx.Rpc}\n\t * @private\n\t */\n\tget rpc() {\n\t\treturn true;\n\t}\n\t/**\n\t * @type {Netx.URL}\n\t * @private\n\t */\n\tget url() {\n\t\treturn Netx.URL.api;\n\t}\n\n\t/**\n\t * @type {object}\n\t */\n\tget xhrTrackProgress() {\n\t\treturn {\n\t\t\tgetAdvertisedSamlServices: true,\n\t\t\tgetPublicMethods: true,\n\t\t};\n\t}\n\n\t/**\n\t * @type {object}\n\t */\n\tget xhrLoadingMessages() {\n\t\treturn {\n\t\t\tgetAdvertisedSamlServices: 'Checking SAML services',\n\t\t\tgetPublicMethods: 'Fetching public methods',\n\t\t};\n\t}\n\n\t/**\n\t * @type {object}\n\t */\n\tget xhrLoadedMessages() {\n\t\treturn {\n\t\t\tgetAdvertisedSamlServices: 'Checked SAML services',\n\t\t\tgetPublicMethods: 'Fetched public methods',\n\t\t};\n\t}\n\n\t/**\n\t * @property {object} defaults - Default attributes\n\t * @property {array} defaults.browserInfo - TODO: document\n\t * @property {object} defaults.browserLimits - Lowest supported browser versions\n\t * @property {boolean} defaults.borwserOk - Browser version confirmed\n\t * @property {string} defaults.loginMsg - Message to display at login screen\n\t * @property {string} defaults.loginMsgClass - CSS class for login screen message ( danger, info, success, warning )\n\t * @property {string} defaults.password - Password (authentication)\n\t * @property {array} defaults.publicMethods - Any array of publicly accessible methods\n\t * @property {string} defaults.sessionKey - Session key\n\t * @property {string} defaults.token - Token key\n\t * @property {string} defaults.username - Username (authentication)\n\t * @property {module:core/lib/netx-collection} defaults.samlServices - SAML services\n\t */\n\tget defaults() {\n\t\treturn {\n\t\t\tbrowserInfo: [],\n\t\t\tbrowserLimits: {\n\t\t\t\tchrome: 25,\n\t\t\t\tcrios: 1,\n\t\t\t\tfirefox: 20,\n\t\t\t\tmsie: 10,\n\t\t\t\tphantomjs: 1,\n\t\t\t\tsafari: 5,\n\t\t\t\ttrident: 6,\n\t\t\t},\n\t\t\tbrowserOk: false,\n\t\t\tloginMsg: '',\n\t\t\tloginMsgClass: '',\n\t\t\tpassword: '',\n\t\t\tpublicMethods: [],\n\t\t\tsessionKey: '',\n\t\t\ttoken: '',\n\t\t\tusername: '',\n\t\t\tloggedInAsOtherUser: false,\n\t\t\tsamlServices: undefined,\n\t\t};\n\t}\n\n\t/**\n\t * @todo: Document why we're using clientAttrs here & what is meant by it?\n\t * There's no calls to session.self() in the codebase that I can find...\n\t * @type {array}\n\t */\n\tget clientAttrs() {\n\t\treturn [\n\t\t\t'browserLimits',\n\t\t\t'loggedInAsOtherUser',\n\t\t\t'loginMsg',\n\t\t\t'loginMsgClass',\n\t\t\t'publicMethods',\n\t\t];\n\t}\n\n\t/**\n\t * Methods for this model\n\t * @type {object}\n\t * @memberof Session\n\t * @property {object} methods - Methods for this model\n\t * @property {method} methods.getPublicMethods - Get public methods\n\t * @property {method} methods.getSamlServices - Get SAML services for SSO login\n\t * @property {method} methods.testSession - Test if session is valid\n\t * @property {method} methods.testToken - Test if token is valid\n\t * @property {method} methods.testAuthentication - Test if authenticated\n\t * @property {method} methods.tickle - Tickle the session (keep alive)\n\t * @property {methos} methods.triggerAnAPIError - Sometimes, while testing, it's useful to be able to trigger an api error by calling an undefined api method\n\t */\n\tget methods() {\n\t\treturn {\n\t\t\tgetPublicMethods: ['getPublicMethods'],\n\t\t\tgetSamlServices: ['getAdvertisedSamlServices'],\n\t\t\ttestAuthentication: ['getAuthentication'],\n\t\t\ttestSession: ['getSelf'],\n\t\t\ttestToken: ['isTokenValid', 'token'],\n\t\t\t_tickle: ['getProductVersion'],\n\t\t\ttriggerAnAPIError: ['undefinedAPIMethod'],\n\t\t};\n\t}\n\n\t/**\n\t * Parsers for this model\n\t * @type {object}\n\t */\n\tget parsers() {\n\t\treturn {\n\t\t\tgetPublicMethods(methods) {\n\t\t\t\tthis.set({publicMethods: methods});\n\t\t\t},\n\t\t\t/**\n\t\t\t * Gets saml services and saves them as a collection, used as login childViews\n\t\t\t * @param {array} samlServices\n\t\t\t * @param {object} opts Request options\n\t\t\t */\n\t\t\tgetSamlServices(samlServices, opts) {\n\t\t\t\t// samlServices.push({\n\t\t\t\t// \tname: 'Custom',\n\t\t\t\t// \ttype: 'saml',\n\t\t\t\t// \tdescription: 'Yo, here is a description',\n\t\t\t\t// \tlabel: 'Login with Custom',\n\t\t\t\t// });\n\t\t\t\tthis.set({samlServices: new SAMLServicesCollection(samlServices)});\n\t\t\t},\n\t\t};\n\t}\n\n\t/** @override */\n\tconstructor(attrs, opts = {}) {\n\t\tsuper(attrs, opts);\n\n\t\t/**\n\t\t * Used?\n\t\t * @type {string}\n\t\t * @default\n\t\t */\n\t\tthis.key = opts.key || null;\n\t\t/**\n\t\t * 30 minutes\n\t\t * @type {number}\n\t\t * @default\n\t\t */\n\t\tthis.length = opts.length || 1800000;\n\n\t\tthis.resetLogoutTimer = _.debounce(this.resetLogoutTimer, 1000);\n\n\t\t// Auto session tickling\n\t\tconst sessionTicklers = (this.sessionTicklers = new Base());\n\t\tthis.addSubModel(sessionTicklers);\n\n\t\t// Listen Up!\n\t\t// Session listens for expiration event\n\t\tthis.listenTo(dispatcher, 'session:expire', this.expireSession)\n\t\t\t.listenTo(dispatcher, 'session:tickle', this.tickle)\n\t\t\t.listenTo(dispatcher, 'session:tickle:add', (key) =>\n\t\t\t\tsessionTicklers.set(key, true),\n\t\t\t)\n\t\t\t.listenTo(dispatcher, 'session:tickle:remove', (key) =>\n\t\t\t\tsessionTicklers.unset(key),\n\t\t\t)\n\t\t\t.listenTo(sessionTicklers, 'change', () => {\n\t\t\t\tthis.shouldBeTickling() ? this.startTickling() : this.stopTickling();\n\t\t\t});\n\n\t\t// Set the REQUIRE_LOGIN configuration default\n\t\tif (_.isUndefined(Netx.custom.REQUIRE_LOGIN)) {\n\t\t\tNetx.custom.REQUIRE_LOGIN = true;\n\t\t}\n\n\t\t// Listen for route changes:\n\t\tif (!_.isUndefined(Netx.router)) {\n\t\t\tthis.listenTo(dispatcher, 'routed', this.getToken);\n\t\t\tthis.getToken();\n\t\t} else {\n\t\t\tconsole.error('Netx.router does not exist, cannot invoke getToken()');\n\t\t}\n\n\t\t// Set portal context on initial load and then listen\n\t\tthis.updatePortalContext();\n\n\t\t// Check against this time to figure out how long user has been inactive\n\t\tthis.lastTickled = this.inactivityStartTime = Date.now();\n\n\t\t// Listen for visbility change\n\t\tdocument.addEventListener(\n\t\t\t'visibilitychange',\n\t\t\tthis.visibilityStateChanged.bind(this),\n\t\t\tfalse,\n\t\t);\n\n\t\t// Establish a connection, and trigger 'netx:configured' upon success.\n\t\t//\n\t\t// These settings from config.js configure our access method.\n\t\t// If DAM_URL is set, configure CORS or proxy\n\t\t// (But if DAM_URL == the local URL, ignore it.)\n\t\tthis.configured = new $.Deferred();\n\t\tif (Netx.custom.DAM_URL && Netx.custom.DAM_URL != window.location.origin) {\n\t\t\t// test direct access with CORS authorization\n\t\t\tvar remoteURL = Netx.custom.DAM_URL + Netx.URL.apiEndpoint;\n\n\t\t\t// TODO: use Backbone.RPC for this.\n\t\t\tthis.testAjax(remoteURL, {\n\t\t\t\tsuccess: (data, status, jqX) => {\n\t\t\t\t\t// This endpoint works. Use it always.\n\t\t\t\t\tNetx.URL.api = remoteURL;\n\t\t\t\t\tNetx.URL.upload = Netx.custom.DAM_URL + Netx.URL.uploadEndpoint;\n\t\t\t\t\t$.ajaxSetup({\n\t\t\t\t\t\txhrFields: {\n\t\t\t\t\t\t\twithCredentials: true, //header for CORS access:\n\t\t\t\t\t\t},\n\t\t\t\t\t\turl: Netx.URL.api,\n\t\t\t\t\t\ttype: 'POST',\n\t\t\t\t\t});\n\t\t\t\t\t_.defer(() => {\n\t\t\t\t\t\tthis.configured.resolve(data.result);\n\t\t\t\t\t\t// dispatcher.trigger('netx:configured', data.result);\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\terror: (jqX, status, err) => {\n\t\t\t\t\tvar remoteErr = err.message;\n\t\t\t\t\t// TODO: detect/report the difference between CORS fail & network fail?\n\t\t\t\t\t// Direct access to the endpoint does not work, so test proxy access.\n\t\t\t\t\tthis.testAjax(Netx.URL.api, {\n\t\t\t\t\t\tsuccess: function (data, status, jqX) {\n\t\t\t\t\t\t\t// The proxy works.\n\t\t\t\t\t\t\t$.ajaxSetup({\n\t\t\t\t\t\t\t\turl: Netx.URL.api,\n\t\t\t\t\t\t\t\ttype: 'POST',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t_.defer(function () {\n\t\t\t\t\t\t\t\tthis.configured.resolve(data.result);\n\t\t\t\t\t\t\t\t// dispatcher.trigger('netx:configured', data.result);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror: function (jqX, status, err) {\n\t\t\t\t\t\t\t// TODO: stop the world & redirect to a failure page.\n\t\t\t\t\t\t\talert(\n\t\t\t\t\t\t\t\t'Unable to contact the DAM at ' +\n\t\t\t\t\t\t\t\t\tNetx.custom.DAM_URL +\n\t\t\t\t\t\t\t\t\t'. Please check your network connection, or try again later.\\n\\n' +\n\t\t\t\t\t\t\t\t\tremoteErr,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tthis.testAjax(Netx.URL.api, {\n\t\t\t\tsuccess: (data, status, jqX) => {\n\t\t\t\t\t_.defer(() => {\n\t\t\t\t\t\tthis.configured.resolve(data.result);\n\t\t\t\t\t\t// dispatcher.trigger('netx:configured', data.result);\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Avoid oneself not being defined to those who are listening\n\t\t_.defer(() => {\n\t\t\t// Until we can handle this better\n\t\t\tif (!this.browserTestOk()) {\n\t\t\t\tdispatcher.trigger('app:browser:override:confirmed');\n\t\t\t\tconsole.warn('Your browser may not be 100% supported.');\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * @method\n\t * @return {boolean} Authenticated\n\t */\n\tauthenticated() {\n\t\treturn (\n\t\t\t!Netx.custom.REQUIRE_LOGIN || this.get('sessionKey') || this.getToken()\n\t\t);\n\t}\n\n\t/**\n\t * Get session duration\n\t * @param {boolean} asMinutes\n\t */\n\tgetSessionDuration(asMinutes = false) {\n\t\tconst defaultMinutes = this.length / 1000 / 60;\n\t\t// DAM-14660 - keep the timeout under a 32 bit integer\n\t\tconst minutes = Math.min(\n\t\t\tNetx.getPreference('user.sessionDuration') || defaultMinutes,\n\t\t\t35791,\n\t\t);\n\t\treturn asMinutes ? minutes : minutes * 60 * 1000;\n\t}\n\n\t/**\n\t * Get session tickle interval (based on half the defined session duration minus one second)\n\t * @method\n\t * @return Tickle interval in `ms`\n\t */\n\tgetSessionTickleInterval() {\n\t\t// We will attempt to \"tickle\" 4 times in a session duration this way we do not run\n\t\t// into anything funny about timing with the response from the server or our debounce\n\t\t// of the `resetLogoutTimer` method.\n\t\t// This also ensures that if a user had just typed, a short moment after a tickle just\n\t\t// occurred, we do not risk the the session timing out if they immediately stop typing\n\t\t// after that point\n\t\t// Always keep a minimum of 59 seconds between \"tickles\" (no one should be setting the\n\t\t// session duration to less than 2 minutes)\n\t\treturn Math.max(this.getSessionDuration() / 4, 1000 * 59);\n\t}\n\n\t//////////////////////////////////////////////////\n\t//\n\t// General testing methods\n\t//\n\t//////////////////////////////////////////////////\n\n\t/**\n\t * Test for remote DAM access\n\t * @param {string} url API endpoint you are trying to access\n\t * @param {object} opt AJAX options object (jquery)\n\t */\n\ttestAjax(url, opt) {\n\t\treturn $.ajax({\n\t\t\turl: url,\n\t\t\ttype: 'POST',\n\t\t\tcache: false,\n\t\t\txhrFields: {\n\t\t\t\twithCredentials: true,\n\t\t\t},\n\t\t\tdataType: 'json',\n\t\t\tcontentType: 'application/json; charset=UTF-8',\n\t\t\tdata: JSON.stringify({\n\t\t\t\tdataContext: 'json',\n\t\t\t\tjsonrpc: '2.0',\n\t\t\t\tmethod: 'getPublicProperties',\n\t\t\t\tid: _.uniqueId(),\n\t\t\t\tparams: [],\n\t\t\t}),\n\t\t\tparseData: false,\n\t\t\tsuccess: opt.success,\n\t\t\terror: opt.error,\n\t\t});\n\t}\n\n\t/**\n\t * Test for supported browser\n\t * @return {boolean} Broser is supported.\n\t */\n\tbrowserTestOk() {\n\t\tvar ua = navigator.userAgent,\n\t\t\tN = navigator.appName,\n\t\t\ttem,\n\t\t\tM =\n\t\t\t\tua.match(\n\t\t\t\t\t/(opera|chrome|safari|firefox|msie|trident|phantomjs|crios)\\/?\\s*([\\d.]+)/i,\n\t\t\t\t) || [];\n\t\tM = M[2] ? [M[1], M[2]] : [N, navigator.appVersion, '-?'];\n\t\tif (M && (tem = ua.match(/version\\/([.\\d]+)/i)) !== null) {\n\t\t\tM[2] = tem[1];\n\t\t}\n\n\t\tthis.set('browserInfo', M.join(' ').split(' '));\n\n\t\tvar browserInfo = this.get('browserInfo');\n\t\tvar limits = this.get('browserLimits');\n\n\t\tif (browserInfo.length) {\n\t\t\tif (\n\t\t\t\t(browserInfo[0].toLowerCase() === 'chrome' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.chrome) ||\n\t\t\t\t(browserInfo[0].toLowerCase() === 'firefox' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.firefox) ||\n\t\t\t\t(browserInfo[0].toLowerCase() === 'msie' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.msie) ||\n\t\t\t\t(browserInfo[0].toLowerCase() === 'trident' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.trident) ||\n\t\t\t\t(browserInfo[0].toLowerCase() === 'phantomjs' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.phantomjs) ||\n\t\t\t\t(browserInfo[0].toLowerCase() === 'crios' &&\n\t\t\t\t\tparseInt(browserInfo[1]) >= limits.crios)\n\t\t\t) {\n\t\t\t\tthis.set('browserOk', true);\n\t\t\t} else if (\n\t\t\t\tbrowserInfo[0].toLowerCase() === 'safari' &&\n\t\t\t\tbrowserInfo.length === 3 &&\n\t\t\t\tparseInt(browserInfo[2]) >= limits.safari\n\t\t\t) {\n\t\t\t\tthis.set('browserOk', true);\n\t\t\t}\n\t\t}\n\t\t// Check that either the browser is actually ok or that there is a cookie override\n\t\tif (this.get('browserOk') || this.getCookie('browserOk')) {\n\t\t\tif (this.getCookie('browserOk')) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t'This browser %o is not officially supported',\n\t\t\t\t\tthis.get('browserInfo'),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t///////////////////////////////////////////////\n\t//\n\t// Browser cookie CRUD methods:\n\t//\n\t///////////////////////////////////////////////\n\n\t/**\n\t * getCookie Gets the value of a clientside cookie\n\t * @param {string} cookie\n\t * @return {string | undefined}\n\t */\n\tgetCookie(cookie) {\n\t\tvar i,\n\t\t\tx,\n\t\t\ty,\n\t\t\tCookies = document.cookie.split(';');\n\t\tfor (i = 0; i < Cookies.length; i++) {\n\t\t\tx = Cookies[i].substr(0, Cookies[i].indexOf('='));\n\t\t\ty = Cookies[i].substr(Cookies[i].indexOf('=') + 1);\n\t\t\tx = x.replace(/^\\s|\\s+$/g, '');\n\t\t\tif (x == cookie) {\n\t\t\t\treturn unescape(y);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * setCookie Sets the value of a clientside cookie\n\t * @param {string} cname name of cookie\n\t * @param {string} cvalue value of cookies\n\t * @param {number} exdays expire time (in days)\n\t * @param {string} path cookie path (defaults to /)\n\t */\n\tsetCookie(cname, cvalue, exdays = 0, path = '/') {\n\t\tvar expires = '';\n\t\tif (exdays) {\n\t\t\tvar d = new Date();\n\t\t\td.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000); // converting days to milliseconds 24 hours * 60 minutes * 60 seconds * 1000 millisecs.\n\t\t\texpires = `expires=\"${d.toUTCString()}\";`;\n\t\t}\n\t\tdocument.cookie = `${cname}=${escape(cvalue)}; ${expires} path=${path};`;\n\t\t// TODO: return the cookie? Define a cookie object??\n\t}\n\n\t/**\n\t * Delete the clientside cookie\n\t * @param {string} name\n\t */\n\tdeleteCookie(name) {\n\t\tthis.setCookie(name, '', -1);\n\t}\n\n\t///////////////////////////////////////////////\n\t//\n\t// NetX session key CRUD methods:\n\t//\n\t///////////////////////////////////////////////\n\n\t/**\n\t * Session.getKey() Checks to see if we are holding a session key\n\t * @return {Boolean}\n\t */\n\tgetKey() {\n\t\t// Did we already store it?\n\t\tvar sessionKey = this.get('sessionKey');\n\n\t\tif (!sessionKey) {\n\t\t\t// Is there a session key in our route? If so, it should take precedence.\n\t\t\t// (This implements the 'login as other user' feature for admins.\n\t\t\t// Session keys are alphanumeric strings with no other punctuation.\n\t\t\tvar match = Backbone.history.fragment.match(/session\\/([0-9a-zA-Z]+)/);\n\t\t\tif (match) {\n\t\t\t\tsessionKey = match[1];\n\t\t\t\tthis.set({loggedInAsOtherUser: true}); // note how we found this key\n\t\t\t} else {\n\t\t\t\t// Is a session key cookie set on our browser?\n\t\t\t\tsessionKey = this.getCookie('sessionKey');\n\t\t\t}\n\t\t}\n\n\t\tif (sessionKey) {\n\t\t\t// Cache the key locally.\n\t\t\tthis.setKey(sessionKey);\n\t\t}\n\n\t\treturn sessionKey;\n\t}\n\n\t/**\n\t * Set session key\n\t * @param {string} key\n\t */\n\tsetKey(key) {\n\t\tthis.set({sessionKey: key});\n\t}\n\n\t/**\n\t * Delete session key\n\t */\n\tdeleteKey() {\n\t\tthis.deleteCookie('sessionKey');\n\t\tthis.set('sessionKey', undefined);\n\t}\n\n\t///////////////////////////////////////////////\n\t//\n\t// Access token CRUD methods:\n\t//\n\t///////////////////////////////////////////////\n\n\t/**\n\t * Checks to see if the route contains a token.\n\t * @return {string} the token string\n\t */\n\tgetToken() {\n\t\t// Q: Should we always check the URL, or only check if if we haven't detected a token already?\n\t\t// In other words, should the token, once detected, grant access to other routes that don't contain it?\n\t\t// A: That use case hasn't come up yet. Until it does, we always check the URL.\n\n\t\t// Tokens in URLs match the official UUID spec: https://en.wikipedia.org/wiki/Universally_unique_identifier\n\t\t// They are \"version 4\" UUIDs. The pattern can get more anal that this, but basically it's 36 characters that are either hexadecimal or dash:\n\t\tvar match = Backbone.history.fragment.match(/request\\/([0-9a-fA-F-]{36})/);\n\t\tif (_.isNull(match)) {\n\t\t\tthis.deleteToken();\n\t\t\t// console.log('This route has no token');\n\t\t} else {\n\t\t\tthis.setToken(match[1].toString());\n\t\t\t// console.log('Token!: %o', this.get('token');\n\t\t}\n\t\treturn this.get('token');\n\t}\n\n\t/**\n\t * Set token\n\t * @param {string} token\n\t */\n\tsetToken(token) {\n\t\tthis.set({token});\n\t}\n\n\t/**\n\t * Delete token\n\t */\n\tdeleteToken() {\n\t\tthis.set({token: undefined});\n\t\tthis.deleteCookie('tokenKey'); // backwards-compatability\n\t}\n\n\t//////////////////////////////////////////////\n\t//\n\t// Session management:\n\t// testing, timing, tickling.\n\t//\n\t//////////////////////////////////////////////\n\n\t/**\n\t * Session.isValid() Return a promise that will resolve or reject on whether we have a valid session,\n\t * either via a session key or an access token\n\t * @return {Promise}\n\t */\n\tisValid() {\n\t\tvar d = new $.Deferred();\n\n\t\t// 1) Do we have an access token set? If so, test it.\n\t\tif (this.getToken()) {\n\t\t\treturn this.testToken();\n\t\t}\n\n\t\t// 2) Do we have a session key at all? If not, we are S.O.L.\n\t\tif (!this.getKey()) {\n\t\t\treturn d.reject().promise(); // no session!\n\t\t}\n\n\t\t// 3) We have a session key, but is it valid?\n\t\tthis.testSession().then(\n\t\t\tfunction (data) {\n\t\t\t\t// If this is an internal user account, check if we\n\t\t\t\t// are logged in as public user and reject\n\t\t\t\tif (\n\t\t\t\t\tNetx.custom.REQUIRE_LOGIN &&\n\t\t\t\t\tdata.userSource === userSource.INTERNAL &&\n\t\t\t\t\tdata.login === Netx.getPublicProperty('viewer.userLogin')\n\t\t\t\t) {\n\t\t\t\t\tthis.deleteCookie('sessionKey');\n\t\t\t\t\td.reject(); // public user!\n\t\t\t\t}\n\t\t\t\t// If not public user resolve\n\t\t\t\td.resolve(); // valid session!\n\t\t\t},\n\t\t\tfunction (data) {\n\t\t\t\t// If the sessionKey is not valid, erase it\n\t\t\t\tthis.deleteCookie('sessionKey');\n\t\t\t\td.reject(); // invalid session!\n\t\t\t},\n\t\t);\n\n\t\treturn d.promise();\n\t}\n\n\tshouldBeTickling() {\n\t\treturn (\n\t\t\tauthConfig.TICKLE_SESSION ||\n\t\t\t!!Object.keys(this.sessionTicklers.attributes).length\n\t\t);\n\t}\n\n\t// Session Tickling\n\t// ================\n\t// If enabled, we tickle the server regularly to make sure it doesn't time us out.\n\n\tresetTickler() {\n\t\tif (!this.tickler && !this.shouldBeTickling()) return;\n\n\t\tthis.stopTickling();\n\t\tthis.startTickling(true);\n\t}\n\n\t/**\n\t * Session.startTickling Starts an interval timer to tickle the server regularly\n\t */\n\tstartTickling(noInitialTickle = false) {\n\t\tif (this.tickler) return;\n\n\t\tconst interval = this.getSessionTickleInterval();\n\n\t\tthis.tickler = setInterval(this.tickle.bind(this), interval);\n\t\t!noInitialTickle && this.tickle();\n\t}\n\n\t/**\n\t * Session.stopTickling Removes the interval timer set by startTickling()\n\t */\n\tstopTickling() {\n\t\tthis.tickler && clearInterval(this.tickler);\n\t\tdelete this.tickler;\n\t}\n\n\t/**\n\t * Session.beTickling Starts the tickling if it hasn't already been started.\n\t */\n\tbeTickling() {\n\t\tif (this.tickler) return;\n\t\tthis.startTickling();\n\t}\n\n\t/**\n\t * Tickle while preventing over tickling\n\t * @method\n\t */\n\ttickle() {\n\t\tif (this.getToken() || !this.getKey()) return;\n\n\t\tconst now = Date.now();\n\t\t// Do not tickle more than once per minute\n\t\tif (now - this.lastTickled >= 1000 * 60) {\n\t\t\tthis.lastTickled = now;\n\t\t\tthis._tickle();\n\t\t}\n\t}\n\n\t// Session Timer\n\t// ================\n\t// A session timer counts down how many seconds remain before the server times us out.\n\t// Here, we watch the clock & warn the user when timeout approaches.\n\t// Note that session tickling prevents session timeout. Use one or the other, but not both.\n\n\t/**\n\t * resetLogoutTimer starts an interval timer to trigger an event 60 seconds before the DAM logs us out.\n\t */\n\t// NOTE: the function is debounced because it will be called on every successful RPC call.\n\tresetLogoutTimer() {\n\t\t// DAM-16342 - if on a token, never timeout session,\n\t\t// never dispatch 'netx:session:timeoutWarning'\n\t\tif (this.getToken()) return;\n\n\t\tthis.lastTickled = this.inactivityStartTime = Date.now();\n\t\tconst timeoutMinutes = this.getSessionDuration(true);\n\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t}\n\n\t\tthis.timer = setTimeout(() => {\n\t\t\t// Only trigger the warning if we are actually logged in, via key or token\n\t\t\t// and if the page is hidden, don't trigger the timeout warning\n\t\t\tif (this.getKey() && document.visibilityState === 'visible') {\n\t\t\t\tdispatcher.trigger('netx:session:timeoutWarning');\n\t\t\t}\n\t\t}, 60 * 1000 * (timeoutMinutes - 1)); // time out 1 minute (60000 milliseconds) before the session duration (which is expressed in minutes)\n\n\t\t// Accidentally removed in 8.8, leading to the \"why am i logged out when i reload\" problem:\n\t\tthis.postponeSessionTimeout(timeoutMinutes);\n\t\t// (In 8.9 we will manage the session entirely on the client, so this will change ...)\n\t}\n\n\t/**\n\t * Manipulate cookies to signal that the session was ended due to a timeout.\n\t * (So that the login screen display a relelevant message.)\n\t */\n\texpireSession() {\n\t\t// DAM-16342 - if on a token, never timeout session\n\t\t// just in case session:expire is dispatched\n\t\tif (this.getToken() || !this.getKey()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.deleteCookie('sessionKey');\n\t\tthis.setCookie('sessionExpired', 'EXPIRED', 1);\n\t\tdispatcher.trigger('app:stop');\n\t}\n\n\t/**\n\t * Postpone session cookie expiration: set the expire time of the session cookie (if any) to 30 minutes from now.\n\t * @param {number} duration Minutes\n\t */\n\tpostponeSessionTimeout(duration) {\n\t\tvar cookie = this.getCookie('sessionKey');\n\t\tif (!cookie) return false;\n\n\t\tif (!duration) duration = this.getSessionDuration(true);\n\n\t\t// NOTE: converting duration from minutes to days: 60 mins * 24 hours = 1 day.\n\t\tthis.setCookie('sessionKey', cookie, duration / (60 * 24));\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Check for, and clear, the session-expired cookie.\n\t */\n\tsessionExpired() {\n\t\tif (this.getCookie('sessionExpired') == 'EXPIRED') {\n\t\t\tthis.deleteCookie('sessionExpired');\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Update the portalContext cookie to reflect the current theme\n\t */\n\tupdatePortalContext() {\n\t\t// Update the portalContext cookie to reflect the current theme\n\t\tthis.setCookie('portalContext', window.location.pathname);\n\t}\n\n\t/**\n\t * The browser page visibility has changed\n\t */\n\tvisibilityStateChanged() {\n\t\tif (document.visibilityState === 'visible') {\n\t\t\t// Set 'portalContext' cookie (DAM-9257)\n\t\t\tthis.updatePortalContext();\n\n\t\t\t// If user backgrounds Netx tab for longer than session,\n\t\t\t// they should be kicked to login screen when tab becomes active.\n\t\t\tconst sessionDuration = this.getSessionDuration();\n\n\t\t\tconst sessionExpired =\n\t\t\t\tDate.now() - this.inactivityStartTime >= sessionDuration;\n\n\t\t\tif (sessionExpired) {\n\t\t\t\t// If multiple Netx tabs are open, this timeout could be triggered.\n\t\t\t\t// Let's ask the server if the session really is expired\n\t\t\t\tthis.testSession()\n\t\t\t\t\t.then(this.resetLogoutTimer.bind(this))\n\t\t\t\t\t.catch(this.expireSession.bind(this));\n\t\t\t}\n\t\t}\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'Session';\n\t}\n}\n\nexport default Session;\n","/**\n * A Netx.Menu defines menus, composed of actions, for use with the data-action-context tag in our templates.\n * It is a more flexible & more centralized syntax than our previous system. Menus are also use to define\n * tabsets and other navigational structures.\n *\n * The 'actions' property of a Netx.Menu is an array that can contain either the names of actions\n * (defined in Netx.Actions) or arrays of same. The arrays are used to define sections in situations\n * where that is useful.\n *\n * The action entries match the \"event\" property of defined actions.\n *\n * This object is not parsed until the moment a menu is rendered. Nonexistent actions are ignored.\n * @class\n */\nimport Base from './netx-model';\n\nclass Menu extends Base {\n\t/** @type {object} */\n\tget defaults() {\n\t\treturn {\n\t\t\tlabel: '', // in some situations (such as submenus) a menu may need a label\n\t\t\tactions: [], // actions in the menu; see example below.\n\t\t};\n\t}\n\n\t/** @type {boolean} */\n\tget isMenu() {\n\t\treturn this.constructor.__isMenu__;\n\t}\n\n\t/*\n\t * return the names of all the actions in a menu, i.e. flatten the menu\n\t */\n\tflatten() {\n\t\treturn this.get('actions'); // TODO: flatten\n\t}\n\n\t/*\n\t * return a flat list of all the action objects (that exist) referenced by a menu\n\t */\n\ttoActions() {\n\t\tvar actions = [];\n\t\t_.each(this.flatten(), function(actionName) {\n\t\t\tif (actionName.isMenu) {\n\t\t\t\tactions = actions.concat(actionName.toActions());\n\t\t\t} else if (_.isArray(actionName)) {\n\t\t\t\t_.map(actionName, function(name) {\n\t\t\t\t\tvar action = Netx.Actions.Find(actionName);\n\t\t\t\t\taction && actions.push(action);\n\t\t\t\t});\n\t\t\t} else if (_.isString(actionName)) {\n\t\t\t\tvar action = Netx.Actions.Find(actionName);\n\t\t\t\taction && actions.push(action);\n\t\t\t} else {\n\t\t\t\tconsole.warn('undefined action ' + actionName);\n\t\t\t}\n\t\t});\n\t\treturn actions;\n\t}\n\n\t/** @type {boolean} */\n\tstatic get __isMenu__() {\n\t\treturn true;\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'Menu';\n\t}\n}\n\nexport default Menu;","/**\n * @fires netx:analytics:start\n */\nexport default function() {\n\tconst promises = [];\n\n\tvar analyticOpts = Netx.custom.portal ? Netx.custom.portal.analytics : null;\n\t// Check for analytics configuration:\n\t_.each(['google'], function(provider) {\n\t\tlet trackingState, trackingCode;\n\t\tif (analyticOpts) {\n\t\t\tprovider = analyticOpts[provider] || {};\n\t\t\ttrackingState = provider.enabled;\n\t\t\ttrackingCode = provider.trackingId;\n\t\t} else {\n\t\t\ttrackingState = Netx.getPublicProperty(\n\t\t\t\t'analytics.' + provider + '.enabled',\n\t\t\t\ttrue,\n\t\t\t);\n\t\t\ttrackingCode = Netx.getPublicProperty(\n\t\t\t\t'analytics.' + provider + '.trackingId',\n\t\t\t);\n\t\t}\n\t\tif (trackingState && trackingCode) {\n\t\t\tvar d = new $.Deferred();\n\t\t\tpromises.push(d);\n\t\t\t// Load & start Analytics.\n\t\t\tdispatcher.trigger(\n\t\t\t\t'netx:analytics:start',\n\t\t\t\tprovider,\n\t\t\t\ttrackingCode,\n\t\t\t\tfunction() {\n\t\t\t\t\td.resolve();\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t});\n\n\treturn Promise.all(promises);\n}\n","import Base from '@netx/core/lib/netx-view';\nimport BaseModel from '@netx/core/lib/netx-model';\nimport BaseCollection from '@netx/core/lib/netx-collection';\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\n\nexport type {ViewOptions} from '@netx/core/lib/netx-view';\n\nexport default class ReactView<\n\tTModel extends BaseModel = BaseModel,\n\tTCollection extends BaseCollection = BaseCollection,\n> extends Base {\n\tpreRender() {\n\t\tsuper.preRender();\n\n\t\tif (this.removing) return this;\n\n\t\tif (this.rendered.state() !== 'pending') {\n\t\t\tthis.rendered = $.Deferred();\n\t\t}\n\n\t\tthis.trigger('preRenderHook', this);\n\t}\n\n\t// @ts-ignore\n\t// We are breaking polymorphism but ¯\\_(ツ)_/¯ we do that a lot in our backbone stuff\n\t// But hey, now you can get props validation in extended react view classes when calling:\n\t// `render(Component, {some: 'prop'})`\n\trender(\n\t\tComponent: C,\n\t\tprops: JSX.IntrinsicAttributes &\n\t\t\tJSX.LibraryManagedAttributes>,\n\t) {\n\t\tReactDOM.render(, this.el);\n\t\treturn this;\n\t}\n\n\tpostRender() {\n\t\tsuper.postRender();\n\n\t\tthis.rendered.resolveWith(this);\n\t\tthis.trigger('rendered');\n\n\t\t// We have rendered once (at least)\n\t\tthis.renderedOnce = true;\n\t\tthis.trigger('renderedHook', this);\n\t}\n\n\tremove() {\n\t\tReactDOM.unmountComponentAtNode(this.el);\n\t\treturn super.remove();\n\t}\n\n\tstatic get __name__() {\n\t\treturn 'ReactView';\n\t}\n}\n","/**\n * The 'enableTest' field of an Action definitions may be set to one of these, or to an array of them for multiple tests.\n * @module core/enablers\n */\n\nimport {getViewCollection, getViewModel} from '@netx/core/lib/utils';\nimport {userSource as userSources} from '@netx/core-user/properties/user';\nimport {isMobile as checkIsMobile} from '@netx/core/lib/underscore-netx';\n\n/**\n * Clips cannot be emailed currently\n * @function\n * @returns {boolean}\n */\nexport const canEmail = v => {\n\tif (v.data && v.data.assetSet) {\n\t\treturn v.data.assetSet.get('canEmail') !== false;\n\t}\n\treturn true;\n};\n\n/**\n * Can user logout\n * @function\n * @return {boolean}\n */\nexport const canLogout = v => {\n\tconst userSource = Netx.getUser('userSource');\n\t// If user source is INTERNAL or SAML\n\treturn userSource === userSources.INTERNAL || userSource === userSources.SAML;\n};\n\n// TODO: We should not reference Netx.[module] (other than user) for enable tests\n// DAM-11555 - currently used only for video publishing\n/**\n * @function\n * @returns {boolean}\n */\nexport const mediaServicesEnabled = v => {\n\tif (Netx.getPublicProperty('mediaServices.enabled', true)) {\n\t\tvar mediaServices = Netx.share.mediaServices,\n\t\t\tbrightCove = mediaServices.find({name: 'Brightcove'}),\n\t\t\tyouTube = mediaServices.find({name: 'YouTube'});\n\n\t\treturn (\n\t\t\t(youTube && youTube.get('authenticated')) ||\n\t\t\t(brightCove && brightCove.get('authenticated'))\n\t\t);\n\t}\n\treturn false;\n};\n\n// collection has at least one model\n/**\n * @function\n * @returns {boolean}\n */\nexport const collectionNotEmpty = v => {\n\tconst collection = getViewCollection(v);\n\tif (!collection) return false;\n\n\t// Sometimes we update the pager before we get models in a collection\n\tconst pager = collection.pager;\n\tif (!pager) return collection.length > 0;\n\n\treturn pager.get('itemTotal') > 0;\n};\n\n/**\n * @function\n * @returns {boolean}\n */\nexport const canUseGridEditor = v => {\n\treturn true;\n};\n\n/**\n * @function\n * @returns {boolean}\n */\nexport const allowsDelete = v => {\n\tif (v.model && _.isFunction(v.model.allows)) {\n\t\treturn v.model.allows('delete');\n\t} else if (v.collection && _.isFunction(v.collection.allows)) {\n\t\treturn v.collectionl.allows('delete');\n\t}\n\treturn false;\n};\n\n// For the case when you want to move an asset out of/into a category,\n// for which you need modify permissions on both. We can't know whether\n// to expect an asset view or a category view here. We have a few different\n// patterns for inserting extra references, too, so here we perform an\n// exhaustive search.\n/**\n * @function\n * @returns {boolean}\n */\nexport const categoryAndAssetCanEdit = view => {\n\t// Best approach is if the view itself has both .asset and .category, being links to appropriate models.\n\tif (view.asset && view.category) {\n\t\treturn view.asset.allows('modify') && view.category.allows('modify');\n\t}\n\n\t// view.model could be either an asset model or a catgegory model, but either way this has to pass:\n\tif (!view.model || !view.model.allows || !view.model.allows('modify')) {\n\t\treturn false;\n\t}\n\n\tif (view.model.constructor.__name__ === 'Category') {\n\t\tif (view.asset) {\n\t\t\t// If a category view has an asset model as .asset, this will work.\n\t\t\treturn view.asset.allows('modify');\n\t\t} else {\n\t\t\t// NOTE: this view.model.get('asset') thing is kind of a hack, used to reference the original asset model in the asset:category:edit handler.\n\t\t\t// I'd rather we attached that directly to the view (as above), because its meaning can be misconstrued otherwise.\n\t\t\t// TODO: fix that up.\n\t\t\treturn (\n\t\t\t\tview.model.get('asset') && view.model.get('asset').allows('modify')\n\t\t\t);\n\t\t}\n\t}\n\n\tif (view.model.constructor.__name__ === 'Asset') {\n\t\t// if an asset view has a category model as .category, this will work.\n\t\tif (view.category) {\n\t\t\treturn view.category.allows('modify');\n\t\t} else {\n\t\t\t// if the current category just so happens to be our asset's \"main\" category, we're in luck and can test.\n\t\t\tview.model.get('categoryid') == Netx.category.current.id &&\n\t\t\t\tNetx.category.current.allows('modify');\n\t\t}\n\t}\n\n\t// Couldn't find a test, alas.\n\treturn false;\n};\n\n/**\n * Have we set `header.helpUrl`?\n * @function\n * @returns {boolean}\n */\nexport const helpUrl = v => {\n\treturn !_.isUndefined(Netx.getPreference('header.helpUrl'));\n};\n\n/**\n * Are integrations (aka media services) available?\n * @function\n * @returns {boolean}\n */\nexport const integrationsAvailable = v => {\n\treturn Netx.getPublicProperty('mediaServices.enabled', true);\n};\n\n/**\n * @function\n * @returns {boolean}\n */\nexport const isMobile = () => {\n\treturn checkIsMobile(false);\n};\n\n/**\n * @function\n * @returns {boolean}\n */\nexport const notMobile = () => {\n\treturn !isMobile();\n};\n\n/**\n * @function\n * @returns {boolean}\n */\nexport const readOnly = v => {\n\tconst model = getViewModel(v);\n\treturn !model.allows('write');\n};\n\n/**\n * Asset review enabled\n * @function\n * @returns {boolean}\n */\nexport const reviewEnabled = v => {\n\t// DAM-14088\n\tif (checkIsMobile()) return false;\n\n\treturn Netx.getPreference('review.enabled', true);\n};\n","/**\n * Manage plugins on a single view's instance\n * @class\n * @param {Netx.View} view View to store plugins on\n * @example\n * {\n * pluginUniqueNameForView: {\n * name : 'tooltip', // The name of the plugin. Used for intializing\n * dataAlias : 'bs.tooltip', // The name of the data the plugin stores on the element, if it differs from the name\n * enablerTest : function() {}, // Just like actions\n * userLevel : 8, // Just like actions\n * multiple : true, // Should we allow multiple instances of this plugin on the view (default is false),\n * destroyMethod : 'destroy', // If the plugin's destroy method name differs from `destroy` - can also be a function (the instance will be the only parameter)\n * initializeMethod : 'initialize', // If the plugin's initialize method name differs from `initialize` - can also be a function (passes the plugin object, the $el, the init options, and a callback - the instance you create must be returned to this callback)\n * updateMethod : 'update', // If the plugin's update method name differs from `update`\n * elementKey : 'container', // If the plugin's element key differs from '$el'\n * options : {\n * // Plugin options\n * placement: 'top'\n * }\n * }\n * }\n */\nconst extendPlugin = (plugin, opts) => {\n\tconst pluginOptions = {...plugin.options, ...opts.options};\n\tObject.assign(plugin, opts);\n\tplugin.options = pluginOptions;\n};\n\nexport default function(view) {\n\t/** @lends Netx.Plugins */\n\tvar plugins = {},\n\t\tpublicMethods = {};\n\t/**\n\t * Extend modifications onto exisiting plugin\n\t * @method\n\t * @public\n\t * @param {object} plugin An object of plugin(s)\n\t * @param {object} opts Options (not used currently)\n\t */\n\tfunction Extend(plugin, opts) {\n\t\topts = opts || {};\n\t\tplugin = plugin || {};\n\t\t// Loop over passed plugins and extend to existing\n\t\t_.each(plugin, function(p, k) {\n\t\t\tif (!_.isUndefined(plugins[k])) {\n\t\t\t\textendPlugin(plugins[k], p);\n\t\t\t} else {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t'The plugin ' +\n\t\t\t\t\t\tk +\n\t\t\t\t\t\t' has not been defined. Please use `register` in place of `extend`.',\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\t/**\n\t * Find plugin(s) by name\n\t * @method\n\t * @public\n\t * @param {array|string} name Plugin name (key, name, dataAlias)\n\t * @return {array|boolean|object}\n\t */\n\tfunction Find(name) {\n\t\t// Just to make things easier - assume array\n\t\tif (!_.isArray(name)) name = [name];\n\n\t\tvar returnData = [];\n\t\t// Loop over plugin names\n\t\t_.each(name, function(n) {\n\t\t\t// It weas the key\n\t\t\tif (plugins[n]) {\n\t\t\t\treturnData.push(plugins[n]);\n\t\t\t}\n\t\t\t// It was not the key, try the name and alias\n\t\t\telse {\n\t\t\t\t_.each(plugins, function(plugin) {\n\t\t\t\t\tif (plugin.name === n || plugin.dataAlias === n) {\n\t\t\t\t\t\treturnData.push(plugin);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// Just return false and not an empty array\n\t\tif (!returnData.length) {\n\t\t\treturn false;\n\t\t}\n\t\t// If a single result, unwrap it from array\n\t\treturn returnData.length > 1 ? returnData : returnData[0];\n\t}\n\t/**\n\t * Get plugin(s) instance by name\n\t * @method\n\t * @public\n\t * @param {array|string} name Plugin name (key, name, dataAlias)\n\t * @param {element} $el Element to get plugin instance on\n\t * @return {array|boolean|object}\n\t */\n\tfunction GetInstance(name, $el) {\n\t\tvar plugin = Find(name);\n\t\tif (plugin && plugin.instance) {\n\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\tif ($el) {\n\t\t\t\t\treturn _.filter(plugin.instance, function(instance) {\n\t\t\t\t\t\tvar el = instance[plugin.elementKey || '$el'];\n\t\t\t\t\t\tif (el) {\n\t\t\t\t\t\t\treturn el instanceof jQuery ? el.is($el) : el == $el;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn plugin.instance;\n\t\t}\n\t\treturn false;\n\t}\n\t/**\n\t * Register plugin(s)\n\t * @method\n\t * @public\n\t * @param {object} plugin An object of plugin(s)\n\t * @param {object} opts Options (not used currently)\n\t */\n\tfunction Register(plugin, opts) {\n\t\topts = opts || {};\n\t\tplugin = plugin || {};\n\n\t\t// Loop over passed plugins and add if not already defined\n\t\t_.each(plugin, function(p, k) {\n\t\t\tif (_.isUndefined(plugins[k])) {\n\t\t\t\tplugins[k] = p;\n\t\t\t} else {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t'The plugin ' +\n\t\t\t\t\t\tk +\n\t\t\t\t\t\t' has already been defined. Please use `extend` in place of `register`.',\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\t/**\n\t * Remove plugin(s)\n\t * @method\n\t * @public\n\t * @param {string} name Actual key name for plugin (the key, not the name/dataAlias)\n\t */\n\tfunction Remove(name) {\n\t\tif (_.isArray(name)) {\n\t\t\t_.each(name, Remove);\n\t\t} else if (plugins[name]) {\n\t\t\tdelete plugins[name];\n\t\t}\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\n\t/**\n\t * Destroy plugin instance(s)\n\t * @method\n\t * @public\n\t * @param {string} name Plugin name (key, name, dataAlias)\n\t * @param {element} $el Element to destroy plugin on\n\t */\n\tfunction Destroy(name, $el) {\n\t\t// Destroy them all if nothing was passed\n\t\tif (!arguments.length) {\n\t\t\t_.each(plugins, function(p) {\n\t\t\t\tdestroyPlugin(p);\n\t\t\t});\n\t\t} else {\n\t\t\t// Multiple plugins to destroy\n\t\t\tif (_.isArray(name)) {\n\t\t\t\t_.each(name, function(n) {\n\t\t\t\t\tDestroy(n, $el);\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Single plugin to destroy\n\t\t\telse {\n\t\t\t\tvar plugin = Find(name);\n\t\t\t\tif (!plugin) {\n\t\t\t\t\t// console.warn( \"The plugin \" + name + \" has not been defined. Cannot destroy what does not exist.\" );\n\t\t\t\t} else if (plugin.length) {\n\t\t\t\t\t_.each(plugin, function(p) {\n\t\t\t\t\t\tdestroyPlugin(p, $el);\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tdestroyPlugin(plugin, $el);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\t/**\n\t * Initialize plugin instance(s)\n\t * @method\n\t * @public\n\t * @param {array|string} name Plugin name (key, name, dataAlias)\n\t * @param {element} $el Element to initialize plugin on\n\t * @param {object} opts Additional plugin options (support for passing custom options at init that may or may not be the same in the registered options)\n\t * @return {promise}\n\t */\n\tfunction Initialize(name, $el, opts) {\n\t\tvar d = new $.Deferred(),\n\t\t\tpromises = [];\n\t\t// Multiple plugins to init\n\t\tif (_.isArray(name)) {\n\t\t\t_.each(name, function(n) {\n\t\t\t\tvar plugin = Find(n);\n\t\t\t\tif (!plugin) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t'The plugin ' +\n\t\t\t\t\t\t\tn +\n\t\t\t\t\t\t\t' has not been defined. Please use `register` prior to intializing.',\n\t\t\t\t\t);\n\t\t\t\t} else if (plugin.length) {\n\t\t\t\t\t_.each(\n\t\t\t\t\t\tplugin,\n\t\t\t\t\t\tfunction(p) {\n\t\t\t\t\t\t\tpromises.push(initializePlugin(p, $el, opts));\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tpromises.push(initializePlugin(plugin, $el, opts));\n\t\t\t\t}\n\t\t\t});\n\t\t\t$.when.apply($, promises).then(function(instances) {\n\t\t\t\td.resolveWith(view, instances);\n\t\t\t});\n\t\t\treturn d.promise();\n\t\t}\n\n\t\t// Single plugin to init\n\t\tvar plugin = Find(name);\n\t\tif (!plugin) {\n\t\t\tconsole.warn(\n\t\t\t\t'The plugin ' +\n\t\t\t\t\tname +\n\t\t\t\t\t' has not been defined. Please use `register` prior to intializing.',\n\t\t\t);\n\t\t} else if (plugin.length) {\n\t\t\t_.each(\n\t\t\t\tplugin,\n\t\t\t\tfunction(p) {\n\t\t\t\t\tpromises.push(initializePlugin(p, $el, opts));\n\t\t\t\t},\n\t\t\t\tthis,\n\t\t\t);\n\t\t\t$.when.apply($, promises).then(function(instances) {\n\t\t\t\td.resolveWith(view, instances);\n\t\t\t});\n\t\t\treturn d.promise();\n\t\t} else {\n\t\t\treturn initializePlugin(plugin, $el, opts);\n\t\t}\n\t}\n\t/**\n\t * Update plugin(s) instance(s)\n\t * @method\n\t * @public\n\t * @param {string} name Plugin name (key, name, dataAlias)\n\t * @param {element} $el Element to update plugin on\n\t * @param {object} opts Additional plugin update arguments\n\t */\n\tfunction Update(name, $el, args) {\n\t\tvar plugin = Find(name);\n\t\tif (!plugin) {\n\t\t\tconsole.warn(\n\t\t\t\t'The plugin ' +\n\t\t\t\t\tname +\n\t\t\t\t\t' has not been defined. Cannot update that which does not exist.',\n\t\t\t);\n\t\t} else if (plugin.length) {\n\t\t\t_.each(\n\t\t\t\tplugin,\n\t\t\t\tfunction(p) {\n\t\t\t\t\tupdatePlugin(p, $el, args);\n\t\t\t\t},\n\t\t\t\tthis,\n\t\t\t);\n\t\t} else {\n\t\t\tupdatePlugin(plugin, $el, args);\n\t\t}\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\n\t/**\n\t * Invoke a method on plugin(s) instance(s)\n\t * @method\n\t * @public\n\t * @param {string} name Plugin name (key, name, dataAlias)\n\t * @param {element} $el Element to update plugin on\n\t * @param {string} methodName The method to invoke\n\t * @param {object} opts Additional plugin update arguments\n\t */\n\tfunction Invoke(name, $el, methodName, args) {\n\t\t// Redirect access to these methods\n\t\tswitch (methodName) {\n\t\t\tcase 'destroy':\n\t\t\t\treturn Destroy(name, $el);\n\t\t\tcase 'init':\n\t\t\tcase 'initialize':\n\t\t\t\treturn Initialize(name, $el, args);\n\t\t\tcase 'update':\n\t\t\t\treturn Update(name, $el, args);\n\t\t}\n\n\t\tvar plugin = Find(name);\n\t\tif (!plugin) {\n\t\t\tconsole.warn(\n\t\t\t\t'The plugin ' +\n\t\t\t\t\tname +\n\t\t\t\t\t' has not been defined. Cannot invoke `' +\n\t\t\t\t\tmethodName +\n\t\t\t\t\t'` that which does not exist.',\n\t\t\t);\n\t\t} else if (plugin.length) {\n\t\t\t_.each(\n\t\t\t\tplugin,\n\t\t\t\tfunction(p) {\n\t\t\t\t\tinvokePluginMethod(p, $el, methodName, args);\n\t\t\t\t},\n\t\t\t\tthis,\n\t\t\t);\n\t\t} else {\n\t\t\tinvokePluginMethod(plugin, $el, methodName, args);\n\t\t}\n\n\t\t// Chain to public methods\n\t\treturn publicMethods;\n\t}\n\n\t/**\n\t * Destroy a plugin instance (if created)\n\t * @method\n\t * @private\n\t * @param {object} plugin Plugin object (with options and instance etc)\n\t * @param {element} $el Element to destroy plugin on\n\t */\n\tfunction destroyPlugin(plugin, $el) {\n\t\t// Destroy helper\n\t\tfunction _destroy(instance) {\n\t\t\tif (instance) {\n\t\t\t\t// Allow for a user defined destroy method callback\n\t\t\t\t// The instance gets passed as the only argument to the callback\n\t\t\t\tif (plugin.destroyMethod && _.isFunction(plugin.destroyMethod)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tplugin.destroyMethod.call(view, instance);\n\t\t\t\t\t} catch (ex) {}\n\t\t\t\t}\n\t\t\t\t// Allow for a user defined destroy method string (the name of the method on the plugin differs from 'destroy')\n\t\t\t\telse if (\n\t\t\t\t\tplugin.destroyMethod &&\n\t\t\t\t\t_.isFunction(instance[plugin.destroyMethod])\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinstance[plugin.destroyMethod]();\n\t\t\t\t\t} catch (ex) {}\n\t\t\t\t}\n\t\t\t\t// Classic destruction\n\t\t\t\telse if (_.isFunction(instance.destroy)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Some plugins do not play by the rules *cough* jQuery.sortable *cough*\n\t\t\t\t\t\tif (instance instanceof jQuery) {\n\t\t\t\t\t\t\tinstance[plugin.name]('destroy');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinstance.destroy();\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (ex) {}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Have a plugin and it has an instance(s)\n\t\tif (plugin && plugin.instance) {\n\t\t\t// We want to destroy a specific instance\n\t\t\tif ($el && _.isArray(plugin.instance)) {\n\t\t\t\t// Get the index of our instance\n\t\t\t\tvar idx = _.indexOf(\n\t\t\t\t\tplugin.instance,\n\t\t\t\t\t$el.data(plugin.dataAlias || plugin.name),\n\t\t\t\t);\n\t\t\t\tif (idx > -1) {\n\t\t\t\t\t_destroy(plugin.instance[idx]);\n\t\t\t\t\tplugin.instance.splice(idx, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// We want to destroy all instances\n\t\t\telse {\n\t\t\t\t// This has multiple instances\n\t\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\t\t_.each(plugin.instance, _destroy);\n\t\t\t\t}\n\t\t\t\t// Just a single instance\n\t\t\t\telse {\n\t\t\t\t\t_destroy(plugin.instance);\n\t\t\t\t}\n\t\t\t\tdelete plugin.instance;\n\t\t\t}\n\t\t} else {\n\t\t\t// Let them know there was no instance to destroy?\n\t\t}\n\t}\n\t/**\n\t * Initialize a plugin instance\n\t * This returns a promise in case there is anything async we need to do before the plugin can be initialized\n\t * Upon successful initialization we (helpfully) pass back the new plugin instance\n\t * @method\n\t * @private\n\t * @param {object} plugin Plugin object (with options and instance etc)\n\t * @param {element} $el Element to initialize plugin on\n\t * @param {object} options Instance specific options (additional options that will get applied on top of any previosuly defined global options for the plugin init)\n\t *\n\t * @return {array|object} Plugin instance(s)\n\t */\n\tfunction initializePlugin(plugin, $el, options) {\n\t\tvar d = new $.Deferred();\n\t\t// If an $el was not specified assume this view's $el\n\t\t$el = $($el) || view.$el;\n\t\t// Make sure we:\n\t\t// Have a plugin\n\t\t// And that plugin has a name\n\t\t// And that we have an element to initialize the plugin on\n\t\tif (plugin && plugin.name && $el.length) {\n\t\t\t// If an instance already exists, destroy it\n\t\t\tif (plugin.instance) {\n\t\t\t\tdestroyPlugin(plugin, $el);\n\t\t\t}\n\t\t\t// If the plugin can have mutliple instances, `plugin.instance` needs to be an array\n\t\t\tif (plugin.multiple && !_.isArray(plugin.instance)) {\n\t\t\t\tplugin.instance = [];\n\t\t\t}\n\n\t\t\t// TODO: when we refactor actions to have more broken out methods we will not need to recreate the tests here\n\t\t\t// If user level is defined and the user level is not met - invalid\n\t\t\tvar valid = !(\n\t\t\t\t!_.isUndefined(plugin.userLevel) &&\n\t\t\t\tNetx.getUserLevel() < plugin.userLevel\n\t\t\t);\n\t\t\t// Check against any enablerTests\n\t\t\tif (valid && plugin.enablerTest) {\n\t\t\t\tvar tests = _.isArray(plugin.enablerTest)\n\t\t\t\t\t? plugin.enablerTest\n\t\t\t\t\t: [plugin.enablerTest];\n\t\t\t\t_.each(\n\t\t\t\t\ttests,\n\t\t\t\t\tfunction(t) {\n\t\t\t\t\t\tif (valid && _.isFunction(t)) valid = t(view);\n\t\t\t\t\t},\n\t\t\t\t\tview,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If we are still good - initialize plugin\n\t\t\tif (valid) {\n\t\t\t\tvar instances;\n\t\t\t\t// Allow for a user defined intialize method callback\n\t\t\t\t// We pass the plugin object, the element, options and our deferred\n\t\t\t\t// It is the responsibility of the custom initializeMethod:\n\t\t\t\t// To store the instance (via push if mutliple)\n\t\t\t\t// To resolve the deferred and pass back the new instance\n\t\t\t\tif (_.isFunction(plugin.initializeMethod)) {\n\t\t\t\t\tif (plugin.multiple) {\n\t\t\t\t\t\tvar promises = [];\n\t\t\t\t\t\t\n\t\t\t\t\t\tinstances = [];\n\t\t\t\t\t\t_.each($el, function(_el) {\n\t\t\t\t\t\t\tvar p = new $.Deferred();\n\t\t\t\t\t\t\tpromises.push(p);\n\t\t\t\t\t\t\t// We pass the plugin object\n\t\t\t\t\t\t\tplugin.initializeMethod.call(\n\t\t\t\t\t\t\t\tview,\n\t\t\t\t\t\t\t\tplugin,\n\t\t\t\t\t\t\t\t$(_el),\n\t\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\t\tfunction(instance) {\n\t\t\t\t\t\t\t\t\tinstances.push(instance);\n\t\t\t\t\t\t\t\t\tp.resolve();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t$.when.apply($, promises).then(function() {\n\t\t\t\t\t\t\t// Concat multiple instances\n\t\t\t\t\t\t\tplugin.instance = plugin.instance.concat(instances);\n\t\t\t\t\t\t\t// Resolve and pass instances back\n\t\t\t\t\t\t\td.resolveWith(view, [instances]);\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tplugin.initializeMethod.call(view, plugin, $el, options, function(\n\t\t\t\t\t\t\tinstance,\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tplugin.instance = instance;\n\t\t\t\t\t\t\td.resolveWith(view, [instance]);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Classic init\n\t\t\t\telse {\n\t\t\t\t\t// DAM-6666: S2 demands we update our templates all over creation, but at least now we get a warning.\n\t\t\t\t\tif (plugin.name == 'select2' && !$el.is('select')) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'applying select2 to non-SELECT element -- this will not work.',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif ($el[0]) {\n\t\t\t\t\t\t\tconsole.log($el[0]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvar pluginReturn;\n\t\t\t\t\t// Assume it some oddball plugin, like typeahead, that wants multiple parameters and not just a single object\n\t\t\t\t\tif (_.isArray(options)) {\n\t\t\t\t\t\tpluginReturn = $el[plugin.name].apply($el, options);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Extend the passed options on top of the default options (defined vie `Register` or `Extend`)\n\t\t\t\t\t\tpluginReturn = $el[plugin.name](\n\t\t\t\t\t\t\t_.extend({}, plugin.options || {}, options || {}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (plugin.multiple) {\n\t\t\t\t\t\tinstances = _.map($el, function(_el) {\n\t\t\t\t\t\t\tvar _$el = $(_el);\n\t\t\t\t\t\t\t// Fallback on the _el if data is not found\n\t\t\t\t\t\t\treturn _$el.data(plugin.dataAlias || plugin.name) || _$el;\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Concat multiple instances\n\t\t\t\t\t\tplugin.instance = plugin.instance.concat(instances);\n\t\t\t\t\t\t// Resolve and pass instances back\n\t\t\t\t\t\td.resolveWith(view, [instances]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Set single instance\n\t\t\t\t\t\t// Fallback on the return of the plugin initialize if data is not found\n\t\t\t\t\t\tplugin.instance =\n\t\t\t\t\t\t\t$el.data(plugin.dataAlias || plugin.name) || pluginReturn;\n\t\t\t\t\t\td.resolveWith(view, [plugin.instance]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Invalid\n\t\t\t\td.reject();\n\t\t\t}\n\t\t} else {\n\t\t\t// Let them know things are missing?\n\t\t\td.reject();\n\t\t}\n\t\treturn d.promise();\n\t}\n\t/**\n\t * Invoke a plugin instance method (if created)\n\t * @method\n\t * @private\n\t * @param {object} plugin Plugin object (with options and instance etc)\n\t * @param {element} $el Element to invoke the plugin method on\n\t * @param {mixed} args Anything to pass to the update method\n\t */\n\tfunction invokePluginMethod(plugin, $el, methodName, args) {\n\t\t// Invoke helper\n\t\tfunction _invoke(instance) {\n\t\t\tinstance &&\n\t\t\t\t_.isFunction(instance[methodName]) &&\n\t\t\t\tinstance[methodName].apply(instance, args);\n\t\t}\n\n\t\tif (plugin && plugin.instance) {\n\t\t\t// We want to update a specific instance\n\t\t\tif ($el) {\n\t\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\t\tvar idx = _.indexOf(\n\t\t\t\t\t\tplugin.instance,\n\t\t\t\t\t\t$el.data(plugin.dataAlias || plugin.name),\n\t\t\t\t\t);\n\t\t\t\t\tidx > -1 && _invoke(plugin.instance[idx]);\n\t\t\t\t} else {\n\t\t\t\t\t_invoke(plugin.instance);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\t\t_.each(plugin.instance, _invoke);\n\t\t\t\t} else {\n\t\t\t\t\t_invoke(plugin.instance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * Update a plugin instance (if created)\n\t * @method\n\t * @private\n\t * @param {object} plugin Plugin object (with options and instance etc)\n\t * @param {element} $el Element to update the plugin on\n\t * @param {mixed} args Anything to pass to the update method\n\t */\n\tfunction updatePlugin(plugin, $el, args) {\n\t\t// Update helper\n\t\tfunction _update(instance) {\n\t\t\tif (instance) {\n\t\t\t\t// Support for custom update method name\n\t\t\t\tif (\n\t\t\t\t\tplugin.updateMethod &&\n\t\t\t\t\t_.isFunction(instance[plugin.updateMethod])\n\t\t\t\t) {\n\t\t\t\t\tinstance[plugin.updateMethod].apply(instance, args);\n\t\t\t\t}\n\t\t\t\t// Default update method\n\t\t\t\telse if (_.isFunction(instance.update)) {\n\t\t\t\t\tinstance.update.apply(instance, args);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar instance, idx;\n\t\tif (plugin && plugin.instance) {\n\t\t\t// We want to update an instance on a specific $el\n\t\t\tif ($el) {\n\t\t\t\t// An array of instances (multiple)\n\t\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\t\t// Find specific instance of $el plugin in instances\n\t\t\t\t\tidx = _.indexOf(\n\t\t\t\t\t\tplugin.instance,\n\t\t\t\t\t\t$el.data(plugin.dataAlias || plugin.name),\n\t\t\t\t\t);\n\t\t\t\t\tidx > -1 && _update(plugin.instance[idx]);\n\t\t\t\t}\n\t\t\t\t// Single instance\n\t\t\t\telse {\n\t\t\t\t\t_update(plugin.instance);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// We want tu update the instance regardless of $el\n\t\t\telse {\n\t\t\t\t// An array of instances (multiple)\n\t\t\t\tif (_.isArray(plugin.instance)) {\n\t\t\t\t\t_.each(plugin.instance, _update);\n\t\t\t\t}\n\t\t\t\t// Single instance\n\t\t\t\telse {\n\t\t\t\t\t_update(plugin.instance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Our public methods\n\tpublicMethods = {\n\t\tExtend: Extend,\n\t\tFind: Find,\n\t\tGetInstance: GetInstance,\n\t\tRegister: Register,\n\t\tRemove: Remove,\n\t\t// Methods on the plugin themselves\n\t\tInitialize: Initialize,\n\t\tInvoke: Invoke,\n\t\tDestroy: Destroy,\n\t\tUpdate: Update,\n\t\t// Helper\n\t\tgetAll() {\n\t\t\treturn plugins;\n\t\t},\n\t};\n\n\treturn publicMethods;\n}\n","/**\n * Netx.View is a subclass of Backbone.View, and is the superclass of all other views in Netx.\n * It adds a number of features to Views: asyncronous loading of templates,\n * a pager, preRender() and postRender() hooks, a standard for defining template arguments,\n * a modular system for linking clicks to events (called \"Actions\"), child view nesting,\n * standard show() and hide() methods, and more.\n *\n * @class\n */\n\nimport Backbone from 'backbone';\n\nconst BBView = Backbone.View;\n// Make a View we can extend from in other classes\nclass ES6View {\n\t/** @override */\n\tconstructor(opts) {\n\t\tBBView.apply(this, arguments);\n\t}\n}\n_.extend(ES6View.prototype, BBView.prototype);\nBackbone.ES6View = ES6View;\n\nimport Plugins from './netx-plugins';\n\nimport PagerModel from '@netx/core-app/models/pager';\n\nimport ActionsIconInlineTemplate from '@netx/core-app/templates/menuView-actionIconsInline.html';\nimport AssetDetailActionsTemplate from '@netx/core-app/templates/menuView-assetDetailActions.html';\nimport AttributeColumnsContextMenuTemplate from '@netx/core-app/templates/menuView-attributeColumnsContextMenu.html';\nimport AttributeColumnsContextMenuItemTemplate from '@netx/core-app/templates/menuView-attributeColumnsContextMenuItem.html';\nimport CartBarActionsTemplate from '@netx/core-app/templates/menuView-cartBarActions.html';\nimport ContextTemplate from '@netx/core-app/templates/menuView-context.html';\nimport HeaderActionsTemplate from '@netx/core-app/templates/menuView-headerActions.html';\nimport ListHeaderActionsTemplate from '@netx/core-app/templates/menuView-listHeaderActions.html';\nimport NavTabsTemplate from '@netx/core-app/templates/menuView-navTabs.html';\nimport PodActionsTemplate from '@netx/core-app/templates/menuView-podActions.html';\nimport SidebarTemplate from '@netx/core-app/templates/menuView-sidebar.html';\nimport SidebarActionsTemplate from '@netx/core-app/templates/menuView-sidebarActions.html';\nimport SystemHeaderActionsTemplate from '@netx/core-app/templates/menuView-systemHeaderActions.html';\nimport SystemListTemplate from '@netx/core-app/templates/menuView-systemList.html';\nimport SystemTableActionsTemplate from '@netx/core-app/templates/menuView-systemTableActions.html';\n\nimport {simulateClickBody} from './utils';\nimport {getEnabledActions} from '@netx/core-permissions/properties/actions';\n\n// currently these are the only menu views that can be used\n// but themes can override the templates\nconst MenuTemplates = {\n\tactionIconsInline: ActionsIconInlineTemplate,\n\tassetDetailActions: AssetDetailActionsTemplate,\n\tattributeColumnsContextMenu: AttributeColumnsContextMenuTemplate,\n\tattributeColumnsContextMenuItem: AttributeColumnsContextMenuItemTemplate,\n\tcartBarActions: CartBarActionsTemplate,\n\tcontext: ContextTemplate,\n\theaderActions: HeaderActionsTemplate,\n\tlistHeaderActions: ListHeaderActionsTemplate,\n\tnavTabs: NavTabsTemplate,\n\tpodActions: PodActionsTemplate,\n\tsidebar: SidebarTemplate,\n\tsidebarActions: SidebarActionsTemplate,\n\tsystemHeaderActions: SystemHeaderActionsTemplate,\n\tsystemList: SystemListTemplate,\n\tsystemTableActions: SystemTableActionsTemplate,\n};\n\nclass View extends ES6View {\n\t/** @type {boolean} */\n\tget isView() {\n\t\treturn this.constructor.__isView__;\n\t}\n\n\t/**\n\t * Actions\n\t * Netx Actions are an extensible framework for modules to register their functionality (event names).\n\t * Actions can be added to views by adding 'data-action' attributes to HTML elements in view templates.\n\t * The global Netx.Menus object composes groups of Netx.Action objects into Netx.Menu objects; these\n\t * can be added to templates by adding the 'data-action-context' attribute to elements. ('context' is a deprecated name;\n\t * we now prefer 'menu'.) These are normally rendered as
    elements, but alternate templates can be\n\t * specified via the 'data-template' attribute.\n\t * Views automaticall convert those elements to buttons, menus and other UI elements, which\n\t * then trigger the specified events.\n\t *\n\t * Actions can define Enabler functions and/or a UserLevel to specify when an Action can be fired.\n\t * Actions beyond the user's level are hidden with $.hide(). Actions disabled by a function are\n\t * disabled with $.disable() and given a class -- usually 'disabled', but that\n\t * classname can be overridden by setting action.disabledClass\n\t *\n\t * By default, an action triggers its event with two arguments: the view, and the event object that triggered the action.\n\t * However, an action can define a wrapper (action.wrapper), a function that takes those arguments and returns\n\t * an array containing another set of arguments to trigger the event with. This makes it easier for an action\n\t * to target a general-purpose event handler that may already exist.\n\t * A view can override the wrapper for any of its actions, by setting this.actionWrappers[eventName] to a similar function.\n\t *\n\t * An action that wants to trigger a route instead of an event can specify a 'route' property;\n\t * this can be either a string or a function; the function is passed the action arguments and expected\n\t * to return a string.\n\t *\n\t */\n\n\t/**\n\t * Child View management\n\t *\n\t * this.childView defines a mechanism to let a collection View specify a different child view for its models.\n\t * Backbone operations on the collection (add/remove/set/reset) will be automatically reflected in the view.\n\t * When all child views are rendered, the event 'addedChildViews' is triggered -- on the parent view, not on the dispatcher.\n\t *\n\t * To use child views, specify a childView object similar to this one:\n\t * @memberof View\n\t * @member childView {object}\n\t * @todo update example for view collections\n\t * @example\n\t * childView: {\n\t * // The Netx.View subclass of the child view (or defaults to Netx.View)\n\t * viewClass: 'SomeChildView',\n\t * // jQuery selector for the place in the parent view where the children will be inserted.\n\t * // NOTE: this feature will be deprecated. Instead, label the desired childview element\n\t * // in the template with the className '.nx-childviews'\n\t * target: '#someplace',\n\t * // Can be a number to set the amount of items to insert at a time, before giving the browser a second to catch its breath,\n\t * // or an object that has more details about how to break up the adding of childViews\n\t * breakItUp: {\n\t * // (optional) The amount of items to add in pass\n\t * amount: 50,\n\t * // (optional) The amount of time to delay, in milliseconds, before making the next pass\n\t * delay: 0,\n\t * },\n\t * // operate on a different set than this.collection\n\t * collection: new Netx.Collection([...]),\n\t * // if true, add attribute draggable=\"true\"\n\t * draggable: false,\n\t * // (optional) same thing for href (use on A els)\n\t * href: function( model ){ return '#foo/' + model.id },\n\t * // (optional) function to generate unique id per child from model\n\t * id: function( model ){ return 'foo-' + model.id },\n\t * // (optional) Set max childViews to show\n\t * maxItems: 5,\n\t * // if true, re-render the superview on every add. (Use with caution)\n\t * reset: true,\n\t * // Options passed in the options field of the child view's constructor\n\t * options: {\n\t * tagName: 'div',\n\t * className: 'et etcetera'\n\t * }\n\t * }\n\t */\n\t// get childView() {\n\t// \treturn {};\n\t// }\n\n\t/**\n\t * Events:\n\t * Netx.View both triggers and listens for 'contextmenu' and 'showcontextmenu' events. These are the only default handlers in the events object.\n\t *\n\t * Context Menus:\n\t *\n\t * Child views can use these events to display a context menu, defined by an Netx.Menu that is rendered in the template of a parent view.\n\t * For parent views with lots of child views (such as asset lists) this avoids duplicating the HTML block of the menu for each child view, yielding better performance.\n\t *\n\t * To use context menus on child views, the childView definition should specify a Netx.Menu in a 'data-contextmenu-target' option in its definition, like so:\n\t *\n\t * @example\n\t * // in the parent view's class definition:\n\t *\n\t * childView: {\n\t *\toptions: {\n\t *\t\tattributes: {\n\t *\t\t\t'data-contextmenu-target': 'TheNameOfANetxMenu'\n\t *\t\t}\n\t *\t},\n\t * },\n\t *\n\t * // in the parent view's template:\n\t *\n\t *
      \n\t * @object\n\t * @see {@link Netx.View#findContextMenu|findContextMenu}\n\t */\n\n\t/**\n\t * Loading Classes:\n\t *\n\t * By default, Netx.View adds classes to every view's containing element\n\t * to reflect the state of their models and/or collections:\n\t *\n\t * The HTML5 class 'loading' is added to every view's containing element\n\t * while the view's model is fetched -- or its collection, if it has no model.\n\t *\n\t * If a view's collection is a subclass of Netx.Collections.Assets and is fetching a page chunk,\n\t * it gets the class 'loading-chunk' instead of 'loading'. (Chunk loading\n\t * is used to implement infinite scroll, among other effects.)\n\t *\n\t * If a view's collection finishes fetching and has no models, the view\n\t * gets the class 'no-assets'.\n\t *\n\t * The class 'not-loaded' is added to the view's containing element at init,\n\t * and removed permanently at the first fetch.\n\t *\n\t * CSS styles can use these classes to give users visual feedback on the status of transactions.\n\t *\n\t * this.loadingMethods is an array of strings specifying the backbone.RPC methods that trigger this behavior;\n\t * by default this is the single string \"read\", but child views can modify the array\n\t * to get the same effect on other methods, or delete it to disable this behavior entirely.\n\t *\n\t * When calling an RPC method, if the property 'loadingClasses' is set false in\n\t * the optional Backbone options object, the behavior will be supressed for\n\t * the duration of that RPC method call.\n\t *\n\t * To disable or modify this behavior, add the array 'loadingClassObjects' to the view,\n\t * either in its definition or as an option when instantiated.\n\t * Then, only the objects in that array will be listened to for fetch events.\n\t * (An empty array will disable loading classes completely.)\n\t */\n\n\t/**\n\t * @override\n\t * @param {object} options View options\n\t */\n\tconstructor(opts = {}) {\n\t\t// Sanity check: have we been handed a null or bogus 'el' option?\n\t\t// did we get a valid options.el?\n\t\t// does that element not exist?\n\t\tif (_.isString(opts.el) && !document.querySelector(opts.el)) {\n\t\t\tconsole.warn(\n\t\t\t\t`Could not attach view to DOM: DOM element ${opts.el} does not exist.`,\n\t\t\t);\n\t\t\t// ...so the backbone.view initializer will create a new one.\n\t\t\tdelete opts.el;\n\t\t}\n\n\t\topts.events = {\n\t\t\t// A handler for the contextmenu event\n\t\t\tcontextmenu: 'findContextMenu',\n\t\t\t'click .nx-cancel:first': 'cancel',\n\t\t\t'click [data-nx-control=\"close\"]:first': 'cancel',\n\t\t\t'click .nx-done:first': 'hide',\n\t\t\t// A handler for popout views:\n\t\t\t'click a[data-nx-popout]': 'togglePopout',\n\t\t\t...opts.events,\n\t\t};\n\t\tsuper(opts);\n\n\t\tthis.args = opts.args || [];\n\t\tthis.headerTitle = opts.headerTitle || '';\n\t\tthis.routeMatch = opts.routeMatch;\n\t\tthis.viewSpec = opts.viewSpec;\n\t\tthis.template = opts.template;\n\t\tthis.loadingClassObjects = opts.loadingClassObjects;\n\t\tthis.loadingClassRemoveDelay = opts.loadingClassRemoveDelay || 0;\n\t\tthis.listenToCollection = opts.listenToCollection;\n\t\tthis.modalOptions = opts.modalOptions || {};\n\t\tthis.properties = opts.properties || {};\n\t\tthis.removeOnHide = opts.removeOnHide === true;\n\t\tthis.removeOnSimpleHide = opts.removeOnSimpleHide !== false;\n\t\tthis.requireSync = opts.requireSync === true;\n\t\tthis.showLoadingOnce = opts.showLoadingOnce === true;\n\t\tthis._loadedOnce = false;\n\n\t\t//opts.childView && ChildViews(this, opts.childView);\n\n\t\t// Debounced/throttled methods\n\t\t// Debounced render for listeners\n\t\t// We are doing this in a lot of views - until we find something better (since we cannot debounce the actual render method):\n\t\tthis.debouncedRender = _.debounce(this.render, 100);\n\n\t\tthis.configureSubmenus = _.debounce(this.configureSubmenus, 100);\n\n\t\t// Keep track of how many views we maintain:\n\t\tNetx.viewStats = Netx.viewStats || {};\n\t\tNetx.viewStats[this.constructor.__name__] =\n\t\t\t(Netx.viewStats[this.constructor.__name__] || 0) + 1;\n\n\t\t/**\n\t\t * this.subViews is an array where any view can manually place a reference to a subview. The promise returned by\n\t\t * have finished rendering. Calls to this.remove() will recursively call all those views.\n\t\t */\n\t\tthis.subViews = {};\n\n\t\t/**\n\t\t * Template Variables.\n\t\t *\n\t\t * By default, if this.model is defined in a template, all of that model's attributes will be available as template variables.\n\t\t * Otherwise, if this.collection is defined, all properties of the collection object will be made into template variables.\n\t\t *\n\t\t * Furthermore, if the view does not override this.doTemplate(), any/every other key/value added to the object this.templateVars\n\t\t * will be translated into additional template variables for the view. This is an easy way to add extra template variables\n\t\t * and is good enough in most situations.\n\t\t *\n\t\t * if this.templateVars is defined as a function, the function will be expected to return an object, which will then be converted to variables.\n\t\t */\n\t\tthis.templateVars = this.templateVars || {};\n\n\t\t// Plugin manager\n\t\tif (!this.Plugins || !(this.Plugins instanceof Plugins)) {\n\t\t\tthis.Plugins = new Plugins(this);\n\t\t}\n\n\t\t// Some plugins that get used a lot\n\t\tthis.Plugins.Register({\n\t\t\tresizeListener: {\n\t\t\t\tname: 'resize',\n\t\t\t\tinitializeMethod: function (pluginObj, $pluginEl, initOpts, cb) {\n\t\t\t\t\t$pluginEl.resize(_.bind(this.resize, this));\n\t\t\t\t\t// This is an odd little plugin - but helpful\n\t\t\t\t\tcb({\n\t\t\t\t\t\tel: $pluginEl,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tdestroyMethod: function (instance) {\n\t\t\t\t\t// Again, an odd (but helpful) plugin\n\t\t\t\t\tinstance.el[0].__resizeTriggers__ && instance.el.removeResize(null);\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\t/**\n\t\t * @type {string}\n\t\t */\n\t\tthis.i18nCountStr =\n\t\t\topts.i18nCountStr !== false ? opts.i18nCountStr || 'i18n.nItems' : false;\n\t\t/** @type {boolean} */\n\t\tthis.isRouted = opts.isRouted === true;\n\t\t/**\n\t\t * Set a delay on the removal of loading classes\n\t\t * Especially useful in views where we debounce renders on sync\n\t\t * @type {number}\n\t\t * @default\n\t\t */\n\t\tthis.loadingClassRemoveDelay = opts.loadingClassRemoveDelay || 0;\n\n\t\t/**\n\t\t * RPC methods to listen for loading on\n\t\t * @type {array}\n\t\t */\n\t\tthis.loadingMethods = opts.loadingMethods || ['read'];\n\n\t\t/**\n\t\t * Normally, a route change clears all modal windows.\n\t\t * If the stickyModal flag is set on a modal view, the view will remain\n\t\t * on screen through route changes.\n\t\t * This will automatically be set to true if a view has `modalOptions.blocking` set to `true`\n\t\t * @type {boolean}\n\t\t * @see {@link Netx.View#isMyRoute|isMyRoute}\n\t\t */\n\t\tthis.stickyModal = opts.stickyModal === true;\n\n\t\t/**\n\t\t * What to extend data from when we run doTemplate\n\t\t * If left unset it defaults to standard behavior - we check for `this.model`, `this.collection`, and lastly, fallback to `this`\n\t\t * @type {object}\n\t\t * @default\n\t\t */\n\t\t// this.templateDataSource = opts.templateDataSource || {};\n\n\t\t/**\n\t\t * A Deferred object that resolves when this view finishes rendering.\n\t\t * This is a Deferred object, and is resolved after the first render.\n\t\t * @deprecated 2016-07-01 - Left for legacy as no longer are we deferred thanks to pre-compiling our templates\n\t\t * @type {object}\n\t\t */\n\t\t// TODO: Is this really deprecated yet? It's still used in a lot of code,\n\t\t// and it does have the effect of postponing thing until a view's first render....\n\t\tthis.rendered = new $.Deferred();\n\n\t\t////////////////////////////////////////\n\t\t// SHOWN/HIDDEN PROMISES\n\t\t////////////////////////////////////////\n\t\t// Initial shown/hidden promises\n\t\tthis._hiddenDeferred = new $.Deferred();\n\t\tthis.whenHidden = this._hiddenDeferred.promise();\n\t\tthis._shownDeferred = new $.Deferred();\n\t\tthis.whenShown = this._shownDeferred.promise();\n\t\t////////////////////////////////////////\n\t\t// !SHOWN/HIDDEN PROMISES\n\t\t////////////////////////////////////////\n\n\t\t// Bind\n\t\tthis.bindCollectionEvents().bindModelEvents();\n\n\t\t// Hey, listen!\n\t\tthis\n\t\t\t// listen for model & collection changes\n\t\t\t.listenTo(this, 'setModel', this.setModel)\n\t\t\t.listenTo(this, 'setCollection', this.setCollection)\n\t\t\t// Listen for showing/shown hiding/hidden events\n\t\t\t.listenTo(this, 'hiding', this.onHiding)\n\t\t\t.listenTo(this, 'hidden', this.afterHidden)\n\t\t\t.listenTo(this, 'showing', this.onShowing)\n\t\t\t.listenTo(this, 'shown', this.afterShown)\n\t\t\t// On hidden create new promise for shown\n\t\t\t.listenTo(this, 'hiddenByProxy', () => {\n\t\t\t\tif (!this.removing && !this.hiding && !this.showing) {\n\t\t\t\t\t// If we were visible at the time\n\t\t\t\t\tif (this.isShown) {\n\t\t\t\t\t\tthis.hiddenByProxy = true;\n\t\t\t\t\t\tthis.afterHidden(this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.shownByProxy = false;\n\t\t\t})\n\t\t\t// On shown create new promise for hidden\n\t\t\t.listenTo(this, 'shownByProxy', () => {\n\t\t\t\tif (!this.removing && !this.hiding && !this.showing) {\n\t\t\t\t\tif (this.isShown || this.hiddenByProxy) {\n\t\t\t\t\t\tthis.shownByProxy = true;\n\t\t\t\t\t\tthis.afterShown(this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.hiddenByProxy = false;\n\t\t\t});\n\n\t\t// Set up any additonal functionality\n\t\tconst __initializers__ = this.constructor.__initializers__ || [];\n\t\t__initializers__.forEach((func) => func(this, opts));\n\n\t\t// Add loading classes\n\t\t// Adding in render gets into to timing issues with lsiteners and repsonses\n\t\t// should a request be in progress\n\t\tthis.addLoadingClasses_internal();\n\t}\n\n\t/**\n\t * Adds loading classes to the the view container\n\t * @method\n\t * @private\n\t */\n\taddLoadingClasses_internal() {\n\t\t// NOTE: no way to check options here for loadingClasses === false.\n\n\t\tif (!this.loadingMethods || !this.loadingMethods.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet showNotLoaded = false;\n\t\tlet thingSyncing;\n\n\t\tconst loadingClassObjects = this.loadingClassObjects || [];\n\n\t\t// First loop over any defined loading class objects and check if they are currently syncing\n\t\tif (loadingClassObjects.length) {\n\t\t\tloadingClassObjects.forEach((item) => {\n\t\t\t\tif (_.isString(item) && this[item] && this[item].isSyncing) {\n\t\t\t\t\tthingSyncing = this[item];\n\t\t\t\t} else if (_.isObject(item) && item.isSyncing) {\n\t\t\t\t\tthingSyncing = item;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// TODO: this.model.isSyncing could contain complete sync info instead of a boolean ....\n\t\t// If nothing already syncing and view is not tied to a collection and it has a model that is syncing\n\t\tif (\n\t\t\t!thingSyncing &&\n\t\t\t!this.collection &&\n\t\t\tthis.model &&\n\t\t\tthis.model.isSyncing\n\t\t) {\n\t\t\tthingSyncing = this.model;\n\t\t}\n\t\t// Have we found anything syncing yet, if not check this.collection\n\t\telse if (!thingSyncing && this.collection && this.collection.isSyncing) {\n\t\t\tthingSyncing = this.collection;\n\t\t}\n\t\t// Either the collection has never synced or the model is new - nothing loaded\n\t\telse if (\n\t\t\t(!this.collection && this.model && this.model.isNew()) ||\n\t\t\t(this.collection && this.collection.syncedOnce !== true)\n\t\t) {\n\t\t\tshowNotLoaded = true;\n\t\t}\n\n\t\tconst thingListener = (thingRequesting, xhr, opts) => {\n\t\t\t// Prevent models from triggering request events on collections, unless a model is specified in loadingClassObjects\n\t\t\tif (\n\t\t\t\t(thingRequesting.isModel && loadingClassObjects.includes('model')) ||\n\t\t\t\t(thingRequesting.isCollection &&\n\t\t\t\t\tloadingClassObjects.includes('collection'))\n\t\t\t) {\n\t\t\t\tthis.showLoading(thingRequesting, xhr, opts);\n\t\t\t}\n\t\t};\n\n\t\t// This function adds to some Backbone object the listeners for adding & removing the loading classes\n\t\tconst addListeners = (thing) => {\n\t\t\tif (!thing || !thing._listenId) return;\n\n\t\t\t_.each(this.loadingMethods, (arg) => {\n\t\t\t\tthis.stopListening(thing, `request:${arg}`, thingListener).listenTo(\n\t\t\t\t\tthing,\n\t\t\t\t\t`request:${arg}`,\n\t\t\t\t\tthingListener,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tthis.stopListening(thing, 'sync', this.showLoaded).listenTo(\n\t\t\t\tthing,\n\t\t\t\t'sync',\n\t\t\t\tthis.showLoaded,\n\t\t\t);\n\t\t};\n\n\t\t// We have a syncing model or collection\n\t\tif (thingSyncing) {\n\t\t\t// if addLoadingClasses is called while the model/collection is fetching, reflect that immediately.\n\t\t\tthis.showLoading(thingSyncing);\n\t\t\taddListeners(thingSyncing);\n\t\t}\n\t\t// Nothing loaded\n\t\telse if (showNotLoaded) {\n\t\t\tthis.showNotLoaded();\n\t\t}\n\t\t// We must already have all we need to be considered \"loaded\"\n\t\telse {\n\t\t\t// TODO: need to include the loadingclassobjects some how\n\t\t\t// we were getting false positives before on no-assets because showLoaded needs\n\t\t\t// a `thing` to reference to make sure we are not adding classes based on some rogue\n\t\t\t// thing that may have been syncing at one time - really we need to sit down and\n\t\t\t// discusss this as there are a lot of problems with our current approach\n\t\t\t// Everything appeared to work so brilliantly when we had a template lag >.<\n\t\t\tthis.showLoaded(this.collection || this.model, null, {noDelay: true});\n\t\t}\n\n\t\t// What should we listen on?\n\t\t// if this.loadingClassObjects is set, use the objects it points to.\n\t\tloadingClassObjects.forEach((item) => {\n\t\t\tlet thingToListenTo;\n\t\t\tif (_.isString(item)) {\n\t\t\t\tif (!_.isUndefined(this[item])) {\n\t\t\t\t\tthingToListenTo = this[item];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthingToListenTo = item;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!thingSyncing ||\n\t\t\t\tthingSyncing._listenId !== thingToListenTo._listenId\n\t\t\t) {\n\t\t\t\taddListeners(thingToListenTo);\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add a pager to this collection view\n\t * @param {Netx.Collection} c Netx.Collection instance -- defaults to this.collection\n\t */\n\taddPagerView(c) {\n\t\tc = c || this.collection;\n\t\tif (!c) {\n\t\t\tconsole.warn('cant add pager to view without a collection!');\n\t\t\treturn;\n\t\t}\n\n\t\tconst pagers = this.$('[data-nx-pager]');\n\t\tif (pagers.length > 1) {\n\t\t\t// ALERT! Sensitivity training error! Report to HR for reprogramming!\n\t\t\t//console.error( 'To many pager Daniel-san! Only one `data-nx-pager` element per template.' );\n\t\t\tconsole.warn('Only one `data-nx-pager` element allowed per template.');\n\t\t} else if (pagers.length === 0) {\n\t\t\tconsole.warn('Cant find a `data-nx-pager` element in template.');\n\t\t} else {\n\t\t\tif (this.pagerView) {\n\t\t\t\tthis.removeSubView(this.pagerView, true);\n\t\t\t}\n\t\t\timport(\n\t\t\t\t/* webpackChunkName: \"view-pagerView\" */ '@netx/core-app/views/pagerView'\n\t\t\t).then((PagerView) => {\n\t\t\t\tconst $pager = pagers[0];\n\t\t\t\tthis.pagerView = new PagerView.default({\n\t\t\t\t\tcollection: c,\n\t\t\t\t\tmodel: c.pager || new PagerModel(),\n\t\t\t\t});\n\t\t\t\tthis.addSubView(this.pagerView);\n\t\t\t\tthis.pagerView.setElement($pager).render();\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Add any old view as a 'subview' to this view. It will be stored in this.subViews{} using view.cid as the key.\n\t * This view will manage the subview's life cycle, destroying it when this view is destroyed,\n\t * and this view's render promise will not resolve until all subviews are also done rendering.\n\t * All other management (like triggering render) must be handled by the parent view.\n\t *\n\t * Unlike this.childViews{}, this.subViews{} is totally seperate from the child view system for collections & their models.\n\t * Views in this.subViews{} are not destroyed in the render cycle.\n\t * @method\n\t * @param {Netx.View} v\n\t * @returns {Netx.View} view Sub view\n\t */\n\taddSubView(v) {\n\t\tthis.subViews[v.cid] = v;\n\t\treturn v;\n\t}\n\n\t/**\n\t * Everything has happend in the core hiding of this view\n\t * Executes just before `whenHidden` is resolved\n\t * @method\n\t * @listens Netx.View#hidden\n\t */\n\tafterHidden(view) {\n\t\tif (view !== this || this.removing) {\n\t\t\treturn;\n\t\t}\n\t\t// Set the appropriate hidden stuff\n\t\tthis.hiding = false;\n\t\tthis.isShown = false;\n\n\t\tthis.el.removeAttribute('data-nx-hiding');\n\t\tthis.el.removeAttribute('data-nx-showing');\n\t\t// this.$el.removeClass('showing hiding');\n\n\t\tif (this.viewSpec) {\n\t\t\tthis.$el.removeClass('active');\n\t\t}\n\n\t\tif (this.whenHidden.state() === 'pending') {\n\t\t\tthis._hiddenDeferred.resolveWith(this);\n\t\t}\n\t\tif (this.whenShown.state() === 'pending') {\n\t\t\tthis._shownDeferred.reject();\n\t\t}\n\n\t\t_.invoke(this.subViews, 'trigger', 'hiddenByProxy', this);\n\n\t\t_.defer(() => {\n\t\t\t// New shown promise\n\t\t\tthis._shownDeferred = new $.Deferred();\n\t\t\tthis.whenShown = this._shownDeferred.promise();\n\t\t});\n\t}\n\n\t/**\n\t * Everything has happend in the core showing of this view\n\t * Executes just before `whenShown` is resolved\n\t * @method\n\t * @listens Netx.View#shown\n\t */\n\tafterShown(view) {\n\t\tif (view !== this || this.removing) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set the appropriate shown stuff\n\t\tthis.isShown = true;\n\t\tthis.showing = false;\n\n\t\tthis.el.removeAttribute('data-nx-hiding');\n\t\tthis.el.removeAttribute('data-nx-showing');\n\t\tthis.$el.removeClass('showing hiding');\n\n\t\tif (this.viewSpec) {\n\t\t\tthis.$el.addClass('active');\n\t\t}\n\n\t\tif (this.whenShown.state() === 'pending') {\n\t\t\tthis._shownDeferred.resolveWith(this);\n\t\t}\n\t\tif (this.whenHidden.state() === 'pending') {\n\t\t\tthis._hiddenDeferred.reject();\n\t\t}\n\n\t\t_.invoke(this.subViews, 'trigger', 'shownByProxy', this);\n\n\t\t_.defer(() => {\n\t\t\t// New hidden promise\n\t\t\tthis._hiddenDeferred = new $.Deferred();\n\t\t\tthis.whenHidden = this._hiddenDeferred.promise();\n\t\t});\n\t}\n\n\t/**\n\t * This is where the any animation should happen\n\t * When the callback is executed the app considers this view as good as hidden\n\t * @method\n\t * @param {function} cb Callback\n\t * @see Netx.View#hide\n\t */\n\tbeforeHidden(cb) {\n\t\tthis.el.style.display = 'none';\n\t\tcb.apply(this);\n\t}\n\n\t/**\n\t * This is where the any animation should happen\n\t * When the callback is executed the app considers this view as good as shown\n\t * @method\n\t * @param {function} cb Callback\n\t * @see Netx.View#show\n\t */\n\tbeforeShown(cb) {\n\t\tthis.el.style.display = '';\n\t\tcb.apply(this);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbindCollectionEvents() {\n\t\tconst collection = this.listenToCollection || this.collection;\n\t\tif (!collection) return this;\n\n\t\tthis.trigger('bindCollectionEventsHook', this);\n\n\t\treturn this.listenTo(collection, 'reset add remove', () => {\n\t\t\tthis.collectionUpdated(collection);\n\t\t})\n\t\t\t.listenTo(collection, 'sync', (thing) => {\n\t\t\t\tif (thing !== collection) return;\n\t\t\t\tthis.collectionUpdated(collection);\n\t\t\t})\n\t\t\t.listenTo(collection, 'updatedTotal', this.collectionUpdated);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbindEvents() {\n\t\tthis.unbindEvents();\n\n\t\t// DAM-13638\n\t\tif (/iphone|ipad|ipod/i.test(navigator.userAgent)) {\n\t\t\tconst menuName = this.$el.data('contextmenu-target');\n\t\t\tif (!menuName) return this;\n\n\t\t\tif (!this.hammer) {\n\t\t\t\tthis.hammer = new Hammer(this.el);\n\t\t\t}\n\n\t\t\tthis.hammer.on('press', (e) => {\n\t\t\t\t// e.preventDefault();\n\t\t\t\tthis.findContextMenu(e.srcEvent);\n\t\t\t});\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbindModelEvents() {\n\t\tif (!this.model) return this;\n\n\t\treturn this.trigger('bindModelEventsHook', this);\n\t}\n\n\t/**\n\t * A helper method for dealing with large arrays or objects of data\n\t * We can set a slight delay to allow the update of progress (etc) and not just have a locked up browser\n\t * @method\n\t * @param {object} options Options (like size, amount, start, delay)\n\t * @param {function} processCallback Is called on each iteration and passes the current index\n\t * @param {function} completeCallback Is called when all iterations are complete - return data here\n\t */\n\tbreakItUp(options, processCallback, completeCallback) {\n\t\t// Helpers\n\t\tconst d = new $.Deferred();\n\n\t\t// Vars\n\t\tvar start = _.isUndefined(options.start) ? 0 : options.start,\n\t\t\tidx = 0,\n\t\t\tamount = options.amount || 10,\n\t\t\tincrement = options.increment || 1,\n\t\t\tsize = options.size,\n\t\t\tdelay = options.delay || 2,\n\t\t\tself = this;\n\n\t\t// I am trying this out so that we might be able to give some progress indication in the event that\n\t\t// we are trying to edit a whole lot of cells (so the screen isn't just locked up)\n\t\tvar brokenUp = function (start, amt) {\n\t\t\t// No delay on first call\n\t\t\tidx === 0 ? process(start, amt) : setTimeout(process, delay, start, amt);\n\t\t};\n\t\t// So we are not creating a new anonymouse function each chunk we iterate over (delays and all)\n\t\tvar process = function (start, amt) {\n\t\t\t// Vars\n\t\t\tvar end, processed;\n\n\t\t\t// Keep in bounds\n\t\t\tif (start < 0) start = 0;\n\t\t\tend = start + amount;\n\t\t\tif (end > size) end = size;\n\n\t\t\tvar c, i;\n\t\t\t// Process\n\t\t\tfor (i = start, c = end; i < c; i += increment) {\n\t\t\t\t// Return false in your process callback to end the loop and just fire the complete callback\n\t\t\t\tprocessed = processCallback.call(self, i);\n\t\t\t\tidx++;\n\t\t\t\tif (processed === false) break;\n\t\t\t}\n\n\t\t\t// Next\n\t\t\tif (processed !== false && i <= size - 1) {\n\t\t\t\tbrokenUp(i, amount);\n\t\t\t}\n\t\t\t// Finished\n\t\t\telse {\n\t\t\t\td.resolveWith(self, [\n\t\t\t\t\t_.isFunction(completeCallback) ? completeCallback.call(self) : null,\n\t\t\t\t]);\n\t\t\t}\n\t\t};\n\t\t// Start\n\t\tbrokenUp(start, amount);\n\n\t\treturn d.promise();\n\t}\n\n\t/**\n\t * @method\n\t * @param {event} e jQueryEvent\n\t */\n\tcancel(e) {\n\t\tif (e && e.preventDefault) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}\n\n\t\tthis.trigger('cancelled', this);\n\t\tthis.hide();\n\n\t\tif (this.eventStr) {\n\t\t\tdispatcher.trigger(\n\t\t\t\t`${this.eventStr}:cancelled`,\n\t\t\t\tthis.model || this.collection,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Differntiate between having `no-assets` and having `no-matches`\n\t * @method\n\t */\n\tcheckHasResults() {\n\t\tconst collection = this.listenToCollection || this.collection;\n\t\tif (\n\t\t\t!collection ||\n\t\t\tcollection.syncing ||\n\t\t\t(this.requireSync && !collection.syncedOnce)\n\t\t)\n\t\t\treturn;\n\n\t\tconst el = this.el;\n\n\t\tel.removeAttribute('data-nx-no-matches'); //removeClass('no-matches');\n\n\t\tif (collection.isFiltered()) {\n\t\t\tel.removeAttribute('data-nx-no-assets');\n\t\t\tel.removeAttribute('data-nx-no-results');\n\t\t\tcollection.length === 0 && el.setAttribute('data-nx-no-matches', true);\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasResults = _.isFunction(this.hasAssets)\n\t\t\t? this.hasAssets()\n\t\t\t: collection.getTotal();\n\t\tif (hasResults) {\n\t\t\tel.removeAttribute('data-nx-no-assets');\n\t\t\tel.removeAttribute('data-nx-no-results');\n\t\t} else {\n\t\t\tel.setAttribute('data-nx-no-assets', true);\n\t\t\tel.setAttribute('data-nx-no-results', true);\n\t\t}\n\t}\n\n\t/**\n\t * Often, a model wants to remove itself from the DOM when its model is removed from a collection.\n\t * checkRemove() is a handler for Backbone \"remove\" events on models, which pass a model, a collection and options.\n\t * It calls .remove() only if the event's collection argument matches this.collection .\n\t * @method\n\t * @param {Backbone.Model} model\n\t * @param {Backbone.Collection) collection\n\t * @param {Object} opts\n\t */\n\tcheckRemove(model, collection, opts) {\n\t\tif (collection == this.collection) {\n\t\t\treturn this.remove();\n\t\t}\n\t}\n\n\t/** @method */\n\tcleanUpActionEvents() {\n\t\t_.forEach(this.actionEvents, (event, action) => {\n\t\t\t_.each(event.els, function (el) {\n\t\t\t\tel.removeEventListener('click', event.func);\n\t\t\t\tel.removeEventListener('keydown', event.func);\n\t\t\t\t$(el).off('tapToClick', event.func);\n\t\t\t});\n\t\t});\n\t\tthis.actionEvents = {};\n\t}\n\n\t/**\n\t * @method\n\t * @param {module:core/lib/netx-collection} collection Collection\n\t */\n\tcollectionUpdated(collection) {\n\t\tconst _collection = this.listenToCollection || this.collection;\n\t\tif (collection !== _collection) return;\n\n\t\tthis.checkHasResults();\n\t\tthis.updateCount();\n\t}\n\n\t/**\n\t * configureActions: for a set of actions, re-test all Enablers and userlevel tests, and enable/disable the Actions as needed.\n\t * This happens automatically with rendering, but can be useful to trigger manually.\n\t * @param {array} actionList the set of actions\n\t * @param {Netx.View} [otherView] operate on a view other than this one.\n\t */\n\tconfigureActions(actionList, otherView) {\n\t\tif (!actionList.length) return;\n\n\t\tconst view = otherView != null ? otherView : this;\n\t\tconst actionOpts =\n\t\t\totherView && otherView !== this ? {targetView: otherView} : undefined;\n\n\t\tconst enabledActions = getEnabledActions(actionList, view);\n\t\tconst disabledActions = actionList.filter(\n\t\t\t(action) => !enabledActions.includes(action),\n\t\t);\n\n\t\tenabledActions.forEach((action) => {\n\t\t\tif (this.$actionEls) {\n\t\t\t\tconst $target = this.$actionEls.filter(\n\t\t\t\t\t`[data-action=\"${action.event}\"]`,\n\t\t\t\t);\n\n\t\t\t\t$target.attr('title', action.label);\n\t\t\t\tthis.enableAction(action, actionOpts);\n\t\t\t}\n\t\t});\n\n\t\tdisabledActions.forEach((action) => {\n\t\t\tif (this.$actionEls) {\n\t\t\t\tconst $target = this.$actionEls.filter(\n\t\t\t\t\t`[data-action=\"${action.event}\"]`,\n\t\t\t\t);\n\n\t\t\t\t$target.attr('title', action.label);\n\t\t\t\tthis.disableAction(action, actionOpts);\n\t\t\t}\n\t\t});\n\n\t\tconst menuActions = this.menuActions;\n\t\t// Reconfigure any menus that need it:\n\t\tlet menusToConfigure = [];\n\t\tactionList.forEach((action) => {\n\t\t\tfor (const menuName in menuActions) {\n\t\t\t\tif (menuActions.hasOwnProperty(menuName)) {\n\t\t\t\t\tmenuActions[menuName].includes(action) &&\n\t\t\t\t\t\t!menusToConfigure.includes(menuName) &&\n\t\t\t\t\t\tmenusToConfigure.push(menuName);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\t// configure each menu once, not once for each menu item\n\t\tmenusToConfigure.forEach((menuName) => {\n\t\t\tthis.configureMenu(menuName);\n\t\t});\n\n\t\t// Super gross\n\t\t// A view containing the menu calls on `this.configureMenu` with the menu it contains\n\t\t// but the menu view is responsible for checking its actions and enabling/disabling them\n\t\t// this can happen after the parent view has already called `this.configureMenu`\n\t\t// There seems to be no reason why a parent view should be handling this since it is trying\n\t\t// to directly control the top level element that is them menu view's el - and it knows\n\t\t// everything that needs to be known about the actions within and itself\n\t\t// Rather than trying to tackle the right way now, holding off for our menu/actiomns refactor\n\t\t// which is greatly needed\n\t\tif (this.isMenuView && this.$el.hasClass('nx-action-context')) {\n\t\t\tthis.configureMenuView(this);\n\t\t}\n\n\t\t// re-initialize backbone's listeners off this.events\n\t\tthis.delegateEvents();\n\n\t\t// done.\n\t\tthis.trigger('configuredActions', actionList);\n\t}\n\n\t/**\n\t * Enable/disable a menu based on whether it contains any enabled actions.\n\t * @method\n\t * @param {module:app/views/menuView} menuView Menu view\n\t * @param {Element} menuEl Menu element (if not specified will use menuView.$el)\n\t */\n\tconfigureMenuView(menuView, $menuEl) {\n\t\t$menuEl = $menuEl || menuView.$el;\n\t\tconst $menuToggle = $menuEl.siblings('[data-toggle=\"dropdown\"]');\n\n\t\t// Check if we have any enabled actions\n\t\tlet allActions = menuView.$('.nx-action');\n\t\tlet disabledActions = menuView.$('.nx-action[disabled]');\n\n\t\t// TODO: maybe there's a bug here:\n\t\t// if a menu has a mix of actions and hrefs,\n\t\t// and one href is the only enabled item,\n\t\t// will this 2-step check work right?\n\t\t//\n\t\t// There should not be, this double checks seems pointless as all things\n\t\t// in a menu are actions and should have a `.nx-action` class -jse-\n\n\t\t// Maybe it is just href based and not data-action\n\t\tif (!allActions.length) {\n\t\t\tallActions = menuView.$('[href]');\n\t\t\tdisabledActions = menuView.$('[href][disabled]');\n\t\t}\n\n\t\t// Configure the menu element: disable if all its actions are disabled.\n\t\t$menuEl.enableIf(disabledActions.length < allActions.length);\n\t\t// If the menu is a dropdown, also configure its toggle.\n\t\t$menuToggle.enableIf(disabledActions.length < allActions.length);\n\n\t\tmenuView.configureSubmenus();\n\t}\n\n\t/**\n\t * Configure menu by name\n\t * @method\n\t * @param {string} menuName Menu name\n\t */\n\tconfigureMenu(menuName) {\n\t\tif (!this.menuViews) {\n\t\t\treturn;\n\t\t} // no menu views yet (something is configuring before we've rendered.)\n\n\t\tvar menuView = this.menuViews[menuName];\n\t\tvar $menuEl = this.$(\n\t\t\t'.nx-action-context[data-action-context=\"' + menuName + '\"]',\n\t\t);\n\t\tif (!menuView || !$menuEl.length) {\n\t\t\t// Let's not be so noisy about it\n\t\t\tconsole.warn(\"Can't find menu \" + menuName);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.configureMenuView(menuView, $menuEl);\n\t}\n\n\t/** @method */\n\tconfigureSyncActions() {\n\t\tthis.configureActions(this.syncActions);\n\t}\n\n\t/** @method */\n\tconfigureUserActions() {\n\t\tthis.configureActions(this.userActions);\n\t}\n\n\t/**\n\t * If we have unsaved changes, confirm that we want to hide\n\t * This method is only automatically called from a `multi-view` world when `hide` is triggered on a top level view (and up for removal)\n\t * For this to fire under any other circumstance requires manually calling where needed\n\t * @return {boolean}\n\t * @fires module:app#app:confirmUnsaved\n\t */\n\tconfirmHide() {\n\t\tconst d = new $.Deferred();\n\t\tlet unsavedView =\n\t\t\t_.isFunction(this.unsavedChanges) && this.unsavedChanges();\n\n\t\tif (unsavedView) {\n\t\t\tdispatcher.trigger('app:confirmUnsaved', {\n\t\t\t\tconfirmed: (...args) => {\n\t\t\t\t\t// Trigger event\n\t\t\t\t\tunsavedView.trigger('nx:unsavedChanges:confirmed');\n\t\t\t\t\t// Resolve with this view (may or may not be the actual unsaved view)\n\t\t\t\t\td.resolveWith(this, [unsavedView].concat(...args));\n\t\t\t\t},\n\t\t\t\tcancelled: (...args) => {\n\t\t\t\t\t// Trigger event\n\t\t\t\t\tunsavedView.trigger('nx:unsavedChanges:cancelled');\n\t\t\t\t\t// Reject and pass the unsaved view\n\t\t\t\t\td.rejectWith(this, [unsavedView].concat(...args));\n\t\t\t\t\t// Show the view in question\n\t\t\t\t\t// Basically, `this.unsavedChanges` returns a view that has unsaved changes - this could be a subView/chilView\n\t\t\t\t\t// If it does return a view other than itself, and this view is a multiView as well, show that view and the higher `multiView` will show this view on reject\n\t\t\t\t\tif (this !== unsavedView && this.isMultiView) {\n\t\t\t\t\t\tthis.isTabView\n\t\t\t\t\t\t\t? this.showTab(unsavedView)\n\t\t\t\t\t\t\t: this.showView(unsavedView);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\td.resolveWith(this);\n\t\t}\n\t\treturn d.promise();\n\t}\n\n\t/**\n\t * disableAction: disables an action. This happens automatically when actions have Enablers.\n\t * @method\n\t * @private\n\t * @param {object} action An Action object, or an event string that identifes a registered Action object\n\t * @param {boolean} [options.redelegate] Should delegateEvents() be called?\n\t */\n\tdisableAction(action, options) {\n\t\tif (_.isString(action)) {\n\t\t\taction = Netx.Actions.Find(action); // convert action name to action object\n\t\t}\n\n\t\tconst $target = this.$actionEls.filter(`[data-action=\"${action.event}\"]`);\n\t\tconst disabledClass = _.isString(action.disabledClass)\n\t\t\t? action.disabledClass\n\t\t\t: 'disabled';\n\n\t\t$target.addClass(disabledClass).disable();\n\n\t\t// if this is the first action and it is disabled, this.actionEvents wont be defined\n\t\tthis.actionEvents = this.actionEvents || {};\n\n\t\tconst actionEvent = this.actionEvents[action.event];\n\t\tif (actionEvent) {\n\t\t\t_.each(actionEvent.els, function (el) {\n\t\t\t\tel.removeEventListener('click', actionEvent.func);\n\t\t\t\t$(el).off('tapToClick', actionEvent.func);\n\t\t\t});\n\t\t\tdelete this.actionEvents[action.event];\n\t\t}\n\n\t\tthis.trigger('disabledAction', action, options);\n\t}\n\n\t/**\n\t * Disable the target element involved in the event\n\t * @method\n\t * @param {event} e Event\n\t */\n\tdisableTarget(e) {\n\t\te && e.target && $(e.target).disable();\n\t}\n\n\t/**\n\t * Netx.View templates are processed by Underscore's _.template() command, which can take various arguments.\n\t * Sub-classes can override this.doTemplate() to specify what arguments are passed to that templating function.\n\t *\n\t * The default implementation is useful; it passes the entire collection (for collection views),\n\t * or all the model attributes (for model views), or the entire view (for views without a model or collection).\n\t * @see {@link Netx.View#render|render}\n\t * @see {@link Netx.View#renderElement|renderElement}\n\t * @method\n\t * @return {object} this\n\t */\n\tdoTemplate() {\n\t\tif (!this.template) return '';\n\t\t// Additional template variables\n\t\t// This is a helper - you will always get the model or collection for free\n\t\t// adding things to this.templateVars will make it so you do not have to override this doTemplate method\n\t\t// If you have a doTemplate override in your view it will be up to you to recreate this functionality or not\n\t\t// The only reason I can see, going forward, to have a custom doTemplate method is if it is absolutely imperative\n\t\t// to not pass the model/collection/view (depending on what is there)\n\t\tlet additionalVars = {};\n\t\tif (_.isFunction(this.templateVars)) {\n\t\t\tadditionalVars = this.templateVars();\n\t\t} else if (_.isObject(this.templateVars)) {\n\t\t\tadditionalVars = _.extend({}, this.templateVars);\n\t\t}\n\n\t\tif (this.model) {\n\t\t\tadditionalVars.isNew = this.model.isNew();\n\t\t}\n\n\t\tlet opts = {};\n\t\t// Defined templateDataSource\n\t\tif (_.isObject(this.templateDataSource)) {\n\t\t\topts = _.extend({}, this.templateDataSource, additionalVars);\n\t\t}\n\t\t// Model view\n\t\telse if (this.model && this.model.attributes) {\n\t\t\topts = _.extend({}, this.model.attributes, additionalVars);\n\t\t}\n\t\t// Collection view\n\t\telse if (this.collection) {\n\t\t\topts = _.extend({}, this.collection.templateProps, additionalVars);\n\t\t}\n\t\t// Generic view\n\t\t// TODO: this needs to go away - if a view has not specified a data source, it gets no data in the template!\n\t\telse {\n\t\t\topts = _.extend({}, this, additionalVars);\n\t\t}\n\n\t\tconst headerTitle = this.headerTitle;\n\t\tif (headerTitle != null && opts.headerTitle == null) {\n\t\t\topts.headerTitle = headerTitle;\n\t\t}\n\t\treturn this.template.call(this, opts);\n\t}\n\n\t/**\n\t * enableAction: enables an action. This happens automatically when actions have Enablers.\n\t * @method\n\t * @private\n\t * @param {} action An Action object, or an event string that identifes a registered Action object\n\t * @param {boolean} [options.redelegate] Should delegateEvents() be called?\n\t * @param {boolean} [options.targetView] Trigger the action on a view other than this one.\n\t */\n\tenableAction(action, options) {\n\t\tif (_.isString(action)) {\n\t\t\taction = Netx.Actions.Find(action); // convert action name to action object\n\t\t}\n\n\t\tconst $target = this.$actionEls.filter(`[data-action=\"${action.event}\"]`);\n\n\t\tconst disabledClass =\n\t\t\ttypeof action.disabledClass === 'string'\n\t\t\t\t? action.disabledClass\n\t\t\t\t: 'disabled';\n\n\t\t$target.removeClass(disabledClass).enable();\n\n\t\t// Add a listener for the action's click events, via the standard Backbone.View events list.\n\t\tthis.events = this.events || {};\n\n\t\tthis.actionEvents = this.actionEvents || {};\n\n\t\tconst actionEvent = this.actionEvents[action.event];\n\n\t\tif (actionEvent) {\n\t\t\t_.each(actionEvent.els, function (el) {\n\t\t\t\tel.removeEventListener('click', actionEvent.func);\n\t\t\t\t$(el).off('tapToClick', actionEvent.func);\n\t\t\t});\n\t\t}\n\n\t\tvar clickEvent = (e) => {\n\t\t\tif (e) {\n\t\t\t\t// Be respectful\n\t\t\t\tif (\n\t\t\t\t\te.defaultPrevented ||\n\t\t\t\t\t(e.originalEvent && e.originalEvent.defaultPrevented) ||\n\t\t\t\t\t// not mouse click, but not enter or space either\n\t\t\t\t\t(e.which !== 1 && e.which !== 13 && e.which !== 32)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Actions are superseding events within them\n\t\t\t\tif (e.target.closest('.nx-ignore-action')) return;\n\t\t\t}\n\n\t\t\t// The click doesn't get up to the menu view\n\t\t\tif (this.isMenuView) {\n\t\t\t\tdispatcher.trigger('app:close:menus');\n\t\t\t}\n\n\t\t\t// With action & arguments, perform the appropriate action:\n\t\t\tthis.performAction(action, [this, e]);\n\t\t\t// Our return value will control subsequent processing of this click event.\n\t\t\t// Set it by tag type:\n\t\t\tvar tag = $(e.currentTarget).prop('tagName');\n\t\t\ttag = tag && tag.toLowerCase();\n\t\t\tif (tag == 'a') {\n\t\t\t\te.preventDefault();\n\t\t\t}\n\n\t\t\tsimulateClickBody();\n\n\t\t\t// Our return value will control subsequent processing of this click event.\n\t\t\t// We do not want to prevent default behavior for inputs and textareas. (return true)\n\t\t\t// For all other elements, tell jQuery we are done processing this click. (return false)\n\t\t\t// THIS IS SO GROSS:\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\ttag == 'input' ||\n\t\t\t\t\ttag == 'select' ||\n\t\t\t\t\ttag == 'textarea' ||\n\t\t\t\t\te.currentTarget.closest('.mdc-drawer')\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t//e.stopPropagation();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tif ($target.length) {\n\t\t\t_.each($target, function (el) {\n\t\t\t\tel.addEventListener('click', clickEvent);\n\t\t\t\tel.addEventListener('keydown', clickEvent);\n\t\t\t\t$(el).on('tapToClick', clickEvent);\n\t\t\t});\n\t\t\tthis.actionEvents[action.event] = {els: $target, func: clickEvent};\n\t\t}\n\n\t\tthis.trigger('enabledAction', action, options);\n\t}\n\n\t/**\n\t * End progress simulation\n\t * @method\n\t */\n\tendProgressSimulation() {\n\t\t// Must have been simulating to end simulation\n\t\tif (!this.simulatingProgress) return;\n\n\t\twindow.requestAnimationFrame(() => {\n\t\t\tthis.$pseudoProgressBar.width('100%').attr('aria-valuenow', '100%');\n\t\t});\n\n\t\t// Simualtion over\n\t\tthis.simulatingProgress = false;\n\n\t\t_.delay(() => {\n\t\t\tif (this.simulatingProgress) return;\n\t\t\tthis.el.removeAttribute('data-nx-simulating-progress');\n\t\t\tthis.$pseudoProgress.removeClass('active');\n\t\t\tthis.$pseudoProgressBar.width('0%').attr('aria-valuenow', 0);\n\t\t}, this.loadingClassRemoveDelay || 300);\n\t}\n\n\t/** @method */\n\tescapeKeyListener() {\n\t\tif (!this.$el.is(':visible')) return;\n\t\tthis.escape();\n\t}\n\n\t/**\n\t * this.findContextMenu(): contextmenu event (right-click, etc) handler for context menus.\n\t *\n\t * A Netx.View may define the attribute 'data-contextmenu-target' on its element to specify that\n\t * right clicks should show a context menu containing the Actions of a Netx.Menu\n\t * The value of 'data-contextmenu-target' is the name of the menu.\n\t *\n\t * You should not need to call this function directly.\n\t *\n\t * @method\n\t * @param {event} e Event\n\t * @private\n\t * @see {@link Netx.View#insertContextMenu|insertContextMenu}\n\t */\n\tfindContextMenu(e) {\n\t\t// If we have data-contextmenu-target set, we are a view trying to have a menu.\n\t\tconst menuName = this.$el.data('contextmenu-target');\n\t\tif (!menuName) return true;\n\n\t\tsimulateClickBody();\n\n\t\t// insert context menu\n\t\tthis.insertContextMenu(menuName, e);\n\t\t// Prevent browser from getting this click\n\t\treturn false;\n\t}\n\n\t/**\n\t * Get this.templateVars\n\t * @method\n\t * @return {function|object} Template variables\n\t */\n\tgetTemplateVars() {\n\t\treturn this.templateVars;\n\t}\n\n\t/**\n\t * Hide the view\n\t * @method\n\t * @param {boolean} simple Simply a flip\n\t * @fires Netx.View#hiding\n\t * @fires Netx.View#hidden\n\t * @see {@link Netx.View#show|show}\n\t * @see {@link Netx.View#toggle|toggle}\n\t */\n\thide(simple, extra) {\n\t\t// used to be function (route, simple)\n\t\tif (extra) {\n\t\t\t// if we got two args\n\t\t\tconsole.warn(\n\t\t\t\t'hide() no longer takes a route argument. Fix before v8.10',\n\t\t\t);\n\t\t\tsimple = extra;\n\t\t}\n\n\t\t// Sometimes events get piped to this method - trying to find them all, but for any remaining\n\t\tif (simple && !_.isBoolean(simple)) {\n\t\t\tsimple = false;\n\t\t}\n\n\t\t// This could change in the interim (while the beforeHidden method runs)\n\t\t// Say there was a simple hide - but while the view was hiding some conditions were met to call a hard hide - so set it and\n\t\t// delete it later - it should never be set outside of right here\n\t\tif (this._simpleHide !== false) {\n\t\t\tthis._simpleHide = simple === true;\n\t\t}\n\n\t\t// Do nothing if we are in the midst of being removed\n\t\t// or are already preparing to hide\n\t\tif (this.removing || this.preparingToHide) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We are fixing to hide but may have to wait for or do a few things first\n\t\tthis.preparingToHide = true;\n\n\t\t// When hiding is complete - check if we should remove this view\n\t\tconst checkAndRemove = () => {\n\t\t\t// Remove? If it is not a simple el hide (caused by a flip and not any actual events) -\n\t\t\t// check if the view should be removed after hiding the instance\n\t\t\tif (\n\t\t\t\t(this._simpleHide !== true || this.removeOnSimpleHide) &&\n\t\t\t\tthis.removeOnHide\n\t\t\t) {\n\t\t\t\t// Check that this view's viewCollection matches our original view collection\n\t\t\t\t// When popping views from one thing to another, we will always put the view back - there is no\n\t\t\t\t// permanant popping. It should be used to go into more focused/larger contexts but ultimately\n\t\t\t\t// still belongs to the viewCollection it was created in.\n\t\t\t\t// Also check that there are not any transient views - if there is a transient view then this\n\t\t\t\t// view that is hiding will be back when that view returns to its original home\n\t\t\t\tif (\n\t\t\t\t\t!this.viewSpec ||\n\t\t\t\t\t(this.viewSpec.currentCollection == null &&\n\t\t\t\t\t\t(!this.viewSpec.collection ||\n\t\t\t\t\t\t\t!this.viewSpec.collection.getTransient()))\n\t\t\t\t) {\n\t\t\t\t\tthis.remove();\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If not a simple hide, and it is not in original `viewCollection` then it needs to be removed\n\t\t\t// from the `currentCollection`\n\t\t\telse if (\n\t\t\t\tthis._simpleHide !== true &&\n\t\t\t\tthis.viewSpec &&\n\t\t\t\tthis.viewSpec.currentCollection\n\t\t\t) {\n\t\t\t\tthis.viewSpec.currentCollection.remove(this.viewSpec);\n\t\t\t}\n\t\t\tdelete this._simpleHide;\n\n\t\t\t// It's over, we are hidden (and possibly removed)\n\t\t\tthis.preparingToHide = false;\n\t\t};\n\n\t\t// In case hide was called while we were still in the middle of showing\n\t\t// Let show finish and then we can hide, this way nothing is jerky in and out of the app\n\t\t$.when(this.showing ? this.whenShown : true).then(() => {\n\t\t\t// To save people from themselves we always have a slight hide delay in most cases\n\t\t\treturn $.when(this.hideDelayed ? this.hideDelayed : true).then(() => {\n\t\t\t\tthis.hiddenByProxy = false;\n\t\t\t\t// Not already hiding\n\t\t\t\t// I do not think there is harm in hiding something already hidden - if there is we need to fine tune a few more things\n\t\t\t\t// as if you race fast enought you can be visible to the user while not being quite \"visible\" to the code and/or vice versa\n\t\t\t\tif (!this.hiding && this.isShown) {\n\t\t\t\t\t// We are now officially starting to hide\n\t\t\t\t\tthis.trigger('hiding', this);\n\n\t\t\t\t\t// NOTE: We do not do any fliiping in here as it is assumed the event system is taking care of showing something else\n\t\t\t\t\t// It is in the `show` method that we help out with flipping\n\n\t\t\t\t\t// Wait for view to be considered hidden\n\t\t\t\t\tthis.beforeHidden(() => {\n\t\t\t\t\t\t// We are now officially hidden\n\t\t\t\t\t\tthis.trigger('hidden', this);\n\t\t\t\t\t\t// Remove?\n\t\t\t\t\t\tcheckAndRemove();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// We are already hidden\n\t\t\t\telse if (!this.isShown) {\n\t\t\t\t\t// Remove?\n\t\t\t\t\tcheckAndRemove();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t * @return {array} Excluded views\n\t */\n\tgetExcludedViews() {\n\t\treturn _.pluck(this.subViews, 'el').concat(_.pluck(this.menuViews, 'el'));\n\t}\n\n\t/**\n\t * @method\n\t * @param {string} functionalityName Functionality name\n\t * @return {boolean}\n\t */\n\thasFunctionality(functionalityName) {\n\t\treturn this.constructor.hasFunctionality(functionalityName);\n\t}\n\n\t/**\n\t * Called by view.initialize() to parse the template for the attributes 'data-action' and\n\t * 'data-action-context', which sets up listeners and does basic parsing.\n\t * @method\n\t * @private\n\t */\n\tinitializeActions() {\n\t\t// TODO: We need to support our multiView stuff in actions so we do not need to set up wrappers on every action related to\n\t\t// a modal crumb or tab item (these are created via child views and there models are the viewSpec - but all actions want the view related to the viewSpec)\n\t\t// var _view = view.model instanceof AppViewModel ? view.model.get('view') : view;\n\t\t// This needs to be handled when triggering a wrapper and enbleTest\n\n\t\tthis.$actionEls = this.$('.nx-action').purge(this.getExcludedViews());\n\t\tif (this.el.classList.contains('nx-action')) {\n\t\t\tthis.$actionEls.push(this.el);\n\t\t}\n\t\t// if this view has action context, parse it.\n\t\t// find all actions & menus in the view;\n\t\t// exclude those that actually belong to child views;\n\t\t// build arrays of their names\n\t\tthis.actions = this.$actionEls.map(function () {\n\t\t\treturn $(this).data('action');\n\t\t});\n\t\tthis.menus = this.$('.nx-action-context')\n\t\t\t.purge(this.getExcludedViews())\n\t\t\t.map(function () {\n\t\t\t\treturn $(this).data('action-context');\n\t\t\t});\n\n\t\t// find syncActions & userActions\n\t\tthis.syncActions = [];\n\t\tthis.specificSyncActions = [];\n\t\tthis.userActions = [];\n\n\t\tthis.menuActions = this.menuActions || {};\n\n\t\t// test all the actions we have buttons for\n\t\t_.each(this.actions, (c, idx, all) => {\n\t\t\tconst a = Netx.Actions.Find(c);\n\t\t\tif (_.isUndefined(a)) {\n\t\t\t\tconsole.warn('The action \"' + c + \"' has not been registered.\");\n\t\t\t\t// add a minimal fake action, so we still trigger an event\n\t\t\t\tNetx.Actions.Register({event: c, fake: true});\n\t\t\t} else {\n\t\t\t\tif (_.has(a, 'testOnSync')) {\n\t\t\t\t\tif (a.testOnSync !== true) {\n\t\t\t\t\t\tthis.specificSyncActions.push(a);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.syncActions.push(a);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (_.has(a, 'userLevel')) {\n\t\t\t\t\tthis.userActions.push(a);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// test all the actions we have menus (menus) for.\n\t\t_.each(this.menus, (menuName) => {\n\t\t\t// search Netx.Menus instead (or also)\n\t\t\tif (Netx.Menus[menuName]) {\n\t\t\t\t// TODO: refactor this.menus, this.menuViews, this.menuActions, etc, into one property on this\n\t\t\t\tthis.menuActions[menuName] = Netx.Menus[menuName].toActions();\n\t\t\t} else {\n\t\t\t\t// Thanks to this interesting code,\n\t\t\t\t// if we have an action named 'foo',\n\t\t\t\t// this lets us say 'data-nx-context=\"foo\"' instead of 'data-nx-action=\"foo\"' ....\n\t\t\t\t// But is this a feature we use? Does it even work? What does it do? Bug maybe? Deprecate?\n\t\t\t\tconsole.warn('using actions as menus is deprecated, gone in 8.13');\n\t\t\t\tthis.menuActions[menuName] = Netx.Actions[menuName];\n\t\t\t}\n\n\t\t\t_.each(this.menuActions[menuName], (a) => {\n\t\t\t\tif (_.has(a, 'testOnSync')) {\n\t\t\t\t\tif (a.testOnSync !== true) {\n\t\t\t\t\t\tthis.specificSyncActions.push(a);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.syncActions.push(a);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (_.has(a, 'userLevel')) {\n\t\t\t\t\tthis.userActions.push(a);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\t// Support appView instances - proxy through the actual view involved in that case\n\t\t// This is used mostly in cases where a appTabITemView is involved - the view itself does not have any syncable models/collections\n\t\t// But the view it works for does\n\t\tconst view =\n\t\t\tthis.model && this.model.isAppView ? this.model.get('view') : this;\n\n\t\tthis.specificSyncActions.forEach((action) => {\n\t\t\tif (this.configureSpecificSyncActions) {\n\t\t\t\tthis.stopListening(\n\t\t\t\t\taction.testOnSync,\n\t\t\t\t\t'sync reset',\n\t\t\t\t\tthis.configureSpecificSyncActions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst syncListener = (this.configureSpecificSyncActions = () => {\n\t\t\t\tthis.configureActions([action]);\n\t\t\t});\n\t\t\tthis.listenTo(\n\t\t\t\taction.testOnSync,\n\t\t\t\t'sync reset',\n\t\t\t\tthis.configureSpecificSyncActions,\n\t\t\t);\n\t\t});\n\n\t\tif (view) {\n\t\t\t// Configure sync listeners for sync actions.\n\t\t\t// We have sync actions\n\t\t\tif (this.syncActions.length) {\n\t\t\t\t// But we haven't set up listeners yet, so set them up now\n\t\t\t\tif (!this.syncActionsListening) {\n\t\t\t\t\tif (view.collection) {\n\t\t\t\t\t\t// not happening on collections?\n\t\t\t\t\t\tthis.stopListening(\n\t\t\t\t\t\t\tview.collection,\n\t\t\t\t\t\t\t'sync reset',\n\t\t\t\t\t\t\tthis.configureSyncActions,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.listenTo(\n\t\t\t\t\t\t\tview.collection,\n\t\t\t\t\t\t\t'sync reset',\n\t\t\t\t\t\t\tthis.configureSyncActions,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (view.model) {\n\t\t\t\t\t\tthis.stopListening(view.model, 'sync', this.configureSyncActions);\n\t\t\t\t\t\tthis.listenTo(view.model, 'sync', this.configureSyncActions);\n\t\t\t\t\t}\n\t\t\t\t\t// avoid re-adding these listeners.\n\t\t\t\t\tthis.syncActionsListening = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// We have no sync actions.\n\t\t// But we have listeners (unlikely but not impossible), so remove them.\n\t\telse if (this.syncActionsListening) {\n\t\t\tthis.stopListening(\n\t\t\t\tview.collection,\n\t\t\t\t'sync reset',\n\t\t\t\tthis.configureSyncActions,\n\t\t\t);\n\t\t\tthis.stopListening(view.model, 'sync', this.configureSyncActions);\n\t\t\tdelete this.syncActionsListening;\n\t\t}\n\n\t\t// Configure sync listeners for user actions ...\n\t\t// TODO: this was from when we had to wait for Netx.user.profile. Now that we are assured of having that object before\n\t\t// the application starts, I'm not sure this matters any more.\n\t\tif (this.userActions.length) {\n\t\t\tif (!this.userActionsListening) {\n\t\t\t\tthis.stopListening(Netx.getUser(), 'sync', this.configureUserActions);\n\t\t\t\tthis.listenTo(Netx.getUser(), 'sync', this.configureUserActions); // could be \"change:userLevel\" instead of \"sync\" ...\n\t\t\t\tthis.userActionsListening = true;\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.userActionsListening) {\n\t\t\t\tthis.stopListening(Netx.getUser(), 'sync', this.configureUserActions);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * initializeKeyListeners() is called by view.initialize() and checks for key events\n\t * @private\n\t */\n\tinitializeKeyListeners() {\n\t\t// Listen for escape key if property is set\n\t\tif (!_.isFunction(this.escape)) return this;\n\n\t\treturn this.stopListening(\n\t\t\tdispatcher,\n\t\t\t'key:escape',\n\t\t\tthis.escapeKeyListener,\n\t\t).listenTo(dispatcher, 'key:escape', this.escapeKeyListener);\n\t}\n\n\t/**\n\t * this.insertContextMenu() inserts a given menu in this view, positioned underneath the mouse pointer.\n\t * @param string menuName\n\t * @param {event} e The original click event (required for positioning)\n\t */\n\tinsertContextMenu(menuName, e) {\n\t\tconst menuOptions = {\n\t\t\tclassName: 'dropdown',\n\t\t\tmodel: this.model,\n\t\t\tcollection: this.menuCollection || this.collection,\n\t\t\tcontext: true,\n\t\t};\n\n\t\tif (!this.useAdvancedMenu) {\n\t\t\tmenuOptions.menu = Netx.Menus[menuName];\n\t\t\t// Warn about obsolete menus:\n\t\t\tif (menuOptions.menu && menuOptions.menu.get('deprecated')) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Menu ${menuName} deprecated, gone after ${menuOptions.menu.get(\n\t\t\t\t\t\t'deprecated',\n\t\t\t\t\t)}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Look for custom template\n\t\tconst templateName = this.useAdvancedMenu\n\t\t\t? menuName\n\t\t\t: (this.$el.attr('data-nx-template') || '').replace('menuView-', '');\n\t\tif (templateName != null) {\n\t\t\tmenuOptions.template = MenuTemplates[templateName];\n\t\t}\n\n\t\t// Menu view type\n\t\tconst menuView = (this.menuView = this.useAdvancedMenu\n\t\t\t? new Netx.Views.AdvancedMenuView(menuOptions)\n\t\t\t: new Netx.Views.MenuView(menuOptions));\n\n\t\t// Where to append menu\n\t\tlet appendTo = this.$el.data('contextmenu-container') || 'body';\n\n\t\t// Set it apart\n\t\tmenuView.$el.addClass('contextmenu');\n\n\t\t// Render and show\n\t\tmenuView.render().$el.appendTo(appendTo);\n\n\t\t// iOS safari has some real issues\n\t\t// if we do not do something here the menu will either hide immediately\n\t\t// or an action that is now beneath your finger will fire\n\t\tlet canHide = true;\n\t\tif (/iphone|ipad|ipod/i.test(navigator.userAgent)) {\n\t\t\tcanHide = false;\n\t\t\tmenuView.$el.find('.dropdown-menu').css('pointer-events', 'none');\n\t\t\t_.delay(() => {\n\t\t\t\tcanHide = true;\n\t\t\t\tmenuView.$el.find('.dropdown-menu').css('pointer-events', 'initial');\n\t\t\t}, 300);\n\t\t}\n\n\t\t// show menu\n\t\tmenuView.$el.find('[data-toggle=\"dropdown\"]').click();\n\n\t\t// Move the menu underneath the mouse\n\t\tmenuView.$el.css(_.getMenuPosition(e, menuView.$el));\n\n\t\t// Remove and destroy the menuView when it gets closed.\n\t\tmenuView.$el.on('hide.bs.dropdown', () => {\n\t\t\tif (!canHide) {\n\t\t\t\t// Reshow\n\t\t\t\tmenuView.$el.find('[data-toggle=\"dropdown\"]').click();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_.defer(() => {\n\t\t\t\tthis.trigger('context:menu:removed', menuView);\n\t\t\t\tmenuView.$el.off('hide.bs.dropdown');\n\t\t\t\tmenuView.remove();\n\t\t\t\tdelete this.menuView;\n\t\t\t});\n\t\t});\n\n\t\t// Make menuView remove itself when its parent (this) is removed\n\t\tmenuView.stopListening(this, 'removed').listenTo(this, 'removed', () => {\n\t\t\tmenuView.remove();\n\t\t});\n\n\t\t// deprecated 2016-07-01 - Left for legacy as no longer are we deferred thanks to pre-compiling our templates\n\t\t// TODO: actually go and remove the listeners for this event from the three views that use it.\n\t\tthis.trigger('context:menu:rendered', menuView);\n\t}\n\n\t/**\n\t * insertMenu creates a menuView and inserts it in the given element, which must have a data-action-context attr.\n\t * @method\n\t * @private\n\t * @param {jQuery} $menuEl Selector for the data-action-context element\n\t * @param {string} menuName Name of the menu (key to this.menus)\n\t * @param {boolean} vanish Should this menu remove itself when it hides?\n\t * @return {Netx.View} Menu view\n\t */\n\tinsertMenu($menuEl, menuName, vanish) {\n\t\tif (!menuName) {\n\t\t\tthrow new Error('insertMenu called on non-menu');\n\t\t}\n\n\t\t// TODO: Talk about the fact model is undefined and collection has 0 models\n\t\t// But- really in the context of where I was testing- appHeader - was one hoping the menu would be privy to the view it was called in's model and collection? Maybe?\n\t\tvar menuOptions = {\n\t\t\tmodel: this.model,\n\t\t\tcollection: this.collection,\n\t\t\tmenu: Netx.Menus[menuName],\n\t\t};\n\n\t\tif (!menuOptions.menu) {\n\t\t\tthrow new Error('Can\\'t find menu \"' + menuName + '\"');\n\t\t}\n\n\t\t// Warn about obsolete menus:\n\t\tif (menuOptions.menu.get('deprecated')) {\n\t\t\tconsole.warn(\n\t\t\t\t'Menu ' +\n\t\t\t\t\tmenuName +\n\t\t\t\t\t' deprecated, gone after ' +\n\t\t\t\t\tmenuOptions.menu.get('deprecated') +\n\t\t\t\t\t'.',\n\t\t\t);\n\t\t}\n\n\t\t// Look for custom template\n\t\tvar templateName = ($menuEl.attr('data-nx-template') || '').replace(\n\t\t\t'menuView-',\n\t\t\t'',\n\t\t);\n\t\tif (templateName != null) {\n\t\t\tmenuOptions.template = MenuTemplates[templateName];\n\t\t}\n\n\t\t// Create menu view if it doesn't exit\n\t\tthis.menuViews = this.menuViews || {};\n\n\t\t// Find/create view, and attach.\n\t\tvar mv = this.menuViews[menuName] || new Netx.Views.MenuView(menuOptions);\n\t\tthis.menuViews[menuName] = mv;\n\t\tif (mv.el !== $menuEl && mv.$el !== $menuEl) {\n\t\t\tmv.setElement($menuEl);\n\t\t}\n\n\t\tvar $parent = mv.$el.parent();\n\n\t\t// The menu can remove itself when hidden\n\t\tif (vanish) {\n\t\t\t// Remove and destroy the menuView when it gets closed.\n\t\t\t$parent.off('hide.bs.dropdown.nx').on(\n\t\t\t\t'hide.bs.dropdown.nx',\n\t\t\t\t_.bind(function (e) {\n\t\t\t\t\t// This isn't going to work\n\t\t\t\t\t// By stopping propagation, it does not just stop the flow of the event upwards, it stops any\n\t\t\t\t\t// other event listener on the element for this event - namespace is not a consideration.\n\t\t\t\t\t// Instead: just respond to the event if it pertains directly to us and then we do not need\n\t\t\t\t\t// to worry about the upward flow of the event\n\t\t\t\t\t// e.stopPropagation();\n\t\t\t\t\tif (e.target == $parent[0]) {\n\t\t\t\t\t\t// Delete the menu view ... this is more complicated than it should be.\n\t\t\t\t\t\t// This defer allows any other event listener to do its thing. Whithout it you risk flickers and other oddities.\n\t\t\t\t\t\t_.defer(\n\t\t\t\t\t\t\t_.bind(function () {\n\t\t\t\t\t\t\t\t$parent.off('hide.bs.dropdown.nx');\n\t\t\t\t\t\t\t\t// We can't just call mv.remove(), but we can't because we installed our view on a UL element and we need to leave that element behind.\n\t\t\t\t\t\t\t\tmv.removeInner();\n\t\t\t\t\t\t\t\tdelete this.menuViews[menuName];\n\t\t\t\t\t\t\t}, this),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}, this),\n\t\t\t);\n\t\t}\n\n\t\t// make mv remove itself when its parent (this) is removed\n\t\tmv.stopListening(this, 'removed');\n\t\tmv.listenTo(this, 'removed', function () {\n\t\t\tif (vanish) {\n\t\t\t\t// We create a lot of menus - be safe and overkill events\n\t\t\t\t$parent.off('hide.bs.dropdown.nx');\n\t\t\t}\n\t\t\t// because .listenTo sets context, this 'this' == mv.\n\t\t\tthis.remove();\n\t\t});\n\n\t\t// Return menu view\n\t\treturn mv;\n\t}\n\n\t/**\n\t * A view can be attached to either a Model or a Collection;\n\t * this.isCollectionView() is the canonical way to tell the difference.\n\t * @method\n\t * @return {boolean} Is collection view\n\t */\n\tisCollectionView() {\n\t\treturn this.model == null;\n\t}\n\n\t/**\n\t * For more complicated responses to route changes, a modal view can override this.isMyRoute();\n\t * It receives the current route, and returns true if the route is one it expects to\n\t * be showing for, or false if it expects to close. The default implementation respects\n\t * this.stickyModal.\n\t * @method\n\t * @param {string} route The current route.\n\t * @return {boolean}\n\t * @see {@link Netx.View#isMyRoute|isMyRoute}\n\t */\n\tisMyRoute(route) {\n\t\tif (this.stickyModal) return true;\n\t\tif (this.routeMatch) {\n\t\t\treturn _.isString(this.routeMatch)\n\t\t\t\t? route === this.routeMatch\n\t\t\t\t: !_.isNull(route.match(this.routeMatch));\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Hide is about to start\n\t * At this point no animations or actual hiding [should] have taken place\n\t * @method\n\t * @listens Netx.View#hiding\n\t */\n\tonHiding(view) {\n\t\tif (view !== this) return;\n\n\t\t// Definitely not showing\n\t\tthis.showing = false;\n\t\t// Set the appropriate hiding stuff\n\t\tthis.hiding = true;\n\t\tthis.el.removeAttribute('data-nx-showing');\n\t\tthis.el.setAttribute('data-nx-hiding', true);\n\t\t//this.$el.removeClass('showing').addClass('hiding');\n\t}\n\n\t/**\n\t * Show is about to start\n\t * At this point no animation or actual showing [should] have taken place\n\t * @method\n\t * @listens Netx.View#showing\n\t */\n\tonShowing(view) {\n\t\tif (view !== this) return;\n\n\t\t// Definitely not hiding anymore\n\t\tthis.hiding = false;\n\t\t// Set the appropriate showing stuff\n\t\tthis.showing = true;\n\t\tthis.el.removeAttribute('data-nx-hiding');\n\t\tthis.el.setAttribute('data-nx-showing', true);\n\t\t//this.$el.removeClass('hiding').addClass('showing');\n\t}\n\n\t/**\n\t * Parse the contents of an action object and execute its action\n\t *\n\t * @param Object action An action object\n\t * @param Array actionArgs A set of action arguments.\n\t * @method\n\t * @private\n\t */\n\tperformAction(action, actionArgs) {\n\t\tvar e = _.last(actionArgs);\n\n\t\t//\n\t\t// Generic handler for all Action clicks:\n\t\t//\n\t\tif (action.fake) {\n\t\t\tconsole.warn(\n\t\t\t\t'The action \"' + action.event + '\" has not been registered.',\n\t\t\t);\n\t\t}\n\n\t\t// if this view has defined an actionWrapper for this action, run the arguments through that.\n\t\tif (\n\t\t\tthis.actionWrappers &&\n\t\t\t_.isFunction(this.actionWrappers[action.event])\n\t\t) {\n\t\t\tactionArgs = this.actionWrappers[action.event].apply(this, actionArgs);\n\t\t\tif (!_.isArray(actionArgs)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"view.actionWrapper['\" + action.event + \"'] did not return an array\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// or else, if the action itself defined a wrapper, run the arguments through that.\n\t\telse if (_.isFunction(action.wrapper)) {\n\t\t\tactionArgs = action.wrapper.apply(this, actionArgs);\n\t\t\tif (!_.isArray(actionArgs)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Action wrapper for ' + action.event + ' did not return an array',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// close any/all open dropdown menus\n\t\t// TODO: have the menus respond to an event, instead of scraping the entire DOM on every click.\n\t\tdispatcher.trigger('app:close:menus');\n\t\t//$('.dropdown.open .dropdown-toggle').click();\n\n\t\t// HTML-1050: Remember when actions are fired.\n\t\tNetx.Actions.latest = action;\n\t\tNetx.Actions.history = Netx.Actions.history || [];\n\t\tNetx.Actions.history.push(action);\n\n\t\t// If this action has a route, route to it\n\t\tif (_.isFunction(action.route)) {\n\t\t\t// route can be a function that takes args & returns a string\n\t\t\tNetx.router.navigate(action.route.apply(this, actionArgs), true);\n\t\t} else if (_.isString(action.route)) {\n\t\t\t// it can also be a plain string.\n\t\t\t// TODO: such actions could be rendered as simple hrefs that can be enabled/disabled, so the browser can do this part ...\n\t\t\tNetx.router.navigate(action.route, true);\n\t\t}\n\n\t\t// If this action has a link, send the browser to it.\n\t\t// (Again, this could have been rendered as a simple href ...)\n\t\telse if (_.isString(action.link)) {\n\t\t\t// a link could be of the format \"#route\", or \"/other/site/on/this/host\" or even \"http://google.com\"\n\t\t\twindow.location = action.link;\n\t\t\treturn;\n\t\t}\n\n\t\t// If no view & no route, trigger this action's event\n\t\telse {\n\t\t\tactionArgs.unshift(action.event);\n\t\t\tdispatcher.trigger.apply(dispatcher, actionArgs);\n\t\t}\n\n\t\tthis.trigger('performedAction', action);\n\t}\n\n\t/**\n\t * Prevent default event\n\t * @method\n\t */\n\tpreventDefault(e) {\n\t\te && e.preventDefault && e.preventDefault();\n\t\treturn false;\n\t}\n\n\t/**\n\t * Pre-Render hook: preRender() is called by render(), and runs first.\n\t * The default method is null by default, and can be overridden without concern.\n\t * It will not be called until the template is loaded.\n\t * @see {@link Netx.View#postRender|postRender}\n\t * @see {@link Netx.View#render|render}\n\t */\n\tpreRender() {\n\t\t// Cleanup lazyloader\n\t\tthis.Plugins.Destroy('lazyloader');\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Post-Render hook: postRender() is called immediately after render completes.\n\t * The default method is null by default and can be overriden without concern.\n\t * It will not be called until the template is loaded.\n\t * @see {@link Netx.View#preRender|preRender}\n\t * @see {@link Netx.View#render|render}\n\t */\n\tpostRender() {\n\t\t//console.debug('POST-RENDER');\n\t}\n\n\t/** @override */\n\tremove() {\n\t\t// This is already happening\n\t\tif (this.removing) return;\n\n\t\tthis.trigger('removeHook', this);\n\n\t\tthis.cleanUpActionEvents();\n\t\tdelete this.$actionEls;\n\n\t\t// We want to know when we are removing\n\t\t// The reason being - when we remove we fire off all appropriate events to hide/remove/cancel our children - the thing is - when children remove\n\t\t// we check to see if there is anything left in our viewCollection - if nothing is left we fire `this.hide` - essentially starting this whole thing over -\n\t\t// which confuses appModalView as the view is already gone as far as it was concerned but the hide event gets back to it - it check its viewCollection\n\t\t// length - see's only 1 and assumes that that is it - modal game over (as why bother trying to do anything fancy if only one view is there at hide time)\n\t\tthis.removing = true;\n\n\t\tthis.menuView && this.menuView.remove();\n\n\t\tthis.unbindEvents();\n\n\t\t// Reject (clean up) any pending stuff\n\t\tthis._hiddenDeferred.state() === 'pending' && this._hiddenDeferred.reject();\n\t\tthis._shownDeferred.state() === 'pending' && this._shownDeferred.reject();\n\t\tthis.rendered.state() === 'pending' && this.rendered.reject();\n\t\tthis.whenImagesLoaded &&\n\t\t\tthis.whenImagesLoaded.state() === 'pending' &&\n\t\t\tthis.whenImagesLoaded.reject();\n\t\tthis.whenShown.state() === 'pending' && this.whenShown.reject();\n\t\tthis.whenHidden.state() === 'pending' && this.whenHidden.reject();\n\n\t\t// Destroy all plugins\n\t\tthis.Plugins.Destroy();\n\n\t\t// Remove any children we may have.\n\t\tthis.removeAllSubViews();\n\n\t\tthis.pseudoProgressInterval && clearInterval(this.pseudoProgressInterval);\n\n\t\tsuper.remove();\n\n\t\tNetx.viewStats[this.constructor.__name__]--;\n\n\t\tthis.trigger('removed');\n\n\t\tthis.off();\n\t}\n\n\t/**\n\t * @method\n\t */\n\tremoveAllSubViews() {\n\t\t_.invoke(this.subViews, 'remove');\n\t\tthis.subViews = {};\n\t\treturn this;\n\t}\n\n\t/**\n\t * If a child is removing a view added with addSubView(), they should call removeSubView() to clean up its reference\n\t * so memory can be freed.\n\t * @method\n\t * @param {string|Netx.View} idx Either a view or a view's .cid (which is a unique ID)\n\t * @param {boolean} destroyView Whether or not to destroy the view\n\t * @see {Netx.View#addSubView}\n\t */\n\tremoveSubView(idx, destroyView) {\n\t\tif (idx === void 0) return;\n\n\t\tif (idx.cid && idx.cid.includes('view')) {\n\t\t\tidx = idx.cid;\n\t\t}\n\n\t\tconst view = this.subViews[idx];\n\t\tdelete this.subViews[idx];\n\t\tdestroyView && view && view.remove();\n\t\treturn view;\n\t}\n\n\t/**\n\t * Render: paint a view's DOM objects.\n\t * render() calls doTemplate() to generate templated HTML, and installs that HTML in the\n\t * view's element, $el. The preRender() and postRender() hooks are called before and after.\n\t *\n\t * NOTE: render() is asynchronous. Templates load on demand as views are instantiated, and if\n\t * render() is called before the template is loaded it returns immediately, but actual\n\t * rendering is deferred until the template is available. Listen for the Backbone event\n\t * \"rendered\" on the View object itself (not the dispatcher) to know when rendering has completed,\n\t * or attach a done handler to the Promise object this.rendered .\n\t *\n\t * render() is quite complex; ideally, views will not need to override this method,\n\t * and will override the pre- and post- hooks instead. If you must override render,\n\t * be sure to call it in your custom render method via this._super().\n\t *\n\t * render() returns the view itself, for daisychaining in the Backbone pattern.\n\t *\n\t * @see {@link Netx.View#doTemplate|doTemplate}\n\t * @see {@link Netx.View#preRender|preRender}\n\t * @see {@link Netx.View#postRender|postRender}\n\t * @see {@link Netx.View#renderElement|renderElement}\n\t */\n\t//\n\t// DEVNOTE: the definition below of render() is wrapped in the initializer (above), which\n\t// passes it the argument 'deferred'. But for the sake of clarity I'm putting the\n\t// documentation here for the external render() method (i.e. the wrapper), which does not\n\t// take an argument.\n\t//\n\t// ... and yes, we need to do it that way, in order to implement pre- and post- hooks on any overridden render() method.\n\t//\n\trender() {\n\t\t// We debounce some renders - do not render if we are removing/removed\n\t\tif (this.removing) return;\n\n\t\t// This is a cleaner way of having to check - `!this.renderedOnce` then `this.listenToOnce( this, 'rendered', ... )`\n\t\t// You can just say `this.rendered.then(...)`\n\t\t// Usefule for things that get declared in the initialize method but do not want to act until the view has first rendered\n\t\tif (this.rendered.state() !== 'pending') {\n\t\t\tthis.rendered = new $.Deferred();\n\t\t}\n\n\t\tif (this.whenImagesLoaded && this.whenImagesLoaded.state() === 'pending') {\n\t\t\tthis.whenImagesLoaded.reject();\n\t\t}\n\t\t// Let our view know when its images have loaded\n\t\tthis.whenImagesLoaded = new $.Deferred();\n\n\t\tif (Netx.custom.TIME_RENDERS && !this._render_started) {\n\t\t\tthis._render_started = new Date().getTime();\n\t\t}\n\n\t\tthis.cleanUpActionEvents();\n\n\t\t// Call pre-render hook before we touch anything.\n\t\tthis.trigger('preRenderHook', this);\n\t\tthis.preRender();\n\t\tthis.unbindEvents();\n\n\t\t// Modifying this.el begins here.\n\t\t// When adding anything new to the render process,\n\t\t// alway add it after this point, or else\n\t\t// preRender() can't access the unmodified version\n\t\tsuper.render();\n\n\t\tlet html;\n\t\t// try to apply the template; catch any template errors.\n\t\ttry {\n\t\t\thtml = this.doTemplate();\n\t\t} catch (error) {\n\t\t\tconsole.error(`Exception in template ${this.constructor.__name__}`);\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Further research finds that this method is about 30% faster (on Chrome at least):\n\t\tif (!this.el) {\n\t\t\t// WTF? Caused by some extension code in custom controller, altering UserPrefsView and SearchRulesView by deleting 'el' in the prototypes.\n\t\t\t// TODO: move those extensions to the new extension system & this won't happen.\n\t\t\t// TODO: our views should not define 'el' in the first place. Probably an old mistake. Fix those in core, then delete this whole hack.\n\t\t\t// Meanwhile, revert to the old algorithm for just these two views.\n\t\t\tthis.el = document.createElement(this.tagName);\n\t\t\tthis.$el = $(this.el);\n\t\t}\n\t\tthis.el.innerHTML = html;\n\t\t// TODO: if we could translate the html before adding it to the DOM, it might be faster still\n\t\tthis.$el.localize();\n\n\t\t// attach model ID to all model views:\n\t\tif (this.model && this.model.id) {\n\t\t\tthis.$el.attr('data-nx-model-id', this.model.id);\n\t\t}\n\n\t\t// process any AutoTemplate directives in the template (and potentially load other templates)\n\t\tdispatcher.trigger('autoTemplate:scan', this.$el);\n\n\t\t// install & configure Actions in this template\n\t\tthis.initializeActions();\n\t\tthis.renderActions();\n\n\t\t// Count/total collection items\n\t\tthis.$count = this.$('.nx-count');\n\t\t// Do not interfere with children\n\t\tif (this.$childTargetEl && this.$childTargetEl.find(this.$count).length) {\n\t\t\tthis.$count = null;\n\t\t}\n\t\tthis.updateCount();\n\n\t\t// Done modifying this.el.\n\t\t// Don't add modifications after here, or\n\t\t// postRender() won't have access to them.\n\n\t\t// call post-render hook\n\t\tthis.trigger('postRenderHook', this);\n\t\tthis.postRender();\n\n\t\t// Add/remove `no-assets`/`no-results`/`no-matches` classes\n\t\t// TODO: Stop using `no-assets`, instead use `no-results`\n\t\tthis.checkHasResults();\n\n\t\t// install key listeners\n\t\tthis.initializeKeyListeners();\n\n\t\t// Re-attach event listeners.\n\t\t// http://ianstormtaylor.com/rendering-views-in-backbonejs-isnt-always-simple/\n\t\tthis.delegateEvents();\n\n\t\t// Maintain statistics on how often we render views; it's easy to render too often.\n\t\tthis.renderStats();\n\t\tif (Netx.custom.TIME_RENDERS) {\n\t\t\tconsole.log(\n\t\t\t\t`${this.constructor.__name__} rendered in ${\n\t\t\t\t\tnew Date().getTime() - this._render_started\n\t\t\t\t}ms.`,\n\t\t\t);\n\t\t\tdelete this._render_started;\n\t\t}\n\n\t\t// Backstory:\n\t\t// We have relied on this rendered promise to so something once in initialize after it is resolved\n\t\t// In a lot of cases we only want this to happen on the first render - so moving the code to postRender is not going to be good for us\n\t\t// I do not see any harm in triggering a rendered event on the view that we can `listenToOnce` and accomplish what we want\n\t\t// I have deferred this event because we chanin our renders a lot - I do not want the event to fire until we are done with our chain\n\t\t_.defer(() => {\n\t\t\t// When we need to do something on only the first render, in some more complciated views, we can just\n\t\t\t// use `.then` rather than having to check `this.renderedOnce` -> `this.listenToOnce(this, 'rendered' ... )`\n\t\t\t// Use cases are for when you only want to do something once on rendered (so postRender will not cut it, though,\n\t\t\t// you could check for `this.renderedOnce` in `postRender`, but all the places we would need to do this, `postRender`\n\t\t\t// just doesn't seem like the appropriate place - `initialize` is a better place for 99% of that logic.\n\t\t\tthis.rendered.resolveWith(this);\n\t\t\tthis.trigger('rendered');\n\t\t\t// Now listen for view's images to load\n\t\t\tthis.$el.imagesLoaded(() => {\n\t\t\t\tthis.whenImagesLoaded.resolveWith(this);\n\t\t\t});\n\n\t\t\tthis.bindEvents();\n\t\t});\n\n\t\t// We have rendered once (at least)\n\t\tthis.renderedOnce = true;\n\n\t\tthis.trigger('renderedHook', this);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * renderActions() is called after view.render(), to install context menus and buttons in the DOM.\n\t * @method\n\t * @private\n\t */\n\trenderActions() {\n\t\t// are there any actions to activate?\n\t\tthis.configureActions(_.map(this.actions, Netx.Actions.Find));\n\n\t\t// any menus to install?\n\t\tif (!this.menus.length) return this;\n\n\t\t_.each(this.menus, (menuName) => {\n\t\t\tvar $menuEl = this.$(\n\t\t\t\t'.nx-action-context[data-action-context=\"' + menuName + '\"]',\n\t\t\t);\n\t\t\tvar triggerEvent =\n\t\t\t\t$menuEl.closest('[data-nx-trigger]').data('nxTrigger') || 'click';\n\n\t\t\t// TODO: this is a hack for DAM-12956 until we reqork menus. Not injecting and testing now could mean an empty menu\n\t\t\t// displaying until hover (at which point it disappears like it should have)\n\t\t\tif (\n\t\t\t\ttriggerEvent !== 'mouseover' &&\n\t\t\t\t$menuEl.filter('.dropdown-menu').length > 0\n\t\t\t) {\n\t\t\t\t// we don't really \"render\" dropdowns any more; we wait for a triggerEvent, and create the menuView then.\n\t\t\t\tvar $trigger = $menuEl.siblings('.dropdown-toggle'); // changed a.dropdown-toggle to .dropdown-toggle (buttons are dropdowns too!)\n\t\t\t\t$trigger.off(triggerEvent + '.data-action-context');\n\t\t\t\t$trigger.on(\n\t\t\t\t\ttriggerEvent + '.data-action-context',\n\t\t\t\t\t_.bind(function () {\n\t\t\t\t\t\tthis.insertMenu($menuEl, menuName, true).render();\n\t\t\t\t\t\tthis.configureMenu(menuName);\n\t\t\t\t\t}, this),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// normal menus are created now\n\t\t\t\tthis.insertMenu($menuEl, menuName, false).render();\n\t\t\t\tthis.configureMenu(menuName);\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Backbone generally updates the screen by re-rendering a view via view.render(). But sometimes we don't want to re-render\n\t * a whole view; for instance, third-party plugins may be bothered if our DOM objects are deleted and re-created.\n\t * renderElement() replaces just one element of our template, specified by a jQuery selector, with freshly template-generated HTML.\n\t * Canonical usage:\n\t * @example\n\t * this.renderElement(selector, this.doTemplate());\n\t * @see {@link Netx.View#render|render}\n\t */\n\trenderElement(selector, the_html) {\n\t\t// convert the_html to DOM object.\n\t\tconst jq = $('
      ' + the_html + '
      ');\n\t\tconst the_el = jq.find(selector);\n\t\tif (the_el.length == 0) {\n\t\t\tconsole.warn('selector found nothing');\n\t\t\treturn;\n\t\t}\n\t\tconst new_html = the_el.html();\n\t\t// install where needed.\n\t\tthis.$(selector).html(new_html).localize();\n\t\t// If there are actions in the new html, initialize and render them.\n\t\tif (\n\t\t\tnew_html.match(/data-action=/) ||\n\t\t\tnew_html.match(/data-action-context=/)\n\t\t) {\n\t\t\tthis.initializeActions();\n\t\t\tthis.renderActions();\n\t\t}\n\t\t// If there are autocomplete fields in the new html, initialize them.\n\t\t//this.detectAutocomplete(this.$(selector));\n\t}\n\n\t/**\n\t * Rendering statistics (for performance tuning and debugging)\n\t * If module or templateName is not provided `this.templateKey` will be used\n\t * @private\n\t * @param {string} module Module name\n\t * @param {string} templateName Template name\n\t */\n\trenderStats(module, templateName) {\n\t\tconst renderStats = Netx.renderStats;\n\t\tif (renderStats == null) return;\n\n\t\tconst templateKey = this.constructor.__name__;\n\t\tif (renderStats[templateKey] == null) {\n\t\t\trenderStats[templateKey] = [];\n\t\t}\n\n\t\tconst stamp = `${new Date()}:${templateKey}`;\n\t\trenderStats[templateKey].push(stamp);\n\t\trenderStats.done.push(stamp);\n\t\trenderStats.all.push(stamp);\n\t}\n\n\t/**\n\t * @method\n\t * @param {event} e `search` event\n\t */\n\tsearch(e) {\n\t\tlet str = (_.isString(e) ? e : (e && e.detail) || '').trim();\n\t\tif (str && str.length >= 2) {\n\t\t\tthis.collection.setFilterStr(str);\n\t\t}\n\t\t// Only clear if we previously had a search str of 2 characters or more\n\t\telse if (\n\t\t\tthis.collection.filterStr &&\n\t\t\tthis.collection.filterStr.length >= 2\n\t\t) {\n\t\t\tthis.collection.setFilterStr('');\n\t\t}\n\t}\n\n\t/** @method */\n\tsetCollection(collection, opts = {}) {\n\t\tif (this.collection && this.collection === collection) return;\n\n\t\tthis.unbindCollectionEvents();\n\n\t\tthis.collection = collection;\n\t\t_.invoke(this.menuViews, 'setCollection', collection);\n\n\t\tthis.bindCollectionEvents();\n\t\tthis.addLoadingClasses_internal();\n\t\tthis.checkHasResults();\n\n\t\tif (this.renderOnSetCollection !== false && !opts.silent) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\t/**\n\t * We want to maintain all class names when we set element\n\t * @override\n\t */\n\tsetElement(element, delegate) {\n\t\tlet className = this.el && this.el.classList ? this.el.className : [];\n\t\tclassName = `${className} ${this.className || ''}`;\n\n\t\tsuper.setElement(element, delegate);\n\n\t\tthis.$el.addClass(className);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Netx.View listens for 'setModel' events that pass a new model; these are routed to\n\t * a .setModel(model, options) function. Children of this class can add handling\n\t * for model changes by overriding that method. Ditto for 'setCollection'\n\t */\n\tsetModel(model, opts = {}) {\n\t\tif (this.model && this.model === model) return;\n\n\t\tthis.unbindModelEvents();\n\n\t\tthis.model = model;\n\t\t_.invoke(this.menuViews, 'setModel', model);\n\n\t\tthis.bindModelEvents();\n\t\tthis.addLoadingClasses_internal();\n\n\t\tif (this.renderOnSetModel !== false && !opts.silent) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\t/**\n\t * Show the view; hide sibling views within the same viewCollection\n\t * @method\n\t * @fires Netx.View#showing\n\t * @fires Netx.View#shown\n\t * @see {@link Netx.View#hide|hide}\n\t * @see {@link Netx.View#toggle|toggle}\n\t */\n\tshow() {\n\t\t// Do nothing if we are in the midst of being removed\n\t\tif (this.removing) return this;\n\n\t\t// We are no longer planning on hiding (or at least remaining hidden if a hide is in progress)\n\t\tthis.preparingToHide = false;\n\n\t\t// In case hide was called while we were still in the middle of hiding\n\t\t// Let hide finish and then we can show, this way nothing is jerky in and out of the app\n\t\t// Also, make sure we are not removing when hide is over\n\t\t$.when(\n\t\t\tthis.hiding && (this._simpleHide || !this.removeOnHide)\n\t\t\t\t? this.whenHidden\n\t\t\t\t: true,\n\t\t)\n\t\t\t.then(() => {\n\t\t\t\tthis.shownByProxy = false;\n\t\t\t\tlet hidePromise;\n\t\t\t\t// Hide any other visible siblings\n\t\t\t\t// Do this before showing the newly active view so we do not end up with uneven animations in/out\n\t\t\t\t// This will be firing off at almost the same time as `this.beforeShown`\n\t\t\t\t// This should happen regardless of if the view was already shown\n\t\t\t\tif (\n\t\t\t\t\tthis.viewSpec &&\n\t\t\t\t\t(this.viewSpec.currentCollection || this.viewSpec.collection)\n\t\t\t\t) {\n\t\t\t\t\t// We want to toglle views in the right `viewCollection` context\n\t\t\t\t\t(this.viewSpec.currentCollection || this.viewSpec.collection).each(\n\t\t\t\t\t\t(viewSpec) => {\n\t\t\t\t\t\t\t// Sometimes - due to timing - we get into a position where we are looping\n\t\t\t\t\t\t\t// while a view is being removed (like a removeOnHide situation) - so just check\n\t\t\t\t\t\t\t// that the model is still defined\n\t\t\t\t\t\t\tif (viewSpec != null) {\n\t\t\t\t\t\t\t\tconst _view = viewSpec.get('view');\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t_view &&\n\t\t\t\t\t\t\t\t\t_view.cid !== this.cid &&\n\t\t\t\t\t\t\t\t\t(viewSpec.get('active') || _view.isShown)\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t// Be sure to pass true as this was not caused by any actual events\n\t\t\t\t\t\t\t\t\t_view.hide(true);\n\t\t\t\t\t\t\t\t\thidePromise = _view.whenHidden;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Not already showing and is not shown\n\t\t\t\tif (!this.showing && !this.isShown) {\n\t\t\t\t\treturn $.when(hidePromise || true).then(() => {\n\t\t\t\t\t\t// We are now officially starting to show\n\t\t\t\t\t\tthis.trigger('showing', this);\n\t\t\t\t\t\t// Wait for view to be considered shown\n\t\t\t\t\t\tthis.beforeShown(() => {\n\t\t\t\t\t\t\t// We are now officially shown\n\t\t\t\t\t\t\tthis.trigger('shown', this);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((ex) => {\n\t\t\t\tconsole.error(`Error showing view`, this, '\\n', ex);\n\t\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * showLoaded expects the same event signature as a Backbone.Sync event\n\t * @method\n\t * @param {Netx.Collection|Netx.Model} thing Instance of Netx.Collection or Netx.Model\n\t * @param {mixed} resp Response\n\t * @param {object} opts Request options\n\t */\n\tshowLoaded(thing, resp, opts = {}) {\n\t\t// PSEUDO PROGRESS\n\t\tthis.endProgressSimulation();\n\n\t\t// If this is part of an app view collection - let the view model know\n\t\t// All loading events will bubble up to the app view collection and the main view can make decisions on how to handle it\n\t\tif (\n\t\t\tthis.viewSpec != null &&\n\t\t\tthing != null &&\n\t\t\t!(thing instanceof this.constructor)\n\t\t) {\n\t\t\tthis.viewSpec.trigger('loaded', thing, this);\n\t\t}\n\n\t\tconst el = this.el;\n\n\t\t// Whether we use loading classes or not - we ought to remove this - because we do not check\n\t\t// for loading classes when we call this.showNotLoaded()\n\t\tel.removeAttribute('data-nx-not-loaded');\n\n\t\tthis.checkHasResults();\n\n\t\t// Just because loading is done on the model/collection doesn't mean we have had enough time to deal with the render\n\t\t// You wind up seeing old data for a split second in a lot of places where we utilize .loading to hide information\n\t\tif (opts.loadingClasses !== false) {\n\t\t\tel.removeAttribute('data-nx-loading');\n\t\t\tel.classList.remove('loading-chunk');\n\t\t}\n\n\t\tthis._loadedOnce = true;\n\t}\n\n\t/**\n\t * showLoading expects the same event signature as a Backbone.Request event\n\t * @method\n\t * @param {Netx.Collection|Netx.Model} thing Instance of Netx.Collection or Netx.Model\n\t * @param {object} xhr XHR object\n\t * @param {object} opts Request options\n\t */\n\tshowLoading(thing, xhr, opts = {}) {\n\t\tif (this.showLoadingOnce && this._loadedOnce) {\n\t\t\treturn;\n\t\t}\n\n\t\t// PSEUDO PROGRESS\n\t\tthis.simulateProgress();\n\n\t\tconst el = this.el;\n\n\t\tel.removeAttribute('data-nx-no-assets');\n\t\tel.removeAttribute('data-nx-no-results');\n\n\t\t// TODO: convert over to the pseudo progress?\n\t\t// Just in case - we also monitor this cleanup in remove - do not want a rogue interval out there\n\t\tthis.listenToOnce(dispatcher, 'cart:removed', (assetIds, cartId) => {\n\t\t\tif (this.interval) clearInterval(this.interval);\n\t\t});\n\n\t\t// If this is part of an app view collection - let the view model know\n\t\t// All loading events will bubble up to the app view collection and the main view can make decisions on how to handle it\n\t\t// The only time `thing` is a view is when this is called from the `addedChildView` listener in `addLoadingClasses_internal` method\n\t\tif (\n\t\t\tthis.viewSpec != null &&\n\t\t\tthing != null &&\n\t\t\t!(thing instanceof this.constructor)\n\t\t) {\n\t\t\tthis.viewSpec.trigger('loading', thing, this);\n\t\t}\n\n\t\t// Whether we use loading classes or not - we ought to remove this - because we do not check\n\t\t// for loading classes when we call this.showNotLoaded() - because mainly, we do not have those options\n\t\t// at that time\n\t\tel.removeAttribute('data-nx-not-loaded');\n\n\t\t// Cant test thing here because of inconsistencies in thing\n\t\tif (opts.loadingClasses !== false) {\n\t\t\t(this.collection && this.collection.loadingChunk) ||\n\t\t\t(thing && thing.loadingChunk)\n\t\t\t\t? el.classList.add('loading-chunk')\n\t\t\t\t: el.setAttribute('data-nx-loading', true);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds `not-loaded` attribute to view's el\n\t * @method\n\t */\n\tshowNotLoaded() {\n\t\tconst el = this.el;\n\t\tif (!el) return;\n\n\t\tel.setAttribute('data-nx-not-loaded', true);\n\t}\n\n\t/**\n\t * Simulates progress on this.$pseudoProgressBar until this.endProgressSimulation is called\n\t * @method\n\t */\n\tsimulateProgress() {\n\t\tif (\n\t\t\tthis.simulatingProgress ||\n\t\t\t!this.$pseudoProgressBar ||\n\t\t\t!this.$pseudoProgressBar.length\n\t\t)\n\t\t\treturn;\n\n\t\t// Simulation start\n\t\tthis.simulatingProgress = true;\n\n\t\tconst min = Math.min;\n\t\tconst $pseudoProgressBar = this.$pseudoProgressBar;\n\t\tlet pseudoProgressWidth = 0;\n\n\t\t$pseudoProgressBar.width('0%').attr('aria-valuenow', 0);\n\n\t\tthis.el.setAttribute('data-nx-simulating-progress', true);\n\t\tthis.$pseudoProgress.addClass('active');\n\n\t\tconst draw = () => {\n\t\t\tpseudoProgressWidth = min(\n\t\t\t\tpseudoProgressWidth + (100 - pseudoProgressWidth) * 0.025,\n\t\t\t\t100,\n\t\t\t);\n\n\t\t\t$pseudoProgressBar\n\t\t\t\t.width(pseudoProgressWidth + '%')\n\t\t\t\t.attr('aria-valuenow', pseudoProgressWidth);\n\n\t\t\tthis.simulatingProgress && window.requestAnimationFrame(draw);\n\t\t};\n\t\tdraw();\n\t}\n\n\t/**\n\t * Stop event propagation\n\t * @method\n\t */\n\tstopPropagation(e) {\n\t\te && e.stopPropagation();\n\t}\n\n\t/**\n\t * this.toggle() calls show() if currently hidden, or hide() if currently shown.\n\t * @see {@link Netx.View#show|show}\n\t * @see {@link Netx.View#hide|hide}\n\t * @fires 'shown' on View object\n\t */\n\ttoggle() {\n\t\treturn this.isShown ? this.hide(true) : this.show();\n\t}\n\n\t/**\n\t * @method\n\t */\n\tunbindCollectionEvents() {\n\t\tconst collection = this.listenToCollection || this.collection;\n\t\tif (!collection) return this;\n\n\t\tthis.trigger('unbindCollectionEventsHook', this);\n\n\t\treturn this.stopListening(collection);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tunbindEvents() {\n\t\tthis.hammer && this.hammer.destroy();\n\t\tdelete this.hammer;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t */\n\tunbindModelEvents() {\n\t\tif (!this.model) return this;\n\n\t\tthis.trigger('unbindModelEventsHook', this);\n\n\t\treturn this.stopListening(this.model);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tupdateCount(count) {\n\t\t// Might not have rendered yet\n\t\tif (!this.$count) return;\n\n\t\tif (count == null) {\n\t\t\tconst collection = this.listenToCollection || this.collection;\n\t\t\tif (\n\t\t\t\t!collection ||\n\t\t\t\t!this.$count ||\n\t\t\t\t!this.$count.length ||\n\t\t\t\t(this.requireSync && !collection.syncedOnce)\n\t\t\t)\n\t\t\t\treturn;\n\n\t\t\tcount = collection.getTotal();\n\t\t}\n\n\t\tthis.$count.attr('data-count', count);\n\n\t\tthis.i18nCountStr\n\t\t\t? this.$count.html(\n\t\t\t\t\ti18n.t(this.i18nCountStr, {\n\t\t\t\t\t\tcount: count,\n\t\t\t\t\t\tdefaultValue: '__count__ items',\n\t\t\t\t\t}),\n\t\t\t )\n\t\t\t: this.$count.html(count);\n\n\t\tthis.$count.attr(\n\t\t\t'aria-label',\n\t\t\ti18n.t('i18n.nItems', {\n\t\t\t\tcount: count,\n\t\t\t}),\n\t\t);\n\t}\n\n\t/**\n\t * Add functions to execute at instance initialization\n\t * @method\n\t * @param {function} cb Callback\n\t * @param {string} functionalityName Functionality name\n\t */\n\tstatic addInitializer(cb, functionalityName) {\n\t\t// We must recreate these as a parent class may have already had functionality extended to it,\n\t\t// which means it would have already had an array on the class\n\t\t// The next view that adds functionality would push it into the parent class' array\n\t\t// polluting all children that extended that parent class with another extended class' functionality\n\t\tconst proto = Object.getPrototypeOf(this.prototype);\n\n\t\t// Super already has some functionality\n\t\tif (proto.constructor.__functionality__) {\n\t\t\tthis.__functionality__ = _.unique(\n\t\t\t\tproto.constructor.__functionality__.concat(\n\t\t\t\t\tthis.__functionality__ || [],\n\t\t\t\t),\n\t\t\t).concat([functionalityName]);\n\t\t} else {\n\t\t\tthis.__functionality__ = (this.__functionality__ || []).concat([\n\t\t\t\tfunctionalityName,\n\t\t\t]);\n\t\t}\n\n\t\t// Super already has some functionality\n\t\tif (proto.constructor.__initializers__) {\n\t\t\tthis.__initializers__ = _.unique(\n\t\t\t\tproto.constructor.__initializers__.concat(this.__initializers__ || []),\n\t\t\t).concat([cb]);\n\t\t} else {\n\t\t\tthis.__initializers__ = (this.__initializers__ || []).concat([cb]);\n\t\t}\n\t}\n\n\t/**\n\t * Extend functionality on the view's super\n\t * @method\n\t * @param {object} functionality Functionality to extend\n\t */\n\tstatic extendFunctionality(functionality) {\n\t\tconst proto = Object.getPrototypeOf(this.prototype);\n\t\tconst myProto = Object.getPrototypeOf(this);\n\t\tfor (let prop in functionality) {\n\t\t\tif (functionality.hasOwnProperty(prop)) {\n\t\t\t\tif (!proto[prop]) {\n\t\t\t\t\tproto[prop] = functionality[prop];\n\t\t\t\t} else {\n\t\t\t\t\tmyProto[prop] = functionality[prop];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn proto;\n\t}\n\n\t/**\n\t * Extend functionality on the view's super\n\t * @method\n\t * @param {string} functionalityName Functionality name\n\t * @return {boolean}\n\t */\n\tstatic hasFunctionality(functionalityName) {\n\t\tconst functionality = this.__functionality__ || [];\n\t\treturn functionality.includes(functionalityName);\n\t}\n\n\t/**\n\t * Wrap a method on base view (functionality should not know anything about views extending base)\n\t * @method\n\t * @param {string} methodName Name of method to wrap\n\t * @param {function} cb Callback\n\t */\n\tstatic wrapMethod(methodName, cb) {\n\t\tconst proto = Object.getPrototypeOf(this.prototype);\n\t\tif (!proto[methodName]) return proto;\n\t\tproto[methodName] = _.wrap(proto[methodName], cb);\n\t\treturn proto;\n\t}\n\n\t/** @type {boolean} */\n\tstatic get __isView__() {\n\t\treturn true;\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'View';\n\t}\n}\n\nexport default View;\n","/**\n * @class\n */\nimport Base from '@netx/core/lib/netx-view';\n\nimport ActionsIconInlineTemplate from '@netx/core-app/templates/menuView-actionIconsInline.html';\nimport AssetDetailActionsTemplate from '@netx/core-app/templates/menuView-assetDetailActions.html';\nimport AttributeColumnsContextMenuTemplate from '@netx/core-app/templates/menuView-attributeColumnsContextMenu.html';\nimport AttributeColumnsContextMenuItemTemplate from '@netx/core-app/templates/menuView-attributeColumnsContextMenuItem.html';\nimport CartBarActionsTemplate from '@netx/core-app/templates/menuView-cartBarActions.html';\nimport ContextTemplate from '@netx/core-app/templates/menuView-context.html';\nimport HeaderActionsTemplate from '@netx/core-app/templates/menuView-headerActions.html';\nimport ListHeaderActionsTemplate from '@netx/core-app/templates/menuView-listHeaderActions.html';\nimport NavTabsTemplate from '@netx/core-app/templates/menuView-navTabs.html';\nimport PodActionsTemplate from '@netx/core-app/templates/menuView-podActions.html';\nimport SidebarTemplate from '@netx/core-app/templates/menuView-sidebar.html';\nimport SystemHeaderActionsTemplate from '@netx/core-app/templates/menuView-systemHeaderActions.html';\nimport SystemListTemplate from '@netx/core-app/templates/menuView-systemList.html';\nimport SystemTableActionsTemplate from '@netx/core-app/templates/menuView-systemTableActions.html';\n\n// currently these are the only menu views that can be used\n// but themes can override the templates\nconst MenuTemplates = {\n\tactionIconsInline: ActionsIconInlineTemplate,\n\tassetDetailActions: AssetDetailActionsTemplate,\n\tattributeColumnsContextMenu: AttributeColumnsContextMenuTemplate,\n\tattributeColumnsContextMenuItem: AttributeColumnsContextMenuItemTemplate,\n\tcartBarActions: CartBarActionsTemplate,\n\tcontext: ContextTemplate,\n\theaderActions: HeaderActionsTemplate,\n\tlistHeaderActions: ListHeaderActionsTemplate,\n\tnavTabs: NavTabsTemplate,\n\tpodActions: PodActionsTemplate,\n\tsidebar: SidebarTemplate,\n\tsystemHeaderActions: SystemHeaderActionsTemplate,\n\tsystemList: SystemListTemplate,\n\tsystemTableActions: SystemTableActionsTemplate,\n};\n\nimport {icon} from '@fortawesome/fontawesome-svg-core';\n\nclass View extends Base {\n\t/** @override */\n\tconstructor(opts = {}) {\n\t\tsuper(opts);\n\n\t\tthis.icons = opts.icons || {};\n\t}\n\n\t/** @override */\n\tpreRender() {\n\t\tObject.assign(this.templateVars, {icons: this.icons});\n\n\t\tsuper.preRender();\n\t}\n\n\t/** @method */\n\tinitializedIcons() {\n\t\t// All icons in this view have been installed\n\t}\n\n\t/**\n\t * Material menus\n\t * @override\n\t */\n\tinsertContextMenu(menuName, e) {\n\t\tconst menuOptions = {\n\t\t\tclassName: 'context-menu mdc-menu-surface--anchor',\n\t\t\tmodel: this.model,\n\t\t\tcollection: this.menuCollection || this.collection,\n\t\t\tcontext: true,\n\t\t\tmenu: Netx.Menus[menuName],\n\t\t\tremoveOnHide: true,\n\t\t\tmaterialMenus: {\n\t\t\t\tautoOpen: true,\n\t\t\t},\n\t\t};\n\n\t\t// Look for custom template\n\t\tconst templateName = (this.$el.attr('data-nx-template') || '').replace(\n\t\t\t'menuView-',\n\t\t\t'',\n\t\t);\n\t\tif (templateName != null) {\n\t\t\tmenuOptions.template = MenuTemplates[templateName];\n\t\t}\n\n\t\t// Menu view type\n\t\tconst menuView = (this.menuView = new Netx.Views.MenuView(menuOptions));\n\t\tmenuView.el.style.top = e.pageY + 'px';\n\t\tmenuView.el.style.left = e.pageX + 'px';\n\t\tdocument.body.appendChild(menuView.el);\n\t\tmenuView.render();\n\n\t\t// iOS safari has some real issues\n\t\t// if we do not do something here the menu will either hide immediately\n\t\t// or an action that is now beneath your finger will fire\n\t\tif (/iphone|ipad|ipod/i.test(navigator.userAgent)) {\n\t\t\tdocument.body.style.pointerEvents = 'none';\n\t\t\t_.delay(() => {\n\t\t\t\tdocument.body.style.pointerEvents = 'initial';\n\t\t\t}, 300);\n\t\t}\n\t}\n\n\t/** @override */\n\tremove() {\n\t\tdelete this.icons;\n\t\tsuper.remove();\n\t}\n\n\t/**\n\t * Manually trigger a tooltip on any element in this view\n\t * @method\n\t * @param {string|function} message Message\n\t * @param {element} $el Element to apply tooltip\n\t * @param {object} options Tooltip options\n\t */\n\tshowTooltip(message, $el, options = {}) {\n\t\tmessage = message || '';\n\n\t\tif (!$el) {\n\t\t\tconsole.warn('`this.tooltip` requires an element');\n\t\t\treturn;\n\t\t}\n\n\t\t// Can only do one tooltip at a time per element\n\t\tif ($el.data('bs.tooltip')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Backup original title\n\t\tconst originalTitle = $el.attr('title');\n\t\t$el.attr(\n\t\t\t'title',\n\t\t\t_.isFunction(message) ? message.apply(this, $el) : message,\n\t\t);\n\n\t\t// Support for custom classes on tooltip\n\t\tif (options.className) {\n\t\t\tconst className = _.isFunction(options.className)\n\t\t\t\t? options.className.apply(this, $el)\n\t\t\t\t: options.className;\n\t\t\tif (options.template) {\n\t\t\t\toptions.template = $(options.template).addClass(className)[0].outerHTML;\n\t\t\t} else {\n\t\t\t\t// Default template with class added\n\t\t\t\toptions.template = `
      `;\n\t\t\t}\n\t\t}\n\n\t\t// Initialize tooltip\n\t\treturn this.Plugins.Initialize('manualTooltips', $el, options).then(\n\t\t\t(instances) => {\n\t\t\t\tif (!instances) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t'`this.tooltip` instances were not returned from initialize',\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst instance = instances[0];\n\t\t\t\tif (!instance) return;\n\n\t\t\t\t// Listen once for shown\n\t\t\t\t$el.one('shown.bs.tooltip', () => {\n\t\t\t\t\t_.delay(() => {\n\t\t\t\t\t\t// Listen once for hidden\n\t\t\t\t\t\t$el.one('hidden.bs.tooltip', () => {\n\t\t\t\t\t\t\t// Cleanup\n\t\t\t\t\t\t\tthis.Plugins.Destroy('manualTooltips', $el);\n\t\t\t\t\t\t\toriginalTitle && $el.attr('title', originalTitle);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Hide\n\t\t\t\t\t\tinstance.hide();\n\t\t\t\t\t}, 3000);\n\t\t\t\t});\n\t\t\t\t// Show\n\t\t\t\tinstance.show();\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * @method\n\t * @static\n\t */\n\tstatic initializeIcons(icons, opts) {\n\t\tconst iconOpts = {classes: ['fa-fw'], ...opts};\n\t\tObject.entries(icons).map(([name, faIcon]) => {\n\t\t\ticons[name] = icon(faIcon, iconOpts).html;\n\t\t});\n\t\treturn icons;\n\t}\n}\n\nexport default View;\n","/**\n * Netx.Model extends Backbone.Model, adding just a few handy methods.\n * @class\n * @extends Backbone.ES6Model\n */\n\nimport Backbone from 'backbone';\nimport Netx from '@netx/core/bootstrap';\nimport Rpc from 'core-libs/backbone.rpc';\n\nimport {protectObjectProxy} from '@netx/core/lib/utils';\n\n// Wrap an optional error callback with a fallback error event.\n// This is from the backbone.js file and allows us to override the save\n// method so that we can support rejecting promises when validation fails\nconst wrapError = (model, options) => {\n\tconst error = options.error;\n\toptions.error = function (resp) {\n\t\tif (error) error.call(options.context, model, resp, options);\n\t\tmodel.trigger('error', model, resp, options);\n\t};\n};\n\n// Setup ajv for data validation\nimport Ajv from 'ajv';\nconst ajv = new Ajv({\n\tallErrors: true,\n\tcoerceTypes: true,\n\t$data: true,\n\tmissingRefs: 'ignore',\n\tuseDefaults: 'empty',\n\tnullable: true,\n});\n\n/**\n * Get default values from schema\n * Used to define `this.defaults`\n * @function\n * @param {schema} schema Schema\n * @return {object} Defaults\n */\nconst getDefaultsFromSchema = (schema) => {\n\tconst {properties} = schema;\n\tconst defaults = {};\n\tfor (let key in properties) {\n\t\tif (properties.hasOwnProperty(key)) {\n\t\t\tconst defaultValue = properties[key].default;\n\t\t\tif (typeof defaultValue !== 'undefined') {\n\t\t\t\tdefaults[key] = defaultValue;\n\t\t\t}\n\t\t}\n\t}\n\treturn defaults;\n};\n\nconst BBModel = Backbone.Model;\n// Make a Model we can extend from in other classes\nclass ES6Model {\n\tget schema() {\n\t\treturn this.constructor.Schema;\n\t}\n\n\t/** @override */\n\tconstructor(attrs, opts) {\n\t\tconst schema = this.schema;\n\t\tif (schema) {\n\t\t\t// If we have not explicitely setup our own validation\n\t\t\t// validate via ajv and our provided schema\n\t\t\tif (!this.validate) {\n\t\t\t\tconst ValidateSchema = ajv.compile(schema);\n\t\t\t\tthis.validate = (attrs, opts) => {\n\t\t\t\t\tconst isValid = ValidateSchema(attrs);\n\t\t\t\t\tif (!isValid) {\n\t\t\t\t\t\tconsole.log(this, [...ValidateSchema.errors]);\n\t\t\t\t\t\treturn [...ValidateSchema.errors];\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Set our defaults based on the schema provided\n\t\t\t// If you are coming from the old backbone stuff and want to use schema and extend from another schema\n\t\t\t// you will need to do that in your schema file and not in the model \"defaults\" getter that we have\n\t\t\t// been using\n\t\t\tObject.defineProperty(this, 'defaults', {\n\t\t\t\tget() {\n\t\t\t\t\treturn getDefaultsFromSchema(schema);\n\t\t\t\t},\n\t\t\t\tconfigurable: false,\n\t\t\t});\n\t\t}\n\n\t\tBBModel.call(this, attrs, opts);\n\n\t\t// Always represent `id` on the model's attributes regardless of what the key actually is\n\t\t// I have yet to find a model that is utilizing a key of id for anything but the id\n\t\t// DEVNOTE: Setting this after call to backbone model as `this.attributes` does not exist until then\n\t\tif (schema && schema.primary !== 'id') {\n\t\t\tObject.defineProperty(this.attributes, 'id', {\n\t\t\t\tget: () => {\n\t\t\t\t\treturn this.id;\n\t\t\t\t},\n\t\t\t\tconfigurable: false,\n\t\t\t});\n\t\t}\n\t}\n}\n// Object.assign(ES6Model.prototype, BBModel.prototype);\n_.extend(ES6Model.prototype, BBModel.prototype);\nBackbone.ES6Model = ES6Model;\n\nclass Model extends ES6Model {\n\t/** @override */\n\tget idAttribute() {\n\t\tconst schema = this.schema;\n\t\t// The backbone way (so that we do not have to do every model at once)\n\t\t// Any model that does not use `id` will already be overriding this getter\n\t\tif (!schema) return 'id';\n\n\t\t// The new schema way\n\t\treturn schema.primary;\n\t}\n\n\t/** @type {boolean} */\n\tget isModel() {\n\t\treturn this.constructor.__isModel__;\n\t}\n\n\t// Whelp\n\t// Need to fix in backbone.rpc - the model get's a property of `syncing`\n\t// whether the call is a syncable (read) or not\n\t// And since our loading indication relies on the `request:read` event and the `sync` event\n\t// we will get false loading positives by checking `this.syncing`\n\t// So, check for the `read` method in our current calls list\n\tget isSyncing() {\n\t\treturn this._rpc && this.syncing && this._rpc.callsByName.read != null;\n\t}\n\n\t/**\n\t * The attribute key to find the model's \"title\"\n\t * @type {string}\n\t */\n\tget titleAttribute() {\n\t\treturn 'title';\n\t}\n\n\t// TODO: when we have switched all the way over to the schema pattern we can remove this\n\tget defaults() {\n\t\treturn {};\n\t}\n\n\t/** @type {array} */\n\tget clientAttrs() {\n\t\treturn [];\n\t}\n\n\t/** @type {object} */\n\tget xhrLoadedMessages() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget xhrLoadingMessages() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget methods() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget parsers() {\n\t\treturn {};\n\t}\n\n\t/**\n\t * @method\n\t * @param {object} attrs Model attributes\n\t * @param {object} opts Model options\n\t */\n\tconstructor(attrs, opts = {}) {\n\t\tsuper(attrs, opts);\n\n\t\t// Init backbone.rpc if requested:\n\t\tconst rpc = opts.rpc != null ? opts.rpc : this.rpc;\n\t\tif (rpc === true) {\n\t\t\tthis._rpc = new Rpc();\n\t\t}\n\n\t\t/**\n\t\t * When a stored model should expire\n\t\t * Set to true to persist until explicitly deleted\n\t\t * https://github.com/ozantunca/locally\n\t\t * Forever/Milliseconds/TTL\n\t\t * @type {boolean|integer|string}\n\t\t * @default\n\t\t * @see Netx.Collection\n\t\t */\n\t\tthis.storeOptions = {\n\t\t\tpersist: false,\n\t\t};\n\t\t// Store options\n\t\tif (opts && _.isObject(opts.storeOptions)) {\n\t\t\tthis.storeOptions = _.extend({}, this.storeOptions, opts.storeOptions);\n\t\t\tdelete opts.storeOptions;\n\t\t}\n\n\t\t/**\n\t\t * If we defined the object _unsavedChanges on a Netx.Model, that\n\t\t * object will track every change between syncs. This is useful\n\t\t * for tracking unsaved local changes over time.\n\t\t */\n\t\t// On change events, store the changes.\n\t\tthis.listenTo(this, 'change', (model, options) => {\n\t\t\tif (!_.isObject(this._unsavedChanges)) return;\n\t\t\tif (options && options.silent) return;\n\t\t\t_.extend(this._unsavedChanges, model.changedAttributes());\n\t\t});\n\t\t// On sync events, flush the changes.\n\t\tthis.listenTo(this, 'sync', () => {\n\t\t\tthis.syncedOnce = true;\n\t\t\tif (_.isObject(this._unsavedChanges)) {\n\t\t\t\tthis._unsavedChanges = {};\n\t\t\t}\n\t\t});\n\n\t\t//////////////////////////////////////////\n\t\t// HOUSEKEEPING\n\t\t//////////////////////////////////////////\n\n\t\t// Where will store references to the collection we belong to. We use the _listenId and store only that\n\t\t// That way we are not creating any circular references and do not risk making our garbage collection\n\t\t// even more difficult to deal with in regards to our ghost models\n\t\t// On one hand- it is great to see details about the collection the model claims to belong to in cases\n\t\t// where you are not sure why it still belongs to one - but the cost of storing the actual collection\n\t\t// coul be that neither the model nor the collection ever get collected as the model is listening to some\n\t\t// global object and maintiaining a reference to a collection that should have been garbage collected\n\t\t// which then could be referencing other objects that would have otherwise been garbage collected and so on.\n\t\t// this.debugCollections = [];\n\t\tthis.collections = [];\n\t\t// Backbone never really anticipated (on purpose) that models\n\t\t// would create models and listen to other things (not self) (especially global variables like our dispatcher)\n\t\t// Cleanup\n\t\tthis.listenTo(this, 'remove', (model, collection, opts) => {\n\t\t\t// Each model that creates sub models should be listening for remove and then triggering the same on its sub models\n\t\t\t// That way everything gets cleaned up and memory leaks decline\n\t\t\tthis.removeCollectionReference(collection);\n\t\t});\n\t\tthis.listenTo(this, 'add', (model, collection, opts) => {\n\t\t\t// If we are not already storing a reference - store one\n\t\t\tthis.addCollectionReference(collection);\n\t\t});\n\t\t//////////////////////////////////////////\n\t\t// !HOUSEKEEPING\n\t\t//////////////////////////////////////////\n\t}\n\n\t/**\n\t * @method\n\t * @param {string} perm Permission\n\t * @return {boolean} Allowed\n\t */\n\tallows(perm) {\n\t\tif (perm === 'read' || perm === 'r' || perm === 'download') return true;\n\n\t\tvar permitted = this.get('permission');\n\n\t\t// Nothing we can check\n\t\tif (!permitted) return true;\n\n\t\tswitch (perm) {\n\t\t\tcase 'd':\n\t\t\tcase 'delete':\n\t\t\t\treturn permitted === 'delete' || permitted === 'd';\n\t\t\tcase 'modify':\n\t\t\tcase 'w':\n\t\t\tcase 'edit':\n\t\t\tcase 'write':\n\t\t\t\treturn (\n\t\t\t\t\tpermitted === 'delete' ||\n\t\t\t\t\tpermitted === 'write' ||\n\t\t\t\t\tpermitted === 'd' ||\n\t\t\t\t\tpermitted === 'w'\n\t\t\t\t);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * @override\n\t * @param {Netx.Models.BatchJob} Batch job model\n\t */\n\tbatchJobComplete(batchJob) {\n\t\tvar args = batchJob.get('args') || [];\n\t\tthis.trigger.apply(this, ['complete', this, batchJob].concat(args));\n\t}\n\t/**\n\t * @override\n\t * @param {Netx.Models.BatchJob} Batch job model\n\t * @param {string} error Error\n\t */\n\tbatchJobError(batchJob, error) {\n\t\tvar args = batchJob.get('args') || [];\n\t\tthis.trigger.apply(this, ['error', this, error].concat(args));\n\t}\n\t/**\n\t * @override\n\t * @param {Netx.Models.BatchJob} Batch job model\n\t * @param {number} progress Progress\n\t */\n\tbatchJobProgress(batchJob, progress) {\n\t\tvar args = batchJob.get('args') || [];\n\t\tthis.trigger.apply(\n\t\t\tthis,\n\t\t\t['progress', this, batchJob, progress].concat(args),\n\t\t);\n\t}\n\n\t/**\n\t * There is a fun labels game we play with some of our objects; particularly users\n\t * We need to get our labels on the same page as what we might get from an autolookup\n\t * This method allows less than ideal models to modify how this label is gathered\n\t * @method\n\t * @return {string} Atuocomplete label\n\t */\n\tgetAutocompleteLabel() {\n\t\treturn this.getLabel();\n\t}\n\n\t/**\n\t * @method\n\t * @param {string} method Method name\n\t */\n\tgetRestLoadedMessage(method) {\n\t\tvar messages = this.xhrLoadedMessages || {};\n\t\treturn messages[method];\n\t}\n\t/**\n\t * @method\n\t * @param {string} method Method name\n\t */\n\tgetRestLoadingMessage(method) {\n\t\tvar messages = this.xhrLoadingMessages || {};\n\t\treturn messages[method];\n\t}\n\n\t/**\n\t * this.self() returns just the attributes of a model that are reflected in the DAM;\n\t * it is used in method definitions to omit model attributes that should *not* be\n\t * synced. We use it for cases where the data is structured differently in the\n\t * model than on the wire, and for models that want to have additional attributes\n\t * for local-only reasons.\n\t *\n\t * The default implementation removes any/all client-only attributes defined in the optional array property this.clientAttrs,\n\t * and aggregates ny/all attributes defined in the optional array property this.gooAttrs\n\t * into a single attribute called 'goo'. If neither of those optional properties\n\t * is defined, this.self() returns all model attributes.\n\t * @return {object}\n\t * @method\n\t */\n\tself() {\n\t\t// If we have goo attrs, this will pack them. Otherwise it will return a clone of this.attributes.\n\t\tlet attrs = this.packAttrs();\n\n\t\tconst schema = this.schema;\n\t\t// If we have client-only attrs, omit them.\n\t\t// The new schema way\n\t\tif (schema) {\n\t\t\tattrs = _.omit(attrs, schema.clientSide);\n\t\t}\n\t\t// The old way\n\t\telse if (this.clientAttrs) {\n\t\t\tattrs = _.omit(attrs, this.clientAttrs);\n\t\t}\n\t\t// Cloning so we don't accidentally modify model properties while preparing attributes to be sent to RPC methods\n\t\treturn _.clone(attrs);\n\t}\n\n\t/**\n\t * this.packAttrs(), given an attributes object (usually this.attributes), returns the JSON string\n\t * representation of any/all model properties listed in this.gooAttrs.\n\t * It's used by this.self, when converting from the client-side to the server-side representation.\n\t * @param {string} goo an attributes object. If undefined, this.attributes is used.\n\t * @return {string}\n\t * @method\n\t */\n\tpackAttrs(ungooeyObj) {\n\t\tungooeyObj = ungooeyObj || this.attributes;\n\t\tif (this.gooAttrs) {\n\t\t\tvar clientGoo = JSON.stringify(_.pick(ungooeyObj, this.gooAttrs));\n\n\t\t\t// HACK around bugs in the DAM JSON parser: triple-escape escaped quotes!\n\t\t\tvar serverGoo = clientGoo.replace(/\"/g, '\\\\\"');\n\n\t\t\treturn _.extend({}, _.omit(ungooeyObj, this.gooAttrs), {goo: serverGoo});\n\t\t} else {\n\t\t\treturn ungooeyObj;\n\t\t}\n\t}\n\n\t/**\n\t * this.unpackAttrs(), given an object with packed goo, returns an unpacked version.\n\t * It's used by parsers converting from server-side to client-side representations.\n\t * @param {object} gooeyObj the goo-encoded object\n\t * @return {object} the goo-decoded version.\n\t */\n\tunpackAttrs(gooeyObj) {\n\t\tif (!(this.gooAttrs && gooeyObj && gooeyObj.goo)) {\n\t\t\t// do nothing if model defines no goo.\n\t\t\treturn gooeyObj;\n\t\t}\n\n\t\tvar serverGoo = gooeyObj.goo;\n\t\t// HACK around bugs in the DAM JSON parser: unescape triple-escaped quotes!\n\t\tvar clientGoo = serverGoo.replace(/\\\\\"/g, '\"');\n\n\t\t// with _.omit, delete the goo key\n\t\treturn _.omit(\n\t\t\t_.extend(\n\t\t\t\t{},\n\t\t\t\tgooeyObj,\n\t\t\t\t// with _.pick, only allow goo we've defined in .gooAttrs!\n\t\t\t\t_.pick(JSON.parse(clientGoo), this.gooAttrs),\n\t\t\t),\n\t\t\t'goo',\n\t\t);\n\t}\n\n\t/**\n\t * Overriding because we expect to get back a promise\n\t * when validation or an error in set occurs backbone just returns false\n\t * @override\n\t */\n\tsave(key, val, options) {\n\t\t// Handle both `\"key\", value` and `{key: value}` -style arguments.\n\t\tvar attrs;\n\t\tif (key == null || typeof key === 'object') {\n\t\t\tattrs = key;\n\t\t\toptions = val;\n\t\t} else {\n\t\t\t(attrs = {})[key] = val;\n\t\t}\n\n\t\toptions = _.extend({validate: true, parse: true}, options);\n\t\tvar wait = options.wait;\n\n\t\t// If we're not waiting and attributes exist, save acts as\n\t\t// `set(attr).save(null, opts)` with validation. Otherwise, check if\n\t\t// the model will be valid when the attributes, if any, are set.\n\t\tif (attrs && !wait) {\n\t\t\tif (!this.set(attrs, options)) {\n\t\t\t\tconst error = new Error(`Error setting data`);\n\t\t\t\treturn new $.Deferred().reject(error);\n\t\t\t\t// return false;\n\t\t\t}\n\t\t} else if (!this._validate(attrs, options)) {\n\t\t\tconst error = new Error(`Validation error`);\n\t\t\terror.details = this.validationError;\n\t\t\treturn new $.Deferred().reject(error);\n\t\t\t// return false;\n\t\t}\n\n\t\t// After a successful server-side save, the client is (optionally)\n\t\t// updated with the server-side state.\n\t\tvar model = this;\n\t\tvar success = options.success;\n\t\tvar attributes = this.attributes;\n\t\toptions.success = function (resp) {\n\t\t\t// Ensure attributes are restored during synchronous saves.\n\t\t\tmodel.attributes = attributes;\n\t\t\tvar serverAttrs = options.parse ? model.parse(resp, options) : resp;\n\t\t\tif (wait) serverAttrs = _.extend({}, attrs, serverAttrs);\n\t\t\tif (serverAttrs && !model.set(serverAttrs, options)) return false;\n\t\t\tif (success) success.call(options.context, model, resp, options);\n\t\t\tmodel.trigger('sync', model, resp, options);\n\t\t};\n\t\twrapError(this, options);\n\n\t\t// Set temporary attributes if `{wait: true}` to properly find new ids.\n\t\tif (attrs && wait) this.attributes = _.extend({}, attributes, attrs);\n\n\t\tvar method = this.isNew() ? 'create' : options.patch ? 'patch' : 'update';\n\t\tif (method === 'patch' && !options.attrs) options.attrs = attrs;\n\t\tvar xhr = this.sync(method, this, options);\n\n\t\t// Restore attributes.\n\t\tthis.attributes = attributes;\n\n\t\treturn xhr;\n\t}\n\n\t/**\n\t * Keep track of any models or collections that may be attributes on the model\n\t * @override\n\t */\n\tset(key, val, options) {\n\t\tif (_.isObject(key)) {\n\t\t\t_.each(\n\t\t\t\tkey,\n\t\t\t\tfunction (v, k) {\n\t\t\t\t\tif (!v) return;\n\n\t\t\t\t\tif (v instanceof this.constructor) {\n\t\t\t\t\t\tthis.addSubModel(v);\n\t\t\t\t\t} else if (v && v.isModel) {\n\t\t\t\t\t\tthis.addSubCollection(v);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tthis,\n\t\t\t);\n\t\t} else if (val) {\n\t\t\tif (val instanceof this.constructor) {\n\t\t\t\tthis.addSubModel(val);\n\t\t\t} else if (val.isCollection) {\n\t\t\t\tthis.addSubCollection(val);\n\t\t\t}\n\t\t}\n\n\t\treturn super.set(key, val, options);\n\t}\n\n\t/**\n\t * @method\n\t * @return {object} Defaults\n\t */\n\tgetDefaults() {\n\t\treturn this.constructor.GetDefaults();\n\t}\n\n\t/**\n\t * @method\n\t * @return {number}\n\t */\n\tgetIndex() {\n\t\treturn this.collection ? this.collection.indexOf(this) : -1;\n\t}\n\n\t/**\n\t * A general-purpose function for getting a UI-compliant label for an object.\n\t * This function can & should be overridden in all child classes.\n\t * @method\n\t * @return {string} Label (title)\n\t */\n\tgetLabel() {\n\t\treturn this.get(this.titleAttribute);\n\t}\n\n\t/**\n\t * Object Polling:\n\t * pollUntil() tells any model/collection to do something repeatedly until a conditional test passes,\n\t * emitting appropriate events along the way. Use this to follow DAM changes to certain object properties,\n\t * or to check status until a status change.\n\t *\n\t * @param {function} doneTest A function that returns true if polling should finish. (Required)\n\t * @param {string} eventPrefix Event string prefix for polling events. If undefined, no events are triggered.\n\t * @param {function} pollMethod A function that causes a poll. Must return a promise. Defaults to this.fetch;\n\t * @param {number} pollInterval Milliseconds between polls. Defaults to 500.\n\t * @param {object} pollMethodOptions Options to pass to the RPC method\n\t * @method\n\t * @todo convert params to a single object so that we can add/remove options without needing to modify every piece of code that utilizes this method\n\t * (you know, unless they NEED to be updated)\n\t */\n\tpollUntil(\n\t\tdoneTest,\n\t\teventPrefix,\n\t\tpollMethod,\n\t\tpollInterval,\n\t\tpollMethodOptions,\n\t) {\n\t\t// Vars\n\t\tvar d = new $.Deferred(),\n\t\t\tself = this;\n\n\t\tif (!_.isFunction(doneTest)) {\n\t\t\tthrow new Error('pollUntil: doneTest argument is not a function.');\n\t\t}\n\n\t\tpollMethodOptions = pollMethodOptions || {};\n\t\tpollInterval = pollInterval || 500; // ms\n\n\t\tpollMethod =\n\t\t\tpollMethod ||\n\t\t\tfunction () {\n\t\t\t\tif (_.isFunction(self.fetch)) return self.fetch(pollMethodOptions);\n\t\t\t\tthrow new Error('default poll method (fetch) not defined.');\n\t\t\t};\n\n\t\tif (this._polling) {\n\t\t\t// We are already polling.\n\t\t\tconsole.warn('This instance is already polling');\n\t\t\treturn this._polling.promise();\n\t\t}\n\n\t\t// Method for when we're finished:\n\t\tvar finished = function () {\n\t\t\tself._polling.resolveWith(self);\n\t\t\tif (eventPrefix) {\n\t\t\t\tdispatcher.trigger.apply(\n\t\t\t\t\tdispatcher,\n\t\t\t\t\t[\n\t\t\t\t\t\teventPrefix +\n\t\t\t\t\t\t\t(self._stopPolling ? ':stoppedPolling' : ':donePolling'),\n\t\t\t\t\t].concat(_.toArray(arguments)),\n\t\t\t\t);\n\t\t\t}\n\t\t\tdelete self._polling;\n\t\t\tdelete self._stopPolling;\n\t\t};\n\n\t\ttry {\n\t\t\t// Pass undefined so that we may differentiate between the first test and the rest\n\t\t\tif (doneTest.apply(this, [undefined])) {\n\t\t\t\t// We don't even need to poll.\n\t\t\t\tfinished();\n\t\t\t\treturn d.promise();\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\t// doneTest() might fail without proper arguments. If so, assume that means 'false'.\n\t\t\t// That means we're going to have to poll at least once in order to perform this test.\n\t\t}\n\n\t\tvar loop = function () {\n\t\t\tpollMethod.call(self, pollMethodOptions).then(\n\t\t\t\tfunction (response) {\n\t\t\t\t\t// For those cases that the server sends an error as a success\n\t\t\t\t\tif (_.isObject(response) && response.error) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t'Server sent error as success. \\nModule :',\n\t\t\t\t\t\t\tself.module,\n\t\t\t\t\t\t\t'\\nModel :',\n\t\t\t\t\t\t\tself,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn d.reject(\n\t\t\t\t\t\t\tnew Error(response.error.message || response.error),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (eventPrefix) {\n\t\t\t\t\t\tdispatcher.trigger.apply(\n\t\t\t\t\t\t\tdispatcher,\n\t\t\t\t\t\t\t[eventPrefix + ':polled'].concat(_.toArray(arguments)),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (this._stopPolling || doneTest.apply(self, arguments)) {\n\t\t\t\t\t\t// Done!\n\t\t\t\t\t\tfinished.apply(self, arguments);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t_.delay(loop, pollInterval);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t},\n\t\t\t\tfunction (err) {\n\t\t\t\t\td.reject(err);\n\t\t\t\t\tif (eventPrefix) {\n\t\t\t\t\t\tdispatcher.trigger.apply(\n\t\t\t\t\t\t\tdispatcher,\n\t\t\t\t\t\t\t[eventPrefix + ':errorPolling', err.message].concat(\n\t\t\t\t\t\t\t\t_.toArray(arguments),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t); // use instead (becuase verbs are better?)\n\t\t\t\t\t\t// This would be nicer & more right:\n\t\t\t\t\t\t// dispatcher.applyTrigger( eventPrefix + ':errorPolling', arguments);\n\t\t\t\t\t}\n\t\t\t\t\tdelete this._polling;\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\n\t\t// Save the deferred as this._polling, to show we're polling.\n\t\tthis._polling = d;\n\t\tif (eventPrefix) {\n\t\t\tdispatcher.trigger.apply(\n\t\t\t\tdispatcher,\n\t\t\t\t[eventPrefix + ':startedPolling'].concat(_.toArray(arguments)),\n\t\t\t);\n\t\t}\n\t\tloop();\n\n\t\treturn this._polling.promise();\n\t}\n\n\t/**\n\t * stopPolling() halts any poll loop currently in process.\n\t */\n\tstopPolling() {\n\t\tif (this._polling) {\n\t\t\tthis._stopPolling = true;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t * @param {string} uuid UUID\n\t * @param {array} args Arguments\n\t * @return {Netx.Models.BatchJob}\n\t * @fires module:app#app:pollBatchJob\n\t */\n\ttrackBatchJob(uuid, args, pollInterval) {\n\t\t// Poll\n\t\tvar batchJob = Netx.app.batchJobs.get(uuid);\n\t\tif (!batchJob) {\n\t\t\tdispatcher.trigger(\n\t\t\t\t'app:pollBatchJob',\n\t\t\t\tuuid,\n\t\t\t\tnull,\n\t\t\t\tfalse,\n\t\t\t\targs,\n\t\t\t\tpollInterval,\n\t\t\t);\n\t\t\tbatchJob = Netx.app.batchJobs.get(uuid);\n\t\t}\n\t\tif (batchJob) {\n\t\t\tthis.listenToOnce(batchJob, 'complete', function (batchJob) {\n\t\t\t\tthis.stopListening(batchJob);\n\t\t\t\tthis.batchJobComplete(batchJob);\n\t\t\t});\n\t\t\tthis.listenToOnce(batchJob, 'error', function (batchJob, error) {\n\t\t\t\tthis.stopListening(batchJob);\n\t\t\t\tthis.batchJobError(batchJob, error);\n\t\t\t});\n\t\t\tthis.listenTo(batchJob, 'change:percentComplete', function (\n\t\t\t\tbatchJob,\n\t\t\t\tprogress,\n\t\t\t) {\n\t\t\t\tthis.batchJobProgress(batchJob, progress);\n\t\t\t});\n\t\t}\n\t\treturn batchJob;\n\t}\n\n\t/**\n\t * A scoped version of jQuery.when(), that always uses 'this' as the context for the promise it returns.\n\t * It's also able to accept an array of promises, so we don't need to use .apply to make it go.\n\t */\n\twhen() {\n\t\t// Vars\n\t\tvar d = new $.Deferred(),\n\t\t\tself = this,\n\t\t\tresolve = function () {\n\t\t\t\td.resolveWith(self, arguments);\n\t\t\t},\n\t\t\treject = function () {\n\t\t\t\td.rejectWith(self, arguments);\n\t\t\t},\n\t\t\tprogress = function () {\n\t\t\t\td.notifyWith(self, arguments);\n\t\t\t};\n\n\t\t// If the first argument is an array of promises, we ignore the others.\n\t\tvar arg0 = _.first(arguments);\n\t\tif (_.isArray(arg0) && arg0.length > 0) {\n\t\t\t$.when.apply($, arg0).then(resolve, reject, progress);\n\t\t} else {\n\t\t\t$.when.apply($, arguments).then(resolve, reject, progress);\n\t\t}\n\n\t\treturn d.promise();\n\t}\n\n\t//////////////////////////////////////////\n\t// HOUSEKEEPING\n\t//////////////////////////////////////////\n\t/**\n\t * Keep track of the collections I belong to\n\t * @method\n\t * @param {Netx.Collection} collection Collection\n\t */\n\taddCollectionReference(collection) {\n\t\tif (collection && this.collections) {\n\t\t\tif (_.indexOf(this.collections, collection._listenId) < 0) {\n\t\t\t\tif (!collection._listenId) return;\n\t\t\t\tthis.collections.push(collection._listenId);\n\t\t\t\t// this.debugCollections[ collection._listenId ] = collection;\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * Keep track of the collections I belong to\n\t * @method\n\t * @param {Netx.Collection} collection Collection\n\t */\n\tremoveCollectionReference(collection) {\n\t\tif (this.collections) {\n\t\t\tif (collection) {\n\t\t\t\tvar idx = _.indexOf(this.collections, collection._listenId);\n\t\t\t\tif (idx > -1) {\n\t\t\t\t\tthis.collections.splice(idx, 1);\n\t\t\t\t\t// delete this.debugCollections[ collection._listenId ];\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Give it time and see if we may have been added to another collection before checking length\n\t\t\t_.defer(\n\t\t\t\t_.bind(function () {\n\t\t\t\t\tif (!this.collections.length) {\n\t\t\t\t\t\tthis.garbageCollect();\n\t\t\t\t\t}\n\t\t\t\t}, this),\n\t\t\t);\n\t\t}\n\t}\n\t/**\n\t * Call this when manually adding a sub collection\n\t * @method\n\t * @param {Netx.Collection} collection Collection to track\n\t */\n\taddSubCollection(collection) {\n\t\tif (collection) {\n\t\t\tif (!_.isObject(this.subCollections)) this.subCollections = {};\n\t\t\t// In very rare situations some collections do not have their _listenId yet\n\t\t\t// Defer seems to solve it and I cannot recreate any further\n\t\t\t_.defer(\n\t\t\t\t_.bind(function () {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.subCollections &&\n\t\t\t\t\t\t_.isUndefined(this.subCollections[collection._listenId])\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.subCollections[collection._listenId] = collection;\n\t\t\t\t\t}\n\t\t\t\t}, this),\n\t\t\t);\n\t\t}\n\t\treturn this;\n\t}\n\t/**\n\t * Call this when manually removing a sub collection\n\t * @method\n\t * @param {Netx.Collection} collection Collection to cleanup\n\t */\n\tremoveSubCollection(collection) {\n\t\tif (\n\t\t\tcollection &&\n\t\t\tcollection._listenId &&\n\t\t\t!_.isUndefined(this.subCollections[collection._listenId])\n\t\t) {\n\t\t\tcollection.garbageCollect();\n\t\t\tdelete this.subCollections[collection._listenId];\n\t\t}\n\t\treturn this;\n\t}\n\t/**\n\t * Call this when manually adding a sub model\n\t * @method\n\t * @param {Netx.Model} model Model to track\n\t */\n\taddSubModel(model) {\n\t\tif (!_.isObject(this.subModels)) this.subModels = {};\n\t\tif (_.isUndefined(this.subModels[model._listenId])) {\n\t\t\tthis.subModels[model._listenId] = model;\n\t\t}\n\t\treturn this;\n\t}\n\t/**\n\t * Call this when manually removing a sub model\n\t * @method\n\t * @param {Netx.Model} model Model to cleanup\n\t */\n\tremoveSubModel(model) {\n\t\tif (\n\t\t\tmodel &&\n\t\t\tmodel._listenId &&\n\t\t\t!_.isUndefined(this.subModels[model._listenId])\n\t\t) {\n\t\t\t// Hotfix for DAM-6402 -- revisit in 8.6 . This solves a mistaken assumption about references,\n\t\t\t// but it un-solves a memory leak ...\n\t\t\t// model.trigger('remove', model, null, null);\n\t\t\tdelete this.subModels[model._listenId];\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Subscribe to websocket\n\t * @method\n\t */\n\tsubscribe() {\n\t\tif (!this.socket) {\n\t\t\tif (this.roomName == null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'`this.roomName` is not set. Cannot subscribe to websocket channel.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tvar socket = (this.socket = Netx.websocket);\n\t\t\tthis.listenTo(\n\t\t\t\tsocket,\n\t\t\t\t'socket:message:' + this.roomName,\n\t\t\t\tthis.subscriptionMessage,\n\t\t\t);\n\t\t\tsocket.subscribe(this.roomName);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Message received from websocket channel\n\t * @method\n\t * @param {object} data Message data\n\t */\n\tsubscriptionMessage(data) {\n\t\tswitch (data.action) {\n\t\t\tcase 'edit':\n\t\t\t\tthis.set(data.dto);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Unsubscribe from websocket\n\t * @method\n\t */\n\tunsubscribe() {\n\t\tif (this.socket) {\n\t\t\tif (this.roomName == null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'`this.roomName` is not set. Cannot unsubscribe from websocket channel.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.socket.unsubscribe(this.roomName);\n\t\t\tthis.stopListening(this.socket);\n\t\t\tthis.socket = false;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Severs all ties to the world so it can be eligible for garbage collection\n\t * @method\n\t */\n\tgarbageCollect() {\n\t\tthis._rpc && this._rpc.garbageCollect();\n\n\t\t// Let go of any websocket channels\n\t\tthis.unsubscribe();\n\t\t// Let go of event listeners\n\t\tthis.stopListening().off();\n\t\tthis.clear();\n\n\t\t// Loop over sub models and trigger their cleanup\n\t\tif (_.isObject(this.subModels)) {\n\t\t\t// Hotfix for DAM-6402 -- ditto to above.\n\t\t\t// _.each( this.subModels, function( m ) {\n\t\t\t// \tm.trigger('remove', m, null, null);\n\t\t\t// } );\n\t\t\tdelete this.subModels;\n\t\t}\n\t\t// Loop over sub collection and trigger their cleanup\n\t\tif (_.isObject(this.subCollections)) {\n\t\t\t_.each(this.subCollections, function (c) {\n\t\t\t\tc.garbageCollect();\n\t\t\t});\n\t\t\tdelete this.subCollections;\n\t\t}\n\n\t\tthis.garbageCollected = true;\n\n\t\treturn this;\n\t}\n\t/**\n\t * Backbone.Model.destroy() returns false -- not a promise -- if the model is new;\n\t * it presumes the server doesn't have the model, and doesn't need to be contacted.\n\t *\n\t * That's reasonable ... but every other sync method always returns a promise,\n\t * and we've written all our code presuming destroy() always returns a promise,\n\t * so at this point we're making it Netx policy that Netx.Model.destroy()\n\t * _always_ returns a promise.\n\t *\n\t * @param {objct} opts sync args\n\t * @returns {Promise}\n\t */\n\tdestroy(opts) {\n\t\tconst retVal = super.destroy(opts);\n\t\tif (!_.isPromise(retVal)) {\n\t\t\treturn this.when(); // a pre-resolved promise with correct context.\n\t\t} else {\n\t\t\treturn retVal;\n\t\t}\n\t}\n\t//////////////////////////////////////////\n\t// !HOUSEKEEPING\n\t//////////////////////////////////////////\n\n\t/**\n\t * Our defaults could be an object or a function that returns an object\n\t * Do not make others figure this out everytime the defaults are neeeded\n\t * @method\n\t * @return {object} Model defaults (cloned so you do not risk polluting the prototype)\n\t */\n\tstatic GetDefaults() {\n\t\tif (!this.Schema) return this.prototype.defaults;\n\t\treturn getDefaultsFromSchema(this.Schema);\n\t}\n\n\t/**\n\t * The attribute key to find the model's \"title\"\n\t * @type {string}\n\t */\n\tstatic get TitleAttribute() {\n\t\treturn this.prototype.titleAttribute;\n\t}\n\n\t/**\n\t * Netx.Model.*.Load() (experimental) takes a unique ID and converts into a server populated model instance.\n\t * It returns a promise for the eventual object.\n\t * @param {number} id Id that corresponds to the model's idAttribute.\n\t * @todo Load() would be handy for a wide variety of collections.\n\t * To get it to all of them we'd need to add the Load class method to Netx.Collection.\n\t */\n\tstatic Load(id) {\n\t\t// Setting the idAttribute on instantiation does not work in Backbone.\n\t\t// So we must explicitly set idAttribute after the instance has been created\n\t\tconst a = new this();\n\t\tconst idAttr = this.prototype.idAttribute || 'id';\n\n\t\treturn a\n\t\t\t.set(idAttr, id)\n\t\t\t.fetch()\n\t\t\t.then(() => {\n\t\t\t\treturn a;\n\t\t\t});\n\t}\n\n\t/**\n\t * @method\n\t * @param {schema} schema Schema\n\t */\n\tstatic SetSchema(schema) {\n\t\tObject.defineProperty(this, 'Schema', {\n\t\t\tvalue: protectObjectProxy(schema),\n\t\t\tconfigurable: false,\n\t\t\twritable: false,\n\t\t});\n\t}\n\n\t/** @type {boolean} */\n\tstatic get __isModel__() {\n\t\treturn true;\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'Model';\n\t}\n}\n\nexport default Model;\n","/**\n * Netx.Collection extends Backbone.Collection and allows us to add functionality\n * outside of the default Backbone methods and properties\n * @class\n */\n\nimport Backbone from 'backbone';\nimport Rpc from 'core-libs/backbone.rpc';\nimport Model from './netx-model';\n\nconst BBCollection = Backbone.Collection;\nBBCollection.prototype.reset = _.wrap(BBCollection.prototype.reset, function (\n\treset,\n\tmodels,\n\toptions = {},\n) {\n\t// WARNING: Do not get it in your head, as I did, that we can and should trigger 'add'/'remove' events here\n\t// it really messes up backgrid and I am sure there is a reason why reset is used in some cases and that it\n\t// is so sneaky about its operations\n\n\t// With reset Backbone basically just circumvents all the official channels of removing models and does it all in hush hush secrecy\n\t// Two things:\n\t// We want tour models to know that they have been removed so they can have a chance to clean themselves up\n\t// We want to handle any local storage cleanup resulting from this reset as well\n\n\t!options.filtering &&\n\t\tthis.each((model) => {\n\t\t\t// Reference to collection\n\t\t\tif (model.removeCollectionReference) {\n\t\t\t\tmodel.removeCollectionReference(this);\n\t\t\t}\n\t\t\t// Local storage\n\t\t\tif (_.isFunction(this.modelRemoved)) {\n\t\t\t\tthis.modelRemoved(model);\n\t\t\t}\n\t\t});\n\n\t// Super - let backbone do its thing\n\treset.call(this, models, options);\n\n\t// Let any models that came in know\n\t// This also deals with `new Netx.Collection( models )` as in Bacbone.Collection constructor\n\t// they use this.reset( models, _.extend( { silent: true }, options ) );\n\tthis.each((model) => {\n\t\t// Reference to collection\n\t\tif (model.addCollectionReference) model.addCollectionReference(this);\n\t\t// Local storage\n\t\tif (_.isFunction(this.modelAdded)) this.modelAdded(model);\n\t});\n});\n\n// Make a Collection we can extend from in other classes\nclass ES6Collection {\n\t/** @override */\n\tconstructor(models, opts) {\n\t\tBBCollection.apply(this, arguments);\n\t}\n}\n_.extend(ES6Collection.prototype, BBCollection.prototype, {\n\t/**\n\t * The underscore `indexOf` extension here is always returning -1\n\t * but a vanilla `indexOf` works just fine :/\n\t * @override\n\t */\n\tindexOf(model) {\n\t\treturn this.models.indexOf(model);\n\t},\n\t/**\n\t * Check for our es6 instance instead\n\t * @override\n\t */\n\t_isModel(model) {\n\t\treturn (\n\t\t\tmodel instanceof Backbone.ES6Model || model instanceof Backbone.Model\n\t\t);\n\t},\n});\nBackbone.ES6Collection = ES6Collection;\n\nclass Collection extends ES6Collection {\n\t/** @type {boolean} */\n\tget isCollection() {\n\t\treturn this.constructor.__isCollection__;\n\t}\n\n\t// Whelp\n\t// Need to fix in backbone.rpc - the model get's a property of `syncing`\n\t// whether the call is a syncable (read) or not\n\t// And since our loading indication relies on the `request:read` event and the `sync` event\n\t// we will get false loading positives by checking `this.syncing`\n\t// So, check for the `read` method in our current calls list\n\tget isSyncing() {\n\t\treturn this._rpc && this.syncing && this._rpc.callsByName.read != null;\n\t}\n\n\t/** @type {object} */\n\tget methods() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget parsers() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget rpc() {\n\t\treturn false;\n\t}\n\n\t/** @type {object} */\n\tget templateProps() {\n\t\treturn this;\n\t}\n\n\t/** @type {object} */\n\tget xhrLoadedMessages() {\n\t\treturn {};\n\t}\n\n\t/** @type {object} */\n\tget xhrLoadingMessages() {\n\t\treturn {};\n\t}\n\n\t/**\n\t * @override\n\t * @param {array} models Models array\n\t * @param {object} options Collection options\n\t */\n\tconstructor(models, opts = {}) {\n\t\t// Circular reference\n\t\t// Model = require('./netx-model.js');\n\n\t\topts.model = opts.model || Model;\n\t\tsuper(models, opts);\n\n\t\tconst rpc = opts.rpc != null ? opts.rpc : this.rpc;\n\t\tif (rpc === true) {\n\t\t\tthis._rpc = new Rpc();\n\t\t}\n\n\t\tthis.sorter = opts.sorter;\n\n\t\t/**\n\t\t * Override this in your collection if you want to store your models locally\n\t\t * If you create two collections of the same type and wish to keep the data seperate in the store\n\t\t * override this in your initialization of the collection and give a different name\n\t\t * Like var secondaryNotifications = new Netx.Collection.Notifications([], { localStorageKey: 'secondary-notifications' })\n\t\t * @note: This will only store the attributes - you can not store object references, etc\n\t\t * @param {object} options\n\t\t */\n\t\tthis.localStorageKey = opts.localStorageKey || null;\n\t\t/** @type {number} */\n\t\tthis.maxStore = opts.maxStore || 100;\n\n\t\t/**\n\t\t * @type {string}\n\t\t */\n\t\tthis.filterStr = opts.filterStr || '';\n\n\t\t/**\n\t\t * Tracks models in local storage\n\t\t * @memberof module:core/lib/netx-collection\n\t\t * @alias stored\n\t\t * @type {array}\n\t\t */\n\t\tthis.stored = [];\n\n\t\t// Hey, listen!\n\t\tthis.listenTo(this, 'add', this.modelAdded)\n\t\t\t.listenTo(this, 'change', this.modelChanged)\n\t\t\t.listenTo(this, 'remove', this.modelRemoved)\n\t\t\t.listenTo(this, 'sync', () => {\n\t\t\t\tthis.syncedOnce = true;\n\t\t\t});\n\n\t\t// Load data\n\t\t// Defer to give everything a chance to finish initialization\n\t\t// TODO: deferLocalStorage property here is not used elsewhere, and is weird\n\t\t// TODO: defering pager listening\n\t\t// allows inherrting class construtors\n\t\t// to go first, not ideal, hard to test\n\t\t_.defer(() => {\n\t\t\tif (!this.deferLocalStorage && this.localStorageKey) {\n\t\t\t\tthis.loadLocalStorage();\n\t\t\t}\n\n\t\t\tif (this.pager) {\n\t\t\t\tthis.listenTo(this.pager, 'change:itemTotal', (pager, total) => {\n\t\t\t\t\tthis.trigger('updatedTotal', this);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * We have some models that utilize the key `attributes` for things like attribute templates\n\t * @override\n\t * @param {number|object|string|Backbone.Model} obj Either a model, raw model attribute data, or a model cid/id\n\t * @return {Backbone.Model}\n\t */\n\tget(obj) {\n\t\tif (obj == null) {\n\t\t\treturn void 0;\n\t\t}\n\n\t\t// There is no reason, I can find in the backbone code to be passing models to this - you could just use\n\t\t// `collection.get()`\n\t\t// I suppose it is for brevity, they do not have to check if the object is a model or raw attributes when looping\n\t\t// over the data provided in add/reset/set, it can just check if the model exists in the collection by passing the object or model\n\t\t// But to assume that the existence of an `attributes` property makes this a model is not good for us\n\t\tif (obj.attributes && this._isModel(obj)) {\n\t\t\tif (obj.cid && this._byId[obj.cid]) {\n\t\t\t\treturn this._byId[obj.cid];\n\t\t\t}\n\t\t\tobj = obj.attributes;\n\t\t}\n\t\t// At this point it should either by an id, cid or a raw object of attributes (set/reset/add)\n\t\t// `_byId` is an object indexed twice, once by id and then cid\n\t\t// If you are ever having issues with this method, check the state of `this._byId`.\n\t\treturn this._byId[obj] || this._byId[this.modelId(obj)];\n\t}\n\n\t/**\n\t * Add model to session storage\n\t * @note It will only store the attributes (and only the attributes which do not reference other objects directly)\n\t * This is because we can only store json strings in the local/session storage\n\t * @param {Netx.Model} model Instance of Netx.Model\n\t */\n\taddToLocalStorage(model) {\n\t\tif (!model || !this.localStorageKey) return;\n\n\t\t// Keep in bounds of this.maxStore\n\t\tthis.checkMaxStore();\n\t\t// Model key\n\t\tconst keyName = [this.localStorageKey, model.id].join('');\n\t\t// To persist or not\n\t\tconst persist = model.storeOptions.persist;\n\n\t\t// Set the value\n\t\t// TODO: implement this in the model itself? (model.toLocalStorage() or similar.)\n\t\tconst store = Netx.store;\n\t\tstore.set(keyName, this.parseLocalStorageModelOut(_.clone(model.self())));\n\t\t// Add to beginning of this.stored array\n\t\tthis.stored.unshift(model.id);\n\t\t// Keep until explicitly removed\n\t\tif (persist === true) {\n\t\t\tstore.persist(keyName);\n\t\t}\n\t\t// Expires\n\t\telse if (_.isString(persist) || _.isNumber(persist)) {\n\t\t\tstore.expire(keyName, persist);\n\t\t}\n\t}\n\n\t/**\n\t * Enforce this.maxStore\n\t * @method\n\t */\n\tcheckMaxStore() {\n\t\tif (!this.maxStore || this.stored.length < this.maxStore - 1) return;\n\n\t\t// Amount to rmeove\n\t\tconst count = this.stored.length - this.maxStore + 1;\n\t\t// Items to remove\n\t\tconst items = _.last(this.stored, count);\n\t\t// Loop over and remove them\n\t\t_.each(items, (id) => this.removeFromLocalStorage(this.get(id)));\n\t}\n\n\t/**\n\t * Clear out session storage for this.localStorageKey\n\t * @method\n\t */\n\tclearLocalStorage() {\n\t\tif (!this.localStorageKey) return;\n\n\t\tconst store = Netx.store;\n\t\t// Match all my model keys\n\t\tconst regexp = new RegExp(['^', this.localStorageKey, '.*'].join(''));\n\t\tstore.remove(store.keys(regexp));\n\t\tthis.stored = [];\n\t}\n\n\t/**\n\t * Perform a deeper clone than the Backbone standard: also clone the collection's models.\n\t * @method\n\t */\n\tdeepClone() {\n\t\tconst clone = this.clone();\n\t\tclone.reset([], {silent: true});\n\t\tclone.set(this.map((model) => model.attributes));\n\n\t\t// Make sure our pagers match as well\n\t\t// todo: this would fail for collections\n\t\t// that don't create a pager on init\n\t\t// like netx-collection\n\t\tif (this.pager) {\n\t\t\tclone.pager.set({...this.pager.attributes});\n\t\t}\n\n\t\treturn clone;\n\t}\n\n\t/**\n\t * @method\n\t * @param {array} ids Model ids to delete\n\t */\n\tdeleteMultiple(ids) {\n\t\tif (ids.isCollection) {\n\t\t\tids = ids.ids();\n\t\t}\n\n\t\treturn $.when.apply(\n\t\t\t$,\n\t\t\tthis.chain() // .chain() lets us perform a stream of tasks.\n\t\t\t\t.filter((item) => ids.indexOf(item.id) > -1) // returns just the objects on the list.\n\t\t\t\t.invoke('destroy', {wait: true}) // calls 'destroy' on each one of those objects, waits for server response\n\t\t\t\t.value(), // returns an array of promises, one returned by each 'destroy' call.\n\t\t);\n\t}\n\n\t/**\n\t * Now that all model views contain the [data-nx-model-id] attribute on their elements,\n\t * this utility function can find a model given a DOM event from that model's view\n\t */\n\tgetModelIdFromEvent(e) {\n\t\tconst id = parseInt(\n\t\t\t$(e.target).closest('[data-nx-model-id]').attr('data-nx-model-id'),\n\t\t);\n\t\treturn this.get(id);\n\t}\n\n\t/**\n\t * Get size information on localStorage\n\t * http://blog.blakesimpson.co.uk/read/46-check-size-of-localstorage-usage-in-chrome\n\t * @method\n\t * @deprecate\n\t * @note not to be used heavily\n\t * @return {object} totals\n\t */\n\tgetLocalStorageSize() {\n\t\tlet amount = 0;\n\t\tlet total = 0;\n\t\tlet myTotal = 0;\n\t\tconst regexp = new RegExp(['^', this.localStorageKey, '.*'].join(''));\n\n\t\tfor (let x in localStorage) {\n\t\t\tamount = (localStorage[x].length * 2) / 1024 / 1024;\n\t\t\ttotal += amount;\n\t\t\tif (x.match(regexp)) myTotal += amount;\n\t\t}\n\n\t\tconsole.log('My total: ' + myTotal.toFixed(10) + ' MB');\n\t\tconsole.log('Total: ' + total.toFixed(10) + ' MB');\n\n\t\treturn {\n\t\t\tmyTotal: myTotal,\n\t\t\ttotal: total,\n\t\t};\n\t}\n\n\t/**\n\t * @method\n\t * @return {number} Total\n\t */\n\tgetTotal() {\n\t\tif (this.length && this.pager) {\n\t\t\tconst total = this.pager.get('itemTotal');\n\t\t\tif (total < this.length) {\n\t\t\t\treturn this.length;\n\t\t\t}\n\t\t\treturn total;\n\t\t}\n\n\t\tif (_.isFunction(this.assetCount)) {\n\t\t\treturn this.assetCount();\n\t\t}\n\n\t\treturn this.length;\n\t}\n\n\t/*\n\t * @method\n\t * @param {number} page Page number\n\t * @param {object} opts Options\n\t */\n\tgotoPage(page, opts) {\n\t\tif (page === this.curPage) {\n\t\t\treturn new $.Deferred().resolveWith(this);\n\t\t}\n\n\t\tthis.curPage = parseInt(page);\n\t\t// Getting a page for detail view\n\t\treturn this.fetch(_.extend({duplicateQueryPolicy: 'abort'}, opts));\n\t}\n\n\t/**\n\t * Return an array of the IDs of the models in this collection.\n\t * @method\n\t */\n\tids() {\n\t\treturn this.pluck(this.model.prototype.idAttribute);\n\t}\n\n\t/**\n\t * @method\n\t * @return {boolean}\n\t */\n\tisFiltered() {\n\t\treturn this.filterStr !== '' || this.filtered === true;\n\t}\n\n\t/**\n\t * Load session storage - happens at this.initialize\n\t * Looks for this.localStorageKey in sessionStorage and loads the data if available\n\t */\n\tloadLocalStorage() {\n\t\tif (!this.localStorageKey) return;\n\n\t\tthis.trigger('request:read', this, null);\n\n\t\t// Reset stored array\n\t\tthis.stored = [];\n\t\t// My model keys\n\t\tconst regexp = new RegExp(['^', this.localStorageKey, '.*'].join(''));\n\t\t// My stored models\n\t\tconst things = Netx.store.get(Netx.store.keys(regexp));\n\t\t// We have some things\n\t\tif (things && _.isArray(things)) {\n\t\t\t_.each(things, (t) => {\n\t\t\t\t// TODO: implement this in the model itself? (model.fromLocalStorage(t) or similar.)\n\t\t\t\tt = this.parseLocalStorageModelIn(t);\n\t\t\t\tif (!t) return;\n\t\t\t\t// Silent to avoid a loop\n\t\t\t\t// Collection hears model added- check to add to local storage - adds to local storage - check to add to loval storage - repeat repeat\n\t\t\t\t// I feel like adding an additional property isn't worth it when we have things like \"silent\" at our disposal\n\t\t\t\tthis.add(t, {silent: true});\n\t\t\t});\n\t\t\tthis.stored = this.ids();\n\t\t}\n\t\tthis.trigger('sync', this);\n\t}\n\n\t/**\n\t * Model was added to collection\n\t * @method\n\t * @param {Netx.Model} model Instance of Netx.Model\n\t */\n\tmodelAdded(model) {\n\t\tif (this.localStorageKey && model.storeOptions.persist) {\n\t\t\tthis.addToLocalStorage(model);\n\t\t}\n\t}\n\n\t/**\n\t * Model was changed in collection\n\t * @method\n\t * @param {Netx.Model} model Instance of Netx.Model\n\t */\n\tmodelChanged(model) {\n\t\tif (!this.localStorageKey) return;\n\n\t\t// Model key\n\t\tconst keyName = [this.localStorageKey, model.id].join('');\n\t\t// To persist or not\n\t\tconst persist = model.storeOptions.persist;\n\n\t\t// Set the value\n\t\tconst parsed = this.parseLocalStorageModelOut(_.clone(model.self()));\n\t\tif (!parsed) return;\n\n\t\tconst store = Netx.store;\n\t\tstore.set(keyName, parsed);\n\t\t// Keep until explicitly removed\n\t\tif (persist === true) {\n\t\t\tstore.persist(keyName);\n\t\t}\n\t\t// Expire\n\t\telse if (_.isString(persist) || _.isNumber(persist)) {\n\t\t\tstore.expire(keyName, persist);\n\t\t}\n\t}\n\n\t/**\n\t * Model was removed from collection\n\t * @method\n\t * @param {Netx.Model} model Instance of Netx.Model\n\t */\n\tmodelRemoved(model) {\n\t\tif (!model || !this.localStorageKey) return;\n\n\t\tthis.removeFromLocalStorage(model);\n\t}\n\n\t/**\n\t * We often need to suggest a name for a new model. \"New Model\" works the first time, but\n\t * after that it's not a unique name any more, so we want to try \"New Model 2\", \"New Model 3\", et cetera,\n\t * until we find a good one.\n\t *\n\t * @method\n\t * @param {string} prefix Prefix of the model name (\"New Model\"), or i18n key of same (\"share:i18n.newModel\")\n\t * \t\t\t\t\t\t\t\t\t\t\t\t\t\t (i18n key should implement the numeric index via i18next plurals: http://i18next.com/translate/pluralSimple)\n\t * @param {string} attr The 'name' attribute of this model. If undefined, we'll try \"name\", \"title\" and \"label\" in that order.\n\t * @returns {string} Returns a unique name, not yet used by any model in this collection.\n\t */\n\tmakeUniqueName(prefix, attr) {\n\t\tlet index = 1;\n\t\tlet translate = false;\n\t\tlet title = prefix;\n\n\t\tif (prefix.match(/:i18n\\./)) {\n\t\t\ttranslate = true;\n\t\t\t// Translate prefix.\n\t\t\ttitle = i18n.t(prefix, {count: index});\n\n\t\t\t// If pluralization isn't working, we could get an endless loop.\n\t\t\t// Test that here:\n\t\t\tconst testTitle = i18n.t(prefix, {count: index + 1});\n\t\t\tif (title === testTitle) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"makeUniqueName: i18n key '\" + prefix + \"' is not pluralized.\",\n\t\t\t\t); // http://i18next.com/translate/pluralSimple\n\t\t\t\treturn title;\n\t\t\t}\n\t\t}\n\n\t\t// Check the easy case: there are no other models!\n\t\tif (!this.length) {\n\t\t\treturn title;\n\t\t}\n\n\t\t// If attr wasn't given, try to guess it.\n\t\tif (!attr) {\n\t\t\tif (this.at(0).has('name')) {\n\t\t\t\tattr = 'name';\n\t\t\t} else if (this.at(0).has('title')) {\n\t\t\t\tattr = 'title';\n\t\t\t} else if (this.at(0).has('label')) {\n\t\t\t\tattr = 'label';\n\t\t\t} else {\n\t\t\t\tthrow 'Undefined attr for model name';\n\t\t\t}\n\t\t}\n\n\t\t// If we can find a model matching this title, make a new title & try again.\n\t\tconst obj = {\n\t\t\t[attr]: title,\n\t\t};\n\t\twhile (this.findWhere(obj)) {\n\t\t\tindex++;\n\t\t\tif (translate) {\n\t\t\t\ttitle = i18n.t(prefix, {count: index});\n\t\t\t} else {\n\t\t\t\ttitle = prefix + ' ' + index;\n\t\t\t}\n\t\t\tobj[attr] = title;\n\t\t}\n\n\t\treturn title;\n\t}\n\n\t/**\n\t * Modify the model object that came back from local storage before inserting it into the collection\n\t * @method\n\t * @param {object} obj Model data object\n\t * @return {object} Model data\n\t */\n\tparseLocalStorageModelIn(obj) {\n\t\treturn obj;\n\t}\n\n\t/**\n\t * Modify the model object that is going to local storage before it does\n\t * @method\n\t * @param {object} obj Model attributes\n\t * @return {object} Model data\n\t */\n\tparseLocalStorageModelOut(obj) {\n\t\treturn obj;\n\t}\n\n\t/**\n\t * Remove model from session storage\n\t * @method\n\t * @param {Netx.Model} model Instance of Netx.Model\n\t */\n\tremoveFromLocalStorage(model) {\n\t\tif (!model || !this.localStorageKey) return;\n\n\t\t// Find by id in this.stored\n\t\tconst idx = _.indexOf(this.stored, model.id);\n\t\tif (idx > -1) {\n\t\t\tthis.stored.splice(idx, 1);\n\t\t}\n\t\tNetx.store.remove([this.localStorageKey, model.id].join(''));\n\t}\n\n\t/**\n\t * this.self() returns just the data in a collection that's reflected in the DAM.\n\t * It can be used in method definitions to omit models or model attributes that should *not* be synced.\n\t * We use it for cases where the data is structured differently in the\n\t * model than on the wire, and for models/collections that want to have additional attributes\n\t * for local-only reasons. .self() is intended to be called from method-definition functions,\n\t * when the API call is looking for a single JSON object to represent the entire collection.\n\t *\n\t * The default Netx.Collection.self() implemetation uses this.invoke() to call model.self() on each model,\n\t * and returns the resulting array.\n\t *\n\t * @return {object}\n\t * @method\n\t */\n\tself() {\n\t\treturn this.invoke('self');\n\t}\n\n\t/**\n\t * @method\n\t * @param {string} str Filter\n\t */\n\tsetFilterStr(str) {\n\t\tstr = str != null ? str.toString() : '';\n\n\t\tif (this.filterStr === str) return new $.Deferred().resolve();\n\n\t\tthis.filterStr = str;\n\t\t// Reset to first page\n\t\tthis.pager.firstPage({fetch: false});\n\n\t\treturn this[this.preferredFetchMethod || 'fetch']({\n\t\t\tduplicateQueryPolicy: 'abort',\n\t\t});\n\t}\n\n\t/**\n\t * Set sort is to be used when sorting on the server with a `sortDTO`\n\t * Otherwise, use the standard backbone/backgrid sorting or override this method\n\t * @method\n\t * @param {string} field Field name\n\t * @param {string} order Order\n\t * @param {object} opts Request options\n\t */\n\tsetSort(field, order, opts) {\n\t\tif (!this.sorter) return;\n\t\tthis.sorter.setSort(field, order, opts);\n\t}\n\n\t/**\n\t * Subscribe to websocket\n\t * @method\n\t */\n\tsubscribe() {\n\t\treturn Model.prototype.subscribe.apply(this, arguments);\n\t}\n\n\t/**\n\t * Message received from websocket channel\n\t * @method\n\t * @param {object} data Message data\n\t */\n\tsubscriptionMessage(data) {\n\t\tconst model = this.get(data.id);\n\t\tswitch (data.action) {\n\t\t\tcase 'add':\n\t\t\t\t!model && this.add(data.dto);\n\t\t\t\tbreak;\n\t\t\tcase 'edit':\n\t\t\t\tmodel ? model.set(data.dto) : this.add(data.dto);\n\t\t\t\tbreak;\n\t\t\tcase 'delete':\n\t\t\t\tmodel && this.remove(model);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Takes an autocomplete object and returns model with enough data\n\t * for a selection interface\n\t * @method\n\t * @param {object} data Data (an object of autocomplete data)\n\t * @return {module:core/lib/netx-model} Instance of `netx-model`\n\t * @example\n\t * .toSelectedItemFromAutocomplete({\n\t * id: \"1\",\n\t * text: \"Item label\"\n\t * });\n\t */\n\ttoSelectedItemFromAutocomplete(data, additionalAttrs = {}, opts = {}) {\n\t\tconst model = this.model;\n\t\tconst modelProto = model.prototype;\n\n\t\tlet id = parseInt(data.id);\n\t\tif (_.isNaN(id)) {\n\t\t\tid = data.id;\n\t\t}\n\t\t// This is where computed keys would be cool\n\t\treturn new model(\n\t\t\t{\n\t\t\t\t[modelProto.idAttribute]: id,\n\t\t\t\t[modelProto.titleAttribute]: data.text,\n\t\t\t\t...additionalAttrs,\n\t\t\t},\n\t\t\topts,\n\t\t);\n\t}\n\n\t/**\n\t * Unsubscribe from websocket\n\t * @method\n\t */\n\tunsubscribe() {\n\t\t// If models have an `unsubscribe` method, call them\n\t\tif (_.isFunction(this.model.prototype.unsubscribe)) {\n\t\t\tthis.invoke('unsubscribe');\n\t\t}\n\t\t// Super (of sorts)\n\t\treturn Model.prototype.unsubscribe.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbatchJobComplete() {\n\t\treturn Model.prototype.batchJobComplete.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbatchJobError() {\n\t\treturn Model.prototype.batchJobError.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tbatchJobProgress() {\n\t\treturn Model.prototype.batchJobProgress.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tgetRestLoadedMessage() {\n\t\treturn Model.prototype.getRestLoadedMessage.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\tgetRestLoadingMessage() {\n\t\treturn Model.prototype.getRestLoadingMessage.apply(this, arguments);\n\t}\n\n\t/**\n\t * @method\n\t */\n\ttrackBatchJob() {\n\t\treturn Model.prototype.trackBatchJob.apply(this, arguments);\n\t}\n\n\t/**\n\t * A scoped version of jQuery.when(), that always uses 'this' as the context for the promise it returns.\n\t * It's also able to accept an array of promises, so we don't need to use .apply to make it go.\n\t * @method\n\t */\n\twhen() {\n\t\treturn Model.prototype.when.apply(this, arguments);\n\t}\n\n\t/**\n\t * Object Polling:\n\t * pollUntil() tells any model/collection to do something repeatedly until a conditional test passes,\n\t * emitting appropriate events along the way. Use this to follow DAM changes to certain object properties,\n\t * or to check status until a status change.\n\t *\n\t * @param function doneTest A function that returns true if polling should finish. (Required)\n\t * @param string eventPrefix Event string prefix for polling events. If undefined, no events are triggered.\n\t * @param function pollMethod A function that causes a poll. Must return a promise. Defaults to this.fetch;\n\t * @param number pollInterval Milliseconds between polls. Defaults to 500.\n\t * @method\n\t */\n\tpollUntil() {\n\t\treturn Model.prototype.pollUntil.apply(this, arguments);\n\t}\n\n\t//////////////////////////////////////////\n\t// LAZYLOADING\n\t//////////////////////////////////////////\n\t/**\n\t * @method\n\t * @param {number} index Index\n\t */\n\tcheckReachedBeginning(index) {\n\t\tthis.reachedBeginning = this.reachedBeginning || index === 0;\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t * @param {number} index Index\n\t */\n\tcheckReachedEnd(index) {\n\t\tthis.reachedEnd =\n\t\t\tthis.reachedEnd ||\n\t\t\tindex + this.pager.get('pageSize') >= this.pager.get('itemTotal');\n\t\treturn this;\n\t}\n\n\t/**\n\t * @method\n\t */\n\tinitializeLazyLoad() {\n\t\tthis.reachedBeginning = this.reachedEnd = false;\n\t\tthis.lazyStartIndex = this.pager.get('startIndex');\n\t\tthis.lowestIndex = this.highestIndex = this.lazyStartIndex;\n\n\t\t// No routing\n\t\tthis.pager.set({\n\t\t\t// TODO: collections/models should not need to know about routes/routing\n\t\t\troutesToPage: false,\n\t\t});\n\n\t\tthis.checkReachedBeginning(this.lazyStartIndex)\n\t\t\t.checkReachedEnd(this.lazyStartIndex)\n\t\t\t.stopListening(this.pager, 'change:startIndex', this.startIndexUpdated)\n\t\t\t.listenTo(this.pager, 'change:startIndex', this.startIndexUpdated);\n\t}\n\n\t/**\n\t * @method\n\t * @param {boolean} forward Forward\n\t * @deprecate - unused\n\t * @return {number} Items loading\n\t */\n\tlazyLoadItems(forward) {\n\t\tif (\n\t\t\tthis.syncing ||\n\t\t\t(!forward && this.reachedBeginning) ||\n\t\t\t(forward && this.reachedEnd)\n\t\t)\n\t\t\treturn false;\n\n\t\tconst pageSize = this.pager.get('pageSize');\n\t\tconst page = forward\n\t\t\t? (this.highestIndex + pageSize) / pageSize + 1\n\t\t\t: (this.lowestIndex - pageSize) / pageSize + 1;\n\n\t\tif (page < 1 || page > this.pager.get('pageTotal')) return false;\n\n\t\tthis.lazyLoadedForward = forward;\n\n\t\t// Update pager\n\t\tthis.pager.set(\n\t\t\t{\n\t\t\t\tcurrentPage: page,\n\t\t\t},\n\t\t\t{\n\t\t\t\tat: forward ? this.length : 0,\n\t\t\t\tmerge: true,\n\t\t\t\tremove: false,\n\t\t\t\tsort: false,\n\t\t\t},\n\t\t);\n\n\t\t// Calculate items that will load\n\t\tif (this.pager.get('pageTotal')) {\n\t\t\tlet diff = page * pageSize - this.pager.get('itemTotal');\n\t\t\tif (diff < 0) diff = 0;\n\t\t\treturn pageSize - diff;\n\t\t}\n\n\t\treturn pageSize;\n\t}\n\n\t/**\n\t * @method\n\t * @param {module:app/models/pager} pager Pager\n\t * @param {number} startIndex Start index\n\t */\n\tstartIndexUpdated(pager, startIndex) {\n\t\t// Was not able to set at lazy load initialize\n\t\tif (this.lazyStartIndex == null) {\n\t\t\tthis.lazyStartIndex = startIndex;\n\t\t}\n\n\t\tif (this.lowestIndex == null || startIndex < this.lowestIndex) {\n\t\t\tthis.lowestIndex = startIndex;\n\t\t}\n\n\t\tif (this.highestIndex == null || startIndex > this.highestIndex) {\n\t\t\tthis.highestIndex = startIndex;\n\t\t}\n\n\t\tthis.checkReachedBeginning(startIndex);\n\t\tthis.checkReachedEnd(startIndex);\n\t}\n\t//////////////////////////////////////////\n\t// !LAZYLOADING\n\t//////////////////////////////////////////\n\n\t//////////////////////////////////////////\n\t// HOUSEKEEPING\n\t//////////////////////////////////////////\n\taddSubCollection() {\n\t\treturn Model.prototype.addSubCollection.apply(this, arguments);\n\t}\n\tremoveSubCollection() {\n\t\treturn Model.prototype.removeSubCollection.apply(this, arguments);\n\t}\n\taddSubModel() {\n\t\treturn Model.prototype.addSubModel.apply(this, arguments);\n\t}\n\tremoveSubModel() {\n\t\treturn Model.prototype.removeSubModel.apply(this, arguments);\n\t}\n\t/**\n\t * Severs all ties to the world so it can be eligible for garbage collection\n\t * @method\n\t */\n\tgarbageCollect() {\n\t\tthis._rpc && this._rpc.garbageCollect();\n\n\t\t// Let go of any websocket channels\n\t\tthis.unsubscribe();\n\t\t// Empty out models - see our reset override\n\t\tthis.reset([]);\n\t\t// Kill all event listeners\n\t\tthis.stopListening().off();\n\n\t\tif (this.pager) {\n\t\t\tthis.pager.garbageCollect();\n\t\t}\n\t\tdelete this.subModels;\n\n\t\t// Loop over sub collection and trigger their cleanup\n\t\tif (_.isObject(this.subCollections)) {\n\t\t\t_.each(this.subCollections, function (c) {\n\t\t\t\tc.garbageCollect();\n\t\t\t});\n\t\t\tdelete this.subCollections;\n\t\t}\n\n\t\tthis.garbageCollected = true;\n\n\t\treturn this;\n\t}\n\t//////////////////////////////////////////\n\t// !HOUSEKEEPING\n\t//////////////////////////////////////////\n\n\t// TODO: Implement the class method Load() for testing\n\t// see Netx.Model definition for implementation guidelines'\n\t//\n\t/**\n\t * @method\n\t * @static\n\t * unused\n\t */\n\tstatic Load(selection) {\n\t\tconst collection = new this();\n\t\tif (selection != null) {\n\t\t\tcollection.selection = selection;\n\t\t}\n\t\treturn collection.fetch().then(() => {\n\t\t\treturn collection;\n\t\t});\n\t}\n\n\t/** @type {boolean} */\n\tstatic get __isCollection__() {\n\t\treturn true;\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'Collection';\n\t}\n}\n\nexport default Collection;\n","/**\n * Add and show views in particular contexts via actions - think of it as a view controller\n * Unlike the usual controller this is very privy to the DOM\n * @class\n */\nimport Base from './netx-view';\nimport EmptyTemplate from '@netx/core-app/templates/empty.html';\n\nimport AppViewsCollection from '@netx/core-app/collections/appViews';\nimport AppViewsQueueCollection from '@netx/core-app/collections/appViewsQueue';\n\nclass MultiView extends Base {\n\t/** @type {boolean} */\n\tget isMultiView() {\n\t\treturn this.constructor.__isMultiView__;\n\t}\n\n\t/**\n\t * @override\n\t * @listens {@link Netx.Collections.AppViews#change:showActions}\n\t * @listens {@link Netx.Collections.AppViews#change:uniqueShowAction}\n\t * @listens {@link Netx.Collections.AppViews#loaded}\n\t * @listens {@link Netx.Collections.AppViews#loading}\n\t * @listens {@link Netx.Collections.AppViews#swtichedBack}\n\t * @listens {@link Netx.Collections.AppViews#view:hiding}\n\t * @listens {@link Netx.Collections.AppViews#view:hidden}\n\t * @listens {@link Netx.Collections.AppViews#view:removed}\n\t * @listens {@link Netx.Collections.AppViews#view:rendered}\n\t * @listens {@link Netx.Collections.AppViews#view:showing}\n\t * @listens {@link Netx.Collections.AppViews#view:shown}\n\t * @listens {@link Netx.Views.MultiView#addedNewChildView|addedChildView}\n\t * @listens {@link Netx.Views.MultiView#removedChildView|removedChildView}\n\t */\n\tconstructor(opts = {}) {\n\t\tconst viewCollection = opts.viewCollection || new AppViewsCollection([]);\n\t\t/**\n\t\t * @property {object} childView - Child view object\n\t\t * @property {string} childView.viewClass - The view class to use when creating `childView` (in our case, it is the `viewSpec` model's `id`)\n\t\t * @property {string} childView.target - The css selector to use when injecting a newly created `childView` (to be overriden in extending `view`)\n\t\t */\n\t\topts.childView = {\n\t\t\tviewClass(model) {\n\t\t\t\treturn model.get('viewClass');\n\t\t\t},\n\t\t\ttarget: false,\n\t\t\tcollection: viewCollection,\n\t\t\toptions: {\n\t\t\t\tattributes: {\n\t\t\t\t\t'data-layer': '',\n\t\t\t\t},\n\t\t\t},\n\t\t\t...opts.childView,\n\t\t};\n\t\tsuper(opts);\n\n\t\tthis.childView = opts.childView;\n\t\tthis.instantiateOnAdd = opts.instantiateOnAdd !== false;\n\t\tthis.registeredViews = [];\n\t\t/**\n\t\t * Classes that will be added to views when they enter our `viewCollection`\n\t\t * These classes will be removed when they are removed from our `viewCollection`\n\t\t * This allows for transient views to have what they need when thye move from `multiView` to `multiView`\n\t\t * @type {string}\n\t\t * @default\n\t\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollection}\n\t\t */\n\t\tthis.additionalViewClasses = opts.additionalViewClasses || '';\n\n\t\t/**\n\t\t * Whether or not to confirm unsaved changes when `this` tries to hide\n\t\t * @type {boolean}\n\t\t * @default\n\t\t */\n\t\tthis.confirmUnsavedChanges = opts.confirmUnsavedChanges === true;\n\n\t\t/**\n\t\t * When `this` hides, should we empty all children in our `viewCollection`\n\t\t * @type {boolean}\n\t\t * @default\n\t\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollection}\n\t\t */\n\t\tthis.emptyOnHide = opts.emptyOnHide === true;\n\n\t\t/**\n\t\t * Should we hide `this` when our `viewCollection` reaches a length of 0\n\t\t * @type {boolean}\n\t\t * @default\n\t\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollection}\n\t\t */\n\t\tthis.hideOnEmpty = opts.hideOnEmpty === true;\n\n\t\t/**\n\t\t * Should we hide `this` when a child view is removed\n\t\t * @type {boolean}\n\t\t * @default\n\t\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollction}\n\t\t */\n\t\tthis.hideWhenChildViewRemoved = opts.hideWhenChildViewRemoved === true;\n\n\t\t/**\n\t\t * Render view immediately after instantiate\n\t\t * @type {boolean}\n\t\t * @default\n\t\t */\n\t\tthis.renderOnInstatiate = opts.renderOnInstatiate === true;\n\n\t\t/**\n\t\t * Should the `childView` be immediately shown when added to our `viewCollection`\n\t\t * @type {boolean}\n\t\t * @default\n\t\t * @see {@link Netx.Views.MultiView#viewInstantiated|viewInstantiated}\n\t\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollection}\n\t\t */\n\t\tthis.showOnAdd = opts.showOnAdd !== false;\n\n\t\t// I am confident in doing this here as this cannot be populated until the first render of this view\n\t\t// and none of the data needs to be validated or passed to the server / shared amongst the rest of the app\n\t\t/**\n\t\t * This is my collection of views.\n\t\t * @memberOf Netx.Views.MultiView\n\t\t * @alias viewCollection\n\t\t * @type {Netx.Collections.AppViews}\n\t\t */\n\t\tthis.viewCollection = viewCollection;\n\n\t\t// For debug output - multiviews within multiviews\n\t\tlet viewSpec = opts.viewSpec;\n\n\t\tthis.listenTo(this.viewCollection, 'add', (viewSpec) => {\n\t\t\tthis.registerView(viewSpec);\n\n\t\t\tif (!this.instantiateOnAdd) return;\n\n\t\t\tthis.instantiateView(viewSpec);\n\t\t});\n\n\t\tthis.listenTo(this.viewCollection, 'remove', (...args) => {\n\t\t\tthis.removeChildView(...args);\n\t\t});\n\n\t\tthis.listenTo(this.viewCollection, 'add remove reset', (collection) => {\n\t\t\tthis.el.classList.toggle(\n\t\t\t\t'multiple-views',\n\t\t\t\tthis.viewCollection.length > 1,\n\t\t\t);\n\t\t});\n\n\t\t////////////////////////////////\n\t\t// QUEUE\n\t\t////////////////////////////////\n\t\t/**\n\t\t * In the event we need to prevent a view from showing for a time (until conditions are met)\n\t\t * Or we receive a transient view that then leave (like a bookmark for the last view that was active before the transient came into our lives)\n\t\t * @memberOf Netx.Views.MultiView\n\t\t * @alias cachedActiveView\n\t\t * @private\n\t\t * @type {Netx.View}\n\t\t */\n\t\tthis.cachedActiveView = null;\n\n\t\t/**\n\t\t * If we are in the middle of hiding - the best thing for all involved is to let it finish - show again and then pick up where the data left off.\n\t\t * @memberOf Netx.Views.MultiView\n\t\t * @alias _viewQueue\n\t\t * @private\n\t\t * @type {Netx.Collections.AppViews}\n\t\t */\n\t\tthis.viewCollection.viewQueue = this._viewQueue = new AppViewsQueueCollection(\n\t\t\t[],\n\t\t\t{\n\t\t\t\tqueueFor: this.viewCollection,\n\t\t\t\tview: this,\n\t\t\t},\n\t\t);\n\n\t\t// NOTE: I am not adding `_viewQueueParentView` to `this.subViews` - as nothing in this view (other than remove)\n\t\t// should have any affect on it\n\t\t/**\n\t\t * The reason for the dummy view is so that the queued views actually get created and can listen for any events that would affect them in the mean\n\t\t * time while they are queued\n\t\t * @memberOf Netx.Views.MultiView\n\t\t * @alias _viewQueueParentView\n\t\t * @private\n\t\t * @type {Netx.View}\n\t\t */\n\t\tthis._viewQueueParentView = new Base({\n\t\t\ttemplate: EmptyTemplate,\n\t\t\tcollection: this._viewQueue,\n\t\t});\n\t\t// Make sure it reflects our `childView` object\n\t\tthis._viewQueueParentView.childView = this.childView;\n\n\t\t// Hey, listen!\n\t\tthis.listenTo(this, 'addedNewChildView', (view) => {\n\t\t\t// Defer so all actions have been registered in the viewSpec\n\t\t\t// These get set at the same time as this event\n\t\t\t_.defer(_.bind(_.partial(this.viewInstantiated, view), this));\n\t\t})\n\t\t\t.listenTo(this, 'removedChildView', (view) => {\n\t\t\t\tthis.viewRemoved(view);\n\t\t\t})\n\t\t\t////////////////////////////////////\n\t\t\t// SHOW ACTION LISTENERS\n\t\t\t////////////////////////////////////\n\t\t\t.listenTo(\n\t\t\t\tthis.viewCollection,\n\t\t\t\t'change:showActions',\n\t\t\t\t(model, collection) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcollection &&\n\t\t\t\t\t\tcollection._listenId === this.viewCollection._listenId\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst prev = model._previousAttributes || {};\n\t\t\t\t\t\tconst newActions = model.get('showActions') || [];\n\t\t\t\t\t\tconst prevActions = prev.showActions || [];\n\n\t\t\t\t\t\t// Stop listening to actions no longer present\n\t\t\t\t\t\t_.each(_.difference(prevActions, newActions), (action) => {\n\t\t\t\t\t\t\tthis.stopListening(dispatcher, action);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Start lsitening to actions that were added\n\t\t\t\t\t\t_.each(_.difference(newActions, prevActions), (action) => {\n\t\t\t\t\t\t\tthis.listenTo(\n\t\t\t\t\t\t\t\tdispatcher,\n\t\t\t\t\t\t\t\taction,\n\t\t\t\t\t\t\t\t_.partial(this.showView, model.get('view')),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t\t.listenTo(\n\t\t\t\tthis.viewCollection,\n\t\t\t\t'change:uniqueShowAction',\n\t\t\t\t(model, collection) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcollection &&\n\t\t\t\t\t\tcollection._listenId === this.viewCollection._listenId\n\t\t\t\t\t) {\n\t\t\t\t\t\tvar prev = model._previousAttributes || {},\n\t\t\t\t\t\t\tnewAction = model.get('uniqueShowAction'),\n\t\t\t\t\t\t\tprevAction = prev.uniqueShowAction;\n\n\t\t\t\t\t\t// TODO: A way to remove actions after they have been defined - is it as simple as removing it from the Actions array?\n\t\t\t\t\t\t// if( prevAction.match( /^appView:(\\w+):show/) ) {}\n\n\t\t\t\t\t\t// Register actions so we can run through the actions/event system\n\t\t\t\t\t\t// We assume that if you provided an action that does not match this pattern that it is a legitamte and registered action\n\t\t\t\t\t\tif (newAction && newAction.match(/^appView:(\\w+):show/)) {\n\t\t\t\t\t\t\tNetx.Actions.Register([\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tevent: newAction,\n\t\t\t\t\t\t\t\t\tlabel: i18n.t('i18n.show'),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevAction && this.stopListening(dispatcher, prevAction);\n\t\t\t\t\t\tnewAction &&\n\t\t\t\t\t\t\tthis.listenTo(\n\t\t\t\t\t\t\t\tdispatcher,\n\t\t\t\t\t\t\t\tnewAction,\n\t\t\t\t\t\t\t\t_.partial(this.showView, model.get('view')),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t\t////////////////////////////////////\n\t\t\t// !SHOW ACTION LISTENERS\n\t\t\t////////////////////////////////////\n\n\t\t\t////////////////////////////////////\n\t\t\t// SWITCHING CONTEXTS\n\t\t\t////////////////////////////////////\n\t\t\t// A model has been switched to another `viewCollection`\n\t\t\t.listenTo(this.viewCollection, 'switched', (model, collection) => {\n\t\t\t\tif (model && model.isMyOriginalCollection(this.viewCollection)) {\n\t\t\t\t\tmodel.get('view') &&\n\t\t\t\t\t\tmodel.get('view').$el.removeClass(this.additionalViewClasses);\n\t\t\t\t\tmodel.set('switched', true);\n\t\t\t\t\tthis.$el.addClass('view-switched');\n\t\t\t\t}\n\t\t\t})\n\t\t\t// A view was returned back to its original home\n\t\t\t.listenTo(this.viewCollection, 'switchedBack', (model, collection) => {\n\t\t\t\t// If our `viewCollection` is its original `viewCollection` - reactivate and show it\n\t\t\t\tif (\n\t\t\t\t\tcollection &&\n\t\t\t\t\tthis.viewCollection._listenId === collection._listenId\n\t\t\t\t) {\n\t\t\t\t\t// Ge the view\n\t\t\t\t\tconst view = model.get('view');\n\t\t\t\t\t// Check if it shopuld be the active view\n\t\t\t\t\tconst activeView = this.getActiveView();\n\n\t\t\t\t\t// We are no longer switched out\n\t\t\t\t\tmodel.set('switched', false);\n\n\t\t\t\t\t// This will get our element back into its right place in the DOM\n\t\t\t\t\tthis.addChildView(model);\n\t\t\t\t\t// Put classes back\n\t\t\t\t\tview.$el.addClass(this.additionalViewClasses);\n\t\t\t\t\t// Either there are no active views or the active view is this view that is switching back\n\t\t\t\t\tif (_.isUndefined(activeView) || activeView.cid === view.cid) {\n\t\t\t\t\t\t// Reactivate\n\t\t\t\t\t\tmodel.set('active', true);\n\t\t\t\t\t\t// Show\n\t\t\t\t\t\tthis.showView(view);\n\t\t\t\t\t}\n\t\t\t\t\t// We are just put back but not active\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Deactivate\n\t\t\t\t\t\tmodel.set('active', false);\n\t\t\t\t\t}\n\t\t\t\t\t// Toggle class based on if any views are still switched out from our `viewCollection`\n\t\t\t\t\tthis.$el.toggleClass(\n\t\t\t\t\t\t'view-switched',\n\t\t\t\t\t\t!_.isUndefined(this.viewCollection.findWhere({switched: true})),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})\n\t\t\t////////////////////////////////////\n\t\t\t// !SWITCHING CONTEXTS\n\t\t\t////////////////////////////////////\n\n\t\t\t// If it is a view event the first argument will always be the view that the event was triggered on\n\t\t\t// due to the fact that we are not consistent in always providing a the view when we trigger an event\n\t\t\t// Collection/model events will be piped through as-is\n\t\t\t// View events are prepended with \"view:\" so we do not conflict with data events\n\t\t\t// this.listenTo( this.viewCollection, 'all', function() {\n\t\t\t// \tconsole.log( arguments );\n\t\t\t// } );\n\n\t\t\t// Sometimes a view is removed by other means than being taken out of the viewCollection\n\t\t\t// Be safe and remove from the collection as well (if it does not exist there is no harm)\n\t\t\t// It will be caught in the 'removedChildView' listener and dealt with\n\t\t\t.listenTo(this.viewCollection, 'view:removed', (view) => {\n\t\t\t\tthis.viewCollection.remove(view.viewSpec);\n\t\t\t})\n\t\t\t.listenTo(this.viewCollection, 'view:hiding', this.viewOnHiding)\n\t\t\t.listenTo(this.viewCollection, 'view:hidden', (view) => {\n\t\t\t\tthis.viewAfterHidden(view);\n\t\t\t})\n\t\t\t.listenTo(this.viewCollection, 'view:showing', this.viewOnShowing)\n\t\t\t.listenTo(this.viewCollection, 'view:shown', (view) => {\n\t\t\t\tthis.viewAfterShown(view);\n\t\t\t});\n\n\t\t// When a child view is hidden we hide the multiView\n\t\tif (this.hideWhenChildViewRemoved) {\n\t\t\t// When any views hide we all hide\n\t\t\tthis.listenTo(this.viewCollection, 'remove', (model) => {\n\t\t\t\tthis.hide();\n\t\t\t});\n\t\t}\n\t}\n\n\t/** @override */\n\tgetExcludedViews() {\n\t\tconst excludedViews = super.getExcludedViews();\n\t\treturn excludedViews.concat(_.pluck(this.childViews, 'el'));\n\t}\n\n\t/**\n\t * @method\n\t */\n\tregisterView(viewSpec) {\n\t\tif (this.registeredViews.indexOf(viewSpec.id) > -1) return;\n\t\tthis.registeredViews.push(viewSpec.id);\n\t\t// Listen for each show:action\n\t\tviewSpec.get('showActions').forEach((action) => {\n\t\t\tthis.listenTo(dispatcher, action, () => {\n\t\t\t\tlet view = viewSpec.get('view');\n\t\t\t\tif (!view) {\n\t\t\t\t\tview = this.instantiateView(viewSpec);\n\t\t\t\t}\n\t\t\t\tthis.showView(view);\n\t\t\t});\n\t\t});\n\n\t\tthis.listenTo(dispatcher, viewSpec.get('uniqueShowAction'), () => {\n\t\t\tlet view = viewSpec.get('view');\n\t\t\tif (!view) {\n\t\t\t\tview = this.instantiateView(viewSpec);\n\t\t\t}\n\t\t\tthis.showView(view);\n\t\t});\n\t}\n\n\t/**\n\t * @method\n\t */\n\tinstantiateView(viewSpec) {\n\t\tif (!this.$childTargetEl || viewSpec.get('view')) return;\n\n\t\tconst viewClass = viewSpec.get('viewClass');\n\t\tlet opts = this.childView.options;\n\t\tif (typeof opts === 'function') {\n\t\t\topts = opts.call(this, viewSpec);\n\t\t} else {\n\t\t\t_.each(opts, (opt, key, all) => {\n\t\t\t\tif (\n\t\t\t\t\tkey === 'template' ||\n\t\t\t\t\tkey === 'onConfirmed' ||\n\t\t\t\t\tkey === 'onCancelled'\n\t\t\t\t)\n\t\t\t\t\treturn;\n\t\t\t\tif (\n\t\t\t\t\t// Do not execute method overrides - leave them as is\n\t\t\t\t\t_.isFunction(opt) &&\n\t\t\t\t\t!opt.__isView__\n\t\t\t\t) {\n\t\t\t\t\tall[key] = opt.call(this, viewSpec);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\topts.viewSpec = viewSpec;\n\t\tlet viewOptions = viewSpec.get('viewOptions') || {};\n\t\tif (typeof viewOptions === 'function') {\n\t\t\tviewOptions = viewOptions.call(this, viewSpec);\n\t\t} else {\n\t\t\t_.each(viewOptions, (opt, key, all) => {\n\t\t\t\tif (\n\t\t\t\t\tkey === 'template' ||\n\t\t\t\t\tkey === 'onConfirmed' ||\n\t\t\t\t\tkey === 'onCancelled'\n\t\t\t\t)\n\t\t\t\t\treturn;\n\t\t\t\tif (\n\t\t\t\t\t// Do not execute method overrides - leave them as is\n\t\t\t\t\t_.isFunction(opt) &&\n\t\t\t\t\t!opt.__isView__\n\t\t\t\t) {\n\t\t\t\t\tall[key] = opt.call(this, viewSpec);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tconst view = new viewClass({...opts, ...viewOptions});\n\t\tviewSpec.set('view', view);\n\t\tthis.childViews = this.childViews || {};\n\t\tthis.childViews[viewSpec.cid] = view;\n\t\tthis.trigger('addedNewChildView', view);\n\n\t\tif (!this.$childTargetEl) return view;\n\n\t\tthis.$childTargetEl.append(view.$el);\n\t\tthis.renderOnInstatiate && view.render();\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * @override\n\t * @param {boolean} simple Simple hide (not up for removal - just visibility change)\n\t */\n\thide(simple) {\n\t\t// If it is not a simple hide and we want to confirm unsaved changes and we have not previously confirmed unsaved changes\n\t\tif (\n\t\t\tsimple === true ||\n\t\t\t!this.confirmUnsavedChanges ||\n\t\t\tthis.confirmedUnsavedChanges\n\t\t) {\n\t\t\treturn super.hide(simple);\n\t\t}\n\n\t\tconst viewCollection = this.viewCollection;\n\n\t\t// Loop over our child views and check for a hide confirmations (unsaved changes)\n\t\t// We will only do the first one we find since wedo not have a great way yet to present a user with all the info about each unsaved view\n\t\t// So, if there are 2+ unsaved views, we confirm for one and it confirms for all\n\t\tlet unsavedView;\n\t\tfor (let i = 0, c = viewCollection.length, view; i < c; i++) {\n\t\t\tview = viewCollection.at(i).get('view');\n\t\t\tif (view && !view.confirmedUnsavedChanges) {\n\t\t\t\tunsavedView =\n\t\t\t\t\t_.isFunction(view.unsavedChanges) && view.unsavedChanges();\n\t\t\t\tif (unsavedView) break;\n\t\t\t}\n\t\t}\n\n\t\t// When all is ready\n\t\treturn this.when(unsavedView ? unsavedView.confirmHide() : true).then(\n\t\t\t(view) => {\n\t\t\t\t// We only confirm once - all other child views will be considered confirmed as well\n\t\t\t\tthis.viewCollection.each((viewSpec) => {\n\t\t\t\t\tconst v = viewSpec.get('view');\n\t\t\t\t\tif (!v) return;\n\t\t\t\t\tv.confirmedUnsavedChanges = true;\n\t\t\t\t});\n\t\t\t\t// We are good to hide\n\t\t\t\tthis.resetActiveView();\n\t\t\t\tsuper.hide(simple);\n\t\t\t},\n\t\t\t(view) => {\n\t\t\t\t// User opted not to hide, show the view\n\t\t\t\tthis.showView(view);\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * Everything has happend in the core hiding of `this`\n\t * Executes just before `whenHidden` is resolved\n\t * @override\n\t * @listens {@link Netx.View#hidden}\n\t * @see {@link Netx.View#whenHidden|whenHidden}\n\t */\n\tafterHidden(view) {\n\t\tsuper.afterHidden(view);\n\n\t\tif (!this.emptyOnHide) return;\n\n\t\t// We defer so that anything running on hidden can finish\n\t\t_.defer(() => {\n\t\t\t// Views that wanted to show while we were hiding momentarily\n\t\t\tif (!this._viewQueue.length) return;\n\t\t\t// Apply queue\n\t\t\tthis.viewCollection.set(this._viewQueue.models);\n\t\t\t// Empty\n\t\t\tthis._viewQueue.reset([]);\n\t\t});\n\t}\n\n\t/**\n\t * We will need to cancel out any remaining views here as we can get collisions on after hidden\n\t * @method\n\t */\n\tbeforeHidden(cb) {\n\t\tsuper.beforeHidden(cb);\n\n\t\tif (!this.emptyOnHide) return this;\n\n\t\tthis.viewCollection.each((viewSpec) => {\n\t\t\tconst view = viewSpec.get('view');\n\t\t\tview && _.isFunction(view.cancel) && view.cancel();\n\t\t});\n\t\t// Always use set to empty\n\t\tthis.viewCollection.set([]);\n\t}\n\n\t/** @override */\n\tcheckHasResults() {\n\t\t// We may have a collection but it is not data related nor should it\n\t\t// be setting any no-results/no-assets attributes\n\t\t// Will need to deal with when we refactor the loading class stuff\n\t\treturn true;\n\t}\n\n\t/** @override */\n\tpostRender() {\n\t\tsuper.postRender();\n\n\t\tconst viewCollection = this.viewCollection;\n\n\t\t// Cache\n\t\tthis.$childTargetEl = this.$(this.childView.target || '.nx-childviews');\n\t\tif (!this.$childTargetEl.length) {\n\t\t\tthis.$childTargetEl = this.$el;\n\t\t}\n\n\t\tif (\n\t\t\t!this.getActiveView() &&\n\t\t\tthis.instantiateOnAdd &&\n\t\t\tviewCollection.length\n\t\t) {\n\t\t\tthis.instantiateView(viewCollection.at(0));\n\t\t}\n\n\t\tthis.el.classList.toggle('multiple-views', viewCollection.length > 1);\n\t}\n\n\t/** @override */\n\tremove() {\n\t\tthis.lastViewSpec = this.currentViewSpec = null;\n\t\t// Clear queue\n\t\tthis._viewQueueParentView.remove();\n\t\tthis._viewQueue.reset([]);\n\t\tthis._viewQueue.garbageCollect();\n\n\t\t_.invoke(this.childViews, 'remove');\n\n\t\tsuper.remove();\n\t}\n\n\t/**\n\t * Respond to `collection` remove events by removing the associated `childView`, if it exists.\n\t * Only respond if the app view has no where else to go - otherwise leave the view and its events intact\n\t * @override\n\t * @see {@link Netx.Views.MultiView#viewCollection|viewCollection}\n\t */\n\tremoveChildView(model, collection, opts = {}) {\n\t\t// Make sure it was removed from our `collection`\n\t\tif (!this.childViews || collection !== this.viewCollection) return;\n\n\t\tconst childView = model.get('view');\n\t\tif (!childView) return;\n\n\t\t// Leave the events and elements intact\n\t\tif (!model.collections.length) {\n\t\t\tchildView.remove();\n\t\t}\n\t\t// This only pertains to this view\n\t\tdelete this.childViews[model.cid];\n\t\tthis.stopListening(childView);\n\t\tthis.trigger('removedChildView', childView);\n\t}\n\n\t/**\n\t * Do any of our children have unsaved changes?\n\t * @override\n\t * @return {boolean|Netx.View} false / first unsaved instance of Netx.View\n\t */\n\tunsavedChanges() {\n\t\tconst viewCollection = this.viewCollection;\n\n\t\t// Loop over our `viewCollection` and find the first `childView` with unsaved changes\n\t\tlet hasUnsavedChanges = false;\n\t\tfor (let i = 0, c = viewCollection.length, view; i < c; i++) {\n\t\t\tview = viewCollection.at(i).get('view');\n\t\t\tif (view && view.unsavedChanges()) {\n\t\t\t\thasUnsavedChanges = view;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn hasUnsavedChanges;\n\t}\n\n\t/**\n\t * Get the active `childView`\n\t * @method\n\t * @return {Netx.View} Active `childView` instance or `undefined`\n\t */\n\tgetActiveView() {\n\t\tconst viewSpec = this.viewCollection.findWhere({active: true});\n\t\treturn viewSpec ? viewSpec.get('view') : undefined;\n\t}\n\n\t/**\n\t * Find the first enabled (via `showActions`/`uniqueShowAction`) `childView` and show it.\n\t * Pass a `viewId` if you want to diqualify a particular `childView` from being considered.\n\t * @method\n\t * @param {string} viewId If provided it will get the first `view` not to match `viewId`\n\t * @return {boolean|Netx.Models.AppView} First enabled instance of {@link Netx.Models.AppView} or `false`\n\t */\n\tgetFirstEnabledView(viewId) {\n\t\tconst activeView = this.getActiveView();\n\t\tconst viewCollection = this.viewCollection;\n\t\tconst collectionLength = viewCollection.length;\n\n\t\tif (\n\t\t\tcollectionLength < 2 ||\n\t\t\t(activeView &&\n\t\t\t\tactiveView.viewSpec.id !== viewId &&\n\t\t\t\tactiveView.viewSpec.get('name') !== viewId)\n\t\t)\n\t\t\treturn false;\n\n\t\t// Either there is no `activeView` or the `activeView` is the view we do not want and we have enough views to do anything\n\t\t// Look for the first view that is not the one we could not show and is also valid to show\n\t\tfor (let i = 0, viewSpec; i < collectionLength; i++) {\n\t\t\tviewSpec = viewCollection.at(i);\n\t\t\tif (\n\t\t\t\t(!viewId ||\n\t\t\t\t\t(viewSpec.id !== viewId && viewSpec.get('name') !== viewId)) &&\n\t\t\t\tthis.isViewActionValid(viewSpec)\n\t\t\t) {\n\t\t\t\treturn viewSpec;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Get a `childView` by `name`\n\t * @method\n\t * @param {string} name View name\n\t * @return {Netx.View} `Netx.View` instance or `undefined`\n\t */\n\tgetViewByName(name) {\n\t\tconst viewSpec =\n\t\t\tthis.viewCollection.findWhere({name: name}) ||\n\t\t\tthis.viewCollection.findWhere({viewClass: name});\n\t\tif (!viewSpec) return;\n\n\t\treturn viewSpec.get('view');\n\t}\n\n\t/**\n\t * Hide every `childView`\n\t * @method\n\t */\n\thideAllViews() {\n\t\t_.invoke(this.childViews, 'hide', true);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Check the unqiue show `action` of a `viewSpec`\n\t * @method\n\t * @param {Netx.Models.AppView} viewSpec View spec\n\t * @return {boolean} View `action` valid\n\t * TODO: Refactor actions and break up the pieces, like tests and synced listeners etc\n\t */\n\tisViewActionValid(viewSpec) {\n\t\tif (!viewSpec) return false;\n\t\treturn viewSpec.isViewActionValid();\n\t}\n\n\t/** @method */\n\tloadedView() {\n\t\tthis._loadingView = false;\n\t\tthis.reflectLoadingTimeout && clearTimeout(this.reflectLoadingTimeout);\n\t\tthis.el.removeAttribute('data-nx-loading-view');\n\t}\n\n\t/** @method */\n\tloadingView() {\n\t\tif (this._loadingView) return;\n\n\t\tthis._loadingView = true;\n\t\tthis.reflectLoadingTimeout && clearTimeout(this.reflectLoadingTimeout);\n\t\tthis.reflectLoadingTimeout = setTimeout(() => {\n\t\t\tif (!this._loadingView) return;\n\t\t\tthis.el.setAttribute('data-nx-loading-view', 'true');\n\t\t}, 48);\n\t}\n\n\t/**\n\t * Set the active `childView` to inactive\n\t * @method\n\t */\n\tresetActiveView() {\n\t\tconst viewSpec = this.viewCollection.findWhere({active: true});\n\t\tviewSpec && viewSpec.set('active', false);\n\t\t// Chain\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set a class on `this.$el` to reflect the currently active `view`\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t */\n\tsetClassName(view) {\n\t\t// Set class this.$el\n\t\tthis.$el\n\t\t\t.removeClass((index, css) => {\n\t\t\t\t// We want to remove all classes matching '*-layer'\n\t\t\t\treturn (css.match(/\\S+-layer/g) || []).join(' ');\n\t\t\t})\n\t\t\t.addClass(\n\t\t\t\t`${view.viewSpec.get('name') || _.toCamelCase(view.viewSpec.id)}-layer`,\n\t\t\t);\n\t\t// Chain\n\t\treturn this;\n\t}\n\n\t/**\n\t * Show a `childView`\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t */\n\tshowView(view) {\n\t\tif (!this.viewChanging(view)) return this;\n\n\t\t// Show `this`\n\t\tthis.show();\n\n\t\t// Clean up any exisiting promise\n\t\tif (this.viewReady && this.viewReady.state() === 'pending') {\n\t\t\tthis.viewReady.rejectWith(this);\n\t\t}\n\t\tthis.viewReady = new $.Deferred();\n\n\t\tthis.loadingView();\n\n\t\tthis.lastViewSpec = this.currentViewSpec;\n\t\tthis.currentViewSpec = view.viewSpec;\n\n\t\t// Let `this` view respond to the fact we are about to call `show` on `view`\n\t\tthis.beforeShowView(view).then(() => {\n\t\t\tthis.whenShown.then(() => {\n\t\t\t\t// Delay hide\n\t\t\t\t// All views will live for at least 500ms - otherwise I have no idea what the interface is trying to do.\n\t\t\t\tconst d = new $.Deferred();\n\t\t\t\tview.hideDelayed = d.promise();\n\n\t\t\t\t_.delay(_.partial(d.resolveWith, this), view.minimumShowTime || 250);\n\n\t\t\t\t// Then call `show` on `view`\n\t\t\t\tview.show();\n\n\t\t\t\tthis.loadedView();\n\t\t\t});\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Show will be starting soon\n\t * At this point not even `view.show` has been executed\n\t * This allows the view to do anything special it needs to do in anticipation of calling `view.show`\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @return {Promise} Promise\n\t */\n\tbeforeShowView(view) {\n\t\t// Multi-view does not currently have any default functionality here\n\t\t// But this mehtod is only implemented in multi-view - other views extending this should call `super`\n\t\t// unless certain that they will always override any behavior that may be later placed here\n\n\t\t// FUN FACT: You cannot even put the word in a comment (without spaces) `_ s u p e r` - backbone super\n\t\t// must parse the functions as a string and search for an instance of that word (regardless of context)\n\t\t// and if it finds it, it tries to wrap the method - if the method's super does not implement the function\n\t\t// you get `Uncaught Super does not implement this method: `\n\n\t\t// This method is for letting the view know a `childView` is going to be shown (before `show` is ever called)\n\t\t// We wait for our view to be shown before showing any `childViews` - but we may want to do something\n\t\t// in anticipation for the showing of a `childView` prior to any delays\n\n\t\t// Now we support promises (useful for when what we are doing may involve deferred modules)\n\t\t// All methods overriding this must return super or return and resolve `this.viewReady`\n\t\tconst deferredModules = view.viewSpec.get('deferredModules');\n\t\tif (!_.isFunction(deferredModules)) {\n\t\t\treturn this.viewReady.resolveWith(this);\n\t\t}\n\n\t\tdeferredModules(() => {\n\t\t\tthis.viewReady.resolveWith(this);\n\t\t});\n\t\treturn this.viewReady.promise();\n\t}\n\n\t/**\n\t * Find and the show the first enabled (via `showActions`/`uniqueShowAction`) `childView` and show it.\n\t * Pass a `viewId` if you want to diqualify a particular `childView` from being considered.\n\t * @method\n\t * @param {number} viewId If provided it will show the first `view` not to match `viewId`\n\t * @return {boolean|Netx.Models.AppView} First enabled instance of {@link Netx.Models.AppView} or `false`\n\t */\n\tshowFirstEnabledView(viewId) {\n\t\tconst viewSpec = this.getFirstEnabledView(viewId);\n\t\tif (!viewSpec) return;\n\n\t\tconst action = Netx.Actions.Find(viewSpec.get('uniqueShowAction'));\n\t\taction && this.performAction(action, [viewSpec.get('view'), null]);\n\n\t\treturn viewSpec;\n\t}\n\n\t/**\n\t * Show a `childView` by `name`\n\t * @method\n\t * @param {string} name `childView` name\n\t */\n\tshowViewByName(name) {\n\t\tlet view = this.getViewByName(name);\n\n\t\tif (!view) {\n\t\t\tlet viewSpec = this.viewCollection.findWhere({name: name});\n\t\t\tview = viewSpec && this.instantiateView(viewSpec);\n\t\t}\n\n\t\tview && this.showView(view);\n\n\t\t// Chain\n\t\treturn this;\n\t}\n\n\t/**\n\t * Provided with the view we are changing to and the knowledge of the current view\n\t * you can block the change by returning `false`\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @returns {boolean} Ok to change/show view\n\t */\n\tviewChanging(view) {\n\t\t// Transient views:\n\t\t// It should be noted - the view will go away still if you change views in its original `viewCollection` - since you are\n\t\t// affecting its original home - it will return (like in the category edit view - clicking another tab in the sidebar -\n\t\t// since that is where the category edit view belongs).\n\t\t// I think this is the desired behavior and avoids a lot of complications we would have if we tried to manage any deeper\n\t\t// than this. If we do, for some reason, decide we want to block it on all fronts - we will need to add this logic check\n\t\t// to the removal method in `multi-view` and check if the view being removed is `switched` and if so if it is blocking and\n\t\t// leave it be - but then you are entering a world of headaches I would imagine... it would be really hard to not create\n\t\t// collisions eventually. I think we would also need to add an idea of a queued active view when an official switch back\n\t\t// does finally occur.\n\t\t// If we have an active view and that view did not orginalyy belong to us, check its `transientOptions`\n\t\tconst activeView = this.getActiveView();\n\t\tif (\n\t\t\tactiveView &&\n\t\t\t!activeView.viewSpec.isMyOriginalCollection(this.viewCollection)\n\t\t) {\n\t\t\tconst transientOpts = activeView.transientOptions || {};\n\t\t\tif (transientOpts.blocking) {\n\t\t\t\t// Update `cachedActiveView` (so we will go to the view that was trying to show when done with this blocking one)\n\t\t\t\tthis.cachedActiveView = view;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Everything has happend in the core hiding of this `childView`\n\t * Executes just before `whenHidden` is resolved\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#view:hidden|view:hidden}\n\t * @see {@link Netx.View#whenHidden|whenHidden}\n\t */\n\tviewAfterHidden(view) {\n\t\t// Multi-view does not currently have any default functionality here\n\t\t// But this mehtod is only implemented in multi-view - other views extending this should call `super`\n\t\t// unless certain that they will always override any behavior that may be later placed here\n\t}\n\n\t/**\n\t * Everything has happend in the core showing of this `childView`\n\t * Executes just before `whenShown` is resolved\n\t * @method\n\t * @param {Netx.View} view Instance of {@link Netx.View} (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#view:shown|view:shown}\n\t * @see {@link Netx.View#whenShown|whenShown}\n\t */\n\tviewAfterShown(view) {\n\t\tthis.setClassName(view);\n\n\t\t// TODO: if the following view is one that renders when its collection fetches\n\t\t// and that is happening or is currently happening - we will get a double render\n\t\t// But I can't know if the view is going to need rendering or not...\n\t\t// We could check ( view.collection || view.model ) `syncedOnce` || `syncing` but\n\t\t// we still do not know if the view is listening to that. Until we figure out a\n\t\t// good pattern - the double render will occur - it is better than the view not\n\t\t// rendering at all by chance\n\t\t!view.renderedOnce && view.render();\n\t}\n\n\t/**\n\t * A `childView` was instantiated (a brand new `childView` was born - or at least as far as this view is concerned)\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#childViewAdded|childViewAdded}\n\t */\n\tviewInstantiated(view) {\n\t\tconst viewSpec = view.viewSpec;\n\n\t\t// So we can out the right one back when our visitor leaves (if nothing else steps up to the plate)\n\t\tif (!viewSpec.isMyOriginalCollection(this.viewCollection)) {\n\t\t\tthis.cachedActiveView = this.getActiveView();\n\t\t}\n\n\t\t// We are only enabled on instatiate if valid\n\t\tviewSpec.set('enabled', this.isViewActionValid(viewSpec));\n\n\t\t////////////////////////////////\n\t\t// LISTENERS\n\t\t////////////////////////////////\n\t\tconst action = Netx.Actions.Find(viewSpec.get('uniqueShowAction')) || {};\n\t\tif (action.testOnSync) {\n\t\t\tview.collection &&\n\t\t\t\tthis.listenTo(\n\t\t\t\t\tview.collection,\n\t\t\t\t\t'sync reset',\n\t\t\t\t\t_.partial(this.viewActionSynced, view),\n\t\t\t\t);\n\t\t\tview.model &&\n\t\t\t\tthis.listenTo(\n\t\t\t\t\tview.model,\n\t\t\t\t\t'sync',\n\t\t\t\t\t_.partial(this.viewActionSynced, view),\n\t\t\t\t);\n\t\t}\n\t\t////////////////////////////////\n\t\t// !LISTENERS\n\t\t////////////////////////////////\n\n\t\t// Rather than doing this on the `childView` object we must do it manually\n\t\t// otherwise we need to start modifying the `className` or we get the classes back on each render\n\t\tview.$el.addClass(this.additionalViewClasses);\n\n\t\t// Reset confirmation\n\t\tview.confirmedUnsavedChanges = false;\n\n\t\t// This is the first time - so show it now\n\t\t// Or we were added from an existing view collection and were active\n\t\tif (this.showOnAdd || view.viewSpec.get('active')) {\n\t\t\tthis.showView(view);\n\t\t}\n\t}\n\n\t/**\n\t * A `model` or `collection` related to a `childView`'s `showAction`/`uniqueShowAction` has syced, check if we should be enabled or not\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * TODO: Refactor actions and break up the pieces, like tests and synced listeners etc\n\t */\n\tviewActionSynced(view) {\n\t\tconst viewSpec = view && view.viewSpec;\n\t\tviewSpec && viewSpec.set('enabled', this.isViewActionValid(viewSpec));\n\t}\n\n\t/**\n\t * `hide` is about to start on a `childView`\n\t * At this point no animations or actual hiding [should] have taken place\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#view:hiding|view:hiding}\n\t */\n\tviewOnHiding(view) {\n\t\t// Only change its active status to `false` if it beloings to our `viewCollection`\n\t\tview.viewSpec.isMyOriginalCollection(this.viewCollection) &&\n\t\t\tview.viewSpec.set('active', false);\n\t\t// A defer here - just as with `viewRemoved` - there can always be that perfect timing where a new view is coming in\n\t\t// A defer is sufficient to avoid these perfect timing bad deals\n\t\t_.defer(() => {\n\t\t\t// We are not already hiding, the view will be removed on hide, this is the only view left and we want to hide when empty\n\t\t\tif (\n\t\t\t\t!this.hiding &&\n\t\t\t\tview.removeOnHide &&\n\t\t\t\tthis.hideOnEmpty &&\n\t\t\t\tthis.viewCollection.length === 1 &&\n\t\t\t\t(!view.viewSpec || this.viewCollection.at(0).id === view.viewSpec.id)\n\t\t\t) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * `show` is about to start on a `childView`\n\t * At this point no animations or actual hiding [should] have taken place\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#view:showing|view:showing}\n\t */\n\tviewOnShowing(view) {\n\t\t// DAM-18927 - don't activate if another view has taken it's place\n\t\tif (view.viewSpec.cid === this.currentViewSpec.cid) {\n\t\t\t// Set as active view\n\t\t\tview.viewSpec.set('active', true);\n\t\t}\n\t}\n\n\t/**\n\t * A `childView` was removed\n\t * @method\n\t * @param {Netx.View} view View (created via {@link Netx.Models.AppView})\n\t * @listens {@link Netx.Views.MultiView#removedChildView|removedChildView}\n\t */\n\tviewRemoved(view) {\n\t\t// Cleanup classes that were added\n\t\tview.$el.removeClass(this.additionalViewClasses);\n\n\t\t// If we were the cached view - we are not anymore\n\t\tif (this.cachedActiveView && view.cid === this.cachedActiveView.cid) {\n\t\t\tdelete this.cachedActiveView;\n\t\t}\n\n\t\tconst idx = this.registeredViews.indexOf(view.viewSpec.id);\n\t\tidx > -1 && this.registeredViews.splice(idx, 1);\n\n\t\t////////////////////////////////\n\t\t// STOP LISTENERS\n\t\t////////////////////////////////\n\t\t// See `viewInstantiated` method\n\t\tthis.stopListening(view);\n\t\t_.each(view.viewSpec.get('showActions'), (action) => {\n\t\t\tthis.stopListening(dispatcher, action);\n\t\t});\n\t\tthis.stopListening(dispatcher, view.viewSpec.get('uniqueShowAction'));\n\t\tview.collection && this.stopListening(view.collection, 'sync reset');\n\t\tview.model && this.stopListening(view.model, 'sync');\n\t\t////////////////////////////////\n\t\t// !STOP LISTENERS\n\t\t////////////////////////////////\n\n\t\t// This should have happend in the viewHidden method - but just in case it was bypassed\n\t\t// This only happens if our `viewCollection` is the `viewSpec`'s original collection\n\t\tview.viewSpec.isMyOriginalCollection(this.viewCollection) &&\n\t\t\tview.viewSpec.set('active', false);\n\n\t\t// Vars\n\t\tconst activeView = this.getActiveView();\n\t\tconst activeViewMatch =\n\t\t\t!activeView || activeView.viewSpec.id === view.viewSpec.id;\n\n\t\t// Make sure we are not already hiding or removing\n\t\tif (this.hiding || this.removing) return;\n\n\t\t// Wait for the chance a new view may have been added\n\t\t_.defer(() => {\n\t\t\tif (this.removing) return;\n\t\t\t// There is nothing left to show - hide this\n\t\t\tif (!this.viewCollection.length) {\n\t\t\t\tthis.hideOnEmpty && this.hide();\n\t\t\t} else {\n\t\t\t\tlet viewToShow;\n\t\t\t\tif (view.viewSpec !== this.currentViewSpec) {\n\t\t\t\t\t// A new current view has already been set in this time but is not visible\n\t\t\t\t\tconst currentView = this.currentViewSpec.get('view');\n\t\t\t\t\tif (!currentView.isShown) {\n\t\t\t\t\t\tviewToShow = currentView;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Either there is no defined active view or the view we just removed was the active one and no others are active\n\t\t\t\telse if (activeViewMatch && !this.getActiveView()) {\n\t\t\t\t\tif (this.lastViewSpec && this.viewCollection.get(this.lastViewSpec)) {\n\t\t\t\t\t\tviewToShow = this.lastViewSpec.get('view');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst keys = _.keys(this.childViews);\n\t\t\t\t\t\tviewToShow =\n\t\t\t\t\t\t\tthis.cachedActiveView || this.childViews[keys[keys.length - 1]];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// We should not be in a situation where we want to show something that is already hiding/removing\n\t\t\t\tif (\n\t\t\t\t\tviewToShow &&\n\t\t\t\t\t!viewToShow.removing &&\n\t\t\t\t\t(!viewToShow.hiding || !viewToShow.removeOnHide)\n\t\t\t\t) {\n\t\t\t\t\tthis.showView(viewToShow);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete this.cachedActiveView;\n\t\t});\n\t}\n\n\t/** @type {boolean} */\n\tstatic get __isMultiView__() {\n\t\treturn true;\n\t}\n\n\t/** @type {string} */\n\tstatic get __name__() {\n\t\treturn 'MultiView';\n\t}\n}\n\nexport default MultiView;\n"],"sourceRoot":""}