mirror of
https://github.com/Febbweiss/febbweiss.github.io.git
synced 2026-03-05 06:35:50 +00:00
Fix: add dependencies
This commit is contained in:
20
demo/filebrowser-durandal-widget/lib/durandal/.bower.json
Normal file
20
demo/filebrowser-durandal-widget/lib/durandal/.bower.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Durandal",
|
||||
"version": "2.1.0",
|
||||
"dependencies": {
|
||||
"jquery": "1.9.1",
|
||||
"requirejs": "2.1.11",
|
||||
"requirejs-text": "2.0.7",
|
||||
"knockout.js": "3.1.0"
|
||||
},
|
||||
"homepage": "https://github.com/BlueSpire/Durandal-Bower",
|
||||
"_release": "2.1.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "2.1.0",
|
||||
"commit": "613eb67114c9dacdc68604a34f91090cd33f8b0b"
|
||||
},
|
||||
"_source": "https://github.com/BlueSpire/Durandal-Bower.git",
|
||||
"_target": "~2.1.0",
|
||||
"_originalSource": "durandal"
|
||||
}
|
||||
194
demo/filebrowser-durandal-widget/lib/durandal/Changes.txt
Normal file
194
demo/filebrowser-durandal-widget/lib/durandal/Changes.txt
Normal file
@@ -0,0 +1,194 @@
|
||||
2.1.0
|
||||
-Fix Issue #381: Update Durandal to use KO 3
|
||||
-Fix Issue #374: Bootstrap 3.0 & Font-Awesome Update
|
||||
-Fix Issue #380: Replaced html bindings with text bindings in sample application codes
|
||||
-Fix Issue #375: Potentially insecure code in Durandal example app
|
||||
-Fix Issue #372: Better system.guid implementation
|
||||
-Fix Issue #385: Routes are case sensitive (and should not be by default)
|
||||
-Fix Issue #357: Child routers which are 3 levels deep are broken with 2.0.1
|
||||
-Fix Issue #376: returning false in canDeactivate strips queryString
|
||||
-Fix Issue #354: Check for obj.prototype before reading or assigning
|
||||
-Fix Issue #407: Entrance Transition Bug
|
||||
-Fix Issue #337: module canActivate is not fired when module is already active
|
||||
-Fix Issue #382: Allow more granular control for module comparison during activation
|
||||
-Fix Issue #293: Transitions now use CSS3 animations when available.
|
||||
-Fix Issue #440: Remove *details part when hash generated #440
|
||||
-Fix Issues #386 and #437: Double activate when using activator with compose binding
|
||||
-Fix Issue #257: Add PUT and DELETE methods to http plugin
|
||||
-Fix Issue #270: Add "as" parameter to compose binding
|
||||
-Fix Issue #409: Navigate method: Only set explicitNavigation to true when trigger is true
|
||||
-Fix Issue #286: Adding the ability to use a .hasChildRoutes boolean route property rather than *details
|
||||
-Fix Issue #312: Improved query string to handle multiple occurences of the same key
|
||||
-Fix Issue #315: Append startRoute option to router activate options
|
||||
-Fix Issue #343: Support for observable route titles
|
||||
-Fix Issue #355: Fix bug where IE will fail to load view due to wrong typeName
|
||||
-Fix Issue #360: Added a toJSON function to the http module to allow customizing how objects are converted
|
||||
-Fix Issue #405: Added Layout = null to index view for vs template and nuget starter kit
|
||||
-Fix Issue #368: Added headers to http.js plugin
|
||||
-Fix Issue #412/#413: Route configured as RegExp object throwing error
|
||||
-Fix Issue #426: Fix bug where guardRoute cannot redirect to ''
|
||||
-Fix Issue #480: DurandalRouteConfiguration.nav to be optional in Typescript definition
|
||||
-Fix Issue #449: dialog's config.messageBoxView working improperly
|
||||
-Fix Issue #445: Improve 'Route Not Found' message
|
||||
-Fix Issue #362: Dialog improvements
|
||||
-Fix Issue #452: Provide original error to system.error
|
||||
-Fix Issue #459: Fixed bug in router where querystring in child routes causes Route Not Found errors
|
||||
-Fix Issue #464: Fix a bug that causes routes to be relative even when in pushState
|
||||
-Fix Issue #473 and 476: Querystring function should only split on first '='
|
||||
-Fix Issue #482: Support full HTML templates
|
||||
-Fix Issue #486: Allow `app.title` to be an observable.
|
||||
-Fix Issue #483: Renaming "module" variable
|
||||
-Fix Issue #300: closeDialog convenience API
|
||||
-Fix Issue #361: TS File has incorrect sig for observable.defineProperty by making the actual implementation more flexible
|
||||
-Fix Issue #436, #453 and #371: Composition complete callbacks not trigged
|
||||
-Fix Issue #481: Dialog improvement (adding binding callback to custom contexts)
|
||||
-Fix Issue #346 and #438: various composition part pass through issues
|
||||
-Fix Issue #475 and #432: Abort composition when the context is changed during activation
|
||||
-Fix Issue #488/#421: TypeScript - expose durandal/system and durandal/viewEngine in module
|
||||
-Fix Issue #490: Add optional change detection via the observable module. See docs for details.
|
||||
-Fix Issue #494: Feature: serializer.clone
|
||||
-Fix Issue #495: Maybe add a router navigation started event (added router:navigation:processing)
|
||||
-Fix Issue #498 and #496: Overwriting an observable array results in one-way binding of the new array
|
||||
-Fix Issue #489: Observable plugin resetting Deferred properties as undefined
|
||||
-Fix Issue #366: Make Observable Tracking Non-Enumerable
|
||||
-Fix Issue #501: Entrance transition bug in Chrome 34
|
||||
-Fix Issue #503: Updated showMessage overload
|
||||
-Fix Issue #395: setRoot() composition skips canActivate
|
||||
-Fix Issues #418, #181, #297: Various fixes to activator hierarchies and child routers
|
||||
-Fix Issue #461: Router: Click binding not stripping root path
|
||||
-Fix Issue #508: Composition on error override
|
||||
-Fix Issue #511: Always end composition, even on error
|
||||
-Fix Issue #509: Unable to set activator settings "closeOnDeactivate" property to false
|
||||
-Fix Issue #512: Multi-item activator issue
|
||||
-Fix Issue #356: Don't throw exception in deferred fail in canActivate
|
||||
-Fix Issue #417: Added support for null routes.
|
||||
-Fix Issue #500: Observable.js - Custom shouldIgnorePropertyName
|
||||
-Fix Issue #505: Make observable plug-in convert existing properties
|
||||
-Fix Issue #262: binding different views to the same view-model (enable default behavior of router)
|
||||
-Fix Issue #430: Sometimes, negative response from CanDeactivate doesn't restore previous URL
|
||||
-Fix Issue #520: Ensuring that composition show never inadvertently hides elements
|
||||
-Fix Issue #514: Don't enforce viewPlugin
|
||||
-Fix Issue #519: Optimize Part Replacement
|
||||
-Fix Issue #513: Navigating back refreshes the page in latest chrome, when using router.navigate with {replace: true}
|
||||
-Fix Issue #516: Add dynamic child hash via cwooldridge
|
||||
-Fix Issue #515: Cache Parsed Views
|
||||
-Fix Issue #479: Can't use template with vs2013 express
|
||||
-Fix Issue #523: viewEngine$createView does not deliver promise but deferred object when returning cached element
|
||||
-Fix issue #530: add console.error call to logError
|
||||
-Fix Issue #531: Made dialog.isOpen computed
|
||||
-Fixed a bug with activation when modules were reused. Lifecycle wasn't fully enforced.
|
||||
-Added a string.trim polyfill
|
||||
-Updated Bootstrap to 3.1.1
|
||||
-Updated FontAwesome to 4.0.3.1
|
||||
-Updated Knockout to 3.1.0
|
||||
-Updated RequireJS to 2.1.11
|
||||
-Updated RequireJS Text Plugin to 2.0.7
|
||||
-Updated Mimosa skeleton to 2.x
|
||||
-Various fixes/extensions to the docs and readme
|
||||
-Various css improvements and typographic fixes
|
||||
|
||||
2.0.1
|
||||
-Fix Issue #259: Fragment doesn't include query when using push state
|
||||
-Fix Issue #258: Absolute links not working when using push state
|
||||
-Fix Issue #254: Bad mainConfigFile entry in the default weyland-config of the Durandal nuget package
|
||||
-Fix Issue #267: Added missing generic type arguments in the Durandal.d.ts file
|
||||
-Fix Issue #265: Undefined reference error when trying to remove the previous view binding instruction from the dom, which doesn't exist.
|
||||
-Fix Issue #261: Improving the Mimosa starter kit by adding bower support for font awesome and durandal
|
||||
-Fix Issue #271: observable.defineProperty overwrites ko
|
||||
-Fix Issue #272: Add a condition on the target attribute so that when pushState is activated, there is a way to bypass the router.
|
||||
-Fix Issue #275: The close declaration in Durandal's TypeScript d.ts file would not allow for passing result parameters. Fixed by adding a rest argument called results.
|
||||
-Fix Issue #255: router.activate Promise never resolves with 'silent' activation
|
||||
-Fix Issue #278: Fixed Route Not Found error in IE11 Preview
|
||||
-Fix Issue #279: Binding handlers added through composition.addBindingHandler don't work outside of a composition
|
||||
-Fix Issue #266: composition.bindAndShow overwrites the elements local display style
|
||||
-Fix Issue #268: TS Definition file Error - Exported variable 'router' has or is using or is using private type 'durandal/typescript.rootRouter'
|
||||
-Fix Issue #264: TS Definition missing activeInstruction().config.route
|
||||
-Fix Issue #281: Infinite Loop Navigation
|
||||
-Fix Issue #292: Correctly position dialog in more scnenarios
|
||||
-Fix Issue #266: Router 2.0 fails to render views when cacheViews is not defined
|
||||
-Fix Issue #305: Navigating from one view to another hangs the application.
|
||||
-Fix Issue #310: Router Swallows errors from activate() promise
|
||||
-Fix Issue #319: dialog:autofocus was being called on last instead of first tagged element
|
||||
-Fix Issue #316: a Widget with no "parts" results in an exception being thrown
|
||||
-Fix Issue #309: Improvements for property DurandalRouteConfiguration.nav and more consistent router ordering.
|
||||
-Fix Issue #324: fix binder-spec to address beforeBind/afterBind renaming to binding/bind...
|
||||
-Fix Issue #334: add events tests
|
||||
-Fix Issue #323: Unit test errors on OSX
|
||||
-Fix Issue #333: Changed entrance animations callbacks from complete to always
|
||||
-Fix Issue #331: compositioncomplete does not get triggered
|
||||
-Fix Issue #330: router canReuseCurrentActivation() function is not quite right
|
||||
-Fix Issue #307: Router handling of null/undefined href is possibly reversed?
|
||||
-Fix Issue #303: Multiple route are active when are base on single viewmodel
|
||||
-Fix Issue #304: Heap Size growing, DOM element detached
|
||||
-Fix Issue #256: [data-part]'s nested in [data-bind] elements get removed from childParts in widgets
|
||||
-Fix Issue #284: Publish 1.X Docs Publicly
|
||||
-Fix Issue #317: Put Samples Online
|
||||
-Fix Issue #308: dialog isn't positioned correctly when is set composition.defaultTransitionName
|
||||
-Fix Issue #338: Old custom almond script used
|
||||
-Fix Issue #341: pushState href="" (empty string) not recognized as internal navigation
|
||||
-Fix Issue #339: exceptions thrown in compositionComplete callbacks prevent other callbacks to run. (other callback may need handling as well.)
|
||||
-Fix Issue #342: logical `if` flow bug in observable.js -> innerSetter
|
||||
-Fix Issue #351: TypeError when redirecting to currently loaded view
|
||||
-Improved ordering of compositionComplete callbacks.
|
||||
-Some perf improvements in the composition engine.
|
||||
-Don't include a trailing slash on the root when the router navigates.
|
||||
-Fixing an improper node removal in one execution path of composition relating to rebinding views.
|
||||
-Tweaking the .NET Index.cshtml so that it plays nicer when using the router in push state mode.
|
||||
|
||||
2.0.0
|
||||
-Massive reorganization of the github repo. The reorg was done to cleanly separate the library, samples and starter kit source from the platform targets and to facilitate a cleaner build process with less manual "fixup" as the list of supported platforms expands.
|
||||
-Durandal now expects to live along side 3rd party script libraries, outside of your application code. All samples and starter kits have been updated to use requirejs.path to setup the correct mapping, per platform. Additionally, the framework no longer assumes that plugins or transitions are under the durandal folder. The starter kits all use requirejs.path to map them to their actual location.
|
||||
-Durandal no longer has any dependencies on globally defined variables. It now requires everything through the module system. This means that jQuery and Knockout must be defined in order for Durandal to function properly. The samples/starter kits all set up the proper configuration to make this happen. This allows you to keep ko/jquery in global scope by using an explicit define call, giving you the same expereience as 1.x or you can now use require.paths and shim config to keep everything out of the gloabl scope if you desire.
|
||||
-There is now an official plugin model which should be configured before calling app.start. This allows plugins to load in, adding binding handlers and extending durandal APIs before your application code runs. You can pass configuration to the plugins as part of this process. Once the plugin model was in place we moved several libraries out of the core and into plugins. These include: dialog (formerly modalDialog), widget and http. Additional plugins shipping with Durandal 2.0 include: router, history, serializer and observable. Plugins which should be directly installed with the new plugin system include: router, dialog, widget and observable (optionally).
|
||||
-The modalDialog module was renamed to "dialog" and changed to a plugin. The messageBox module's source and view are now part of the dialog module. Formerly, showing a modal added a "modal" property on to the shown module which could be used to close the modal and return a value. This is no longer the case. Closing and returning a value should now be done with dialog.close(viewModel, returnValue). If you need to customize the MessageBox, you can access it via dialog.MessageBox. It's view now uses text bindings instead of html bindings for better security. The dialog's default context has also been updated to take advantage of the new compositionComplete event so that sizing/positioning of the dialog occurs after all internal compositions are complete. This means that new dialog contexts should have addHost, removeHost and compositionComplete callbacks. The compositionComplete callbacks receives the view, parent view and composition context as arguments.
|
||||
-The viewModelBinder was renamed to binder.
|
||||
-The router has been completely re-written. It no longer has any dependencies outside of Durandal's core dependencies. (No more SammyJS) The router is built on top of a new history module which encapsulates the low-level history manipulation. This was done so that developers who have unique routing requirements can dispense with Durandal's router but not have to also re-write the history portion of the system. The new router adds a new router binding handler, child routers, better deep linking support, many bug fixes, support for not only parameterized routes, but also splats, optional parameters and query strings. It also has a better mechanism for handling unknown routes, default routes and conventional routing. The router also publishes events related to its activity and sports a simple, fluent configuration interface.
|
||||
-The viewModel module was renamed to "activator" and its activator function was renamed to "create". Passing an array as activationData now results in activate being called with one argument for each array element. The areItemsSame settings callback now has four parameters: currentItem, newItem, currentActivationData, newActivationData.
|
||||
-The viewEngine had some refactoring to expose parseMarkup and processMarkup. We also added ensureSingleElement and createFallbackView.
|
||||
-New composition lifecycle. Without an activator: activate, binding (renamed from beforeBind), bindingComplete (renamed from afterBind), attached (renamed from viewAttached), compositionComplete, detached. With an activator: canActivate, activate, binding, bindingComplete, attached, compositionComplete, canDeactivate, deactivate, detached. The compositionComplete event fires after the entire composition that the current view model is a part of is completely finished and all nodes are in the document. This event bubbles, starting by notifying child view models first, then parents. The detached event fires whenever the module's corresponding view is removed from the DOM. Composition now supports inline views by setting mode:'inline' on the binding and supplying the view as a child element. Composition now supports templated parts by setting mode:'templated' and supplying the part overrides as child elements. Composition now supports activationData which will be passed to the module's activate function. Composition now has a new function called addBindingHandler. This allows you to create a standard knockout binding handler whose execution is delayed until the composition.current.complete event is fired. The binding callback on a VM can now return false, to cancel the applyBindings call. It can also return an object with a property called applyBindings to control this. Furthermore, the object that is returned from the binding callback is passed along to the beforeBind and afterBind hooks of the view model binder to allow plugins access to this information. Returning a promise from activate is no longer necessary. You can return one to halt binding and screen composition, but no longer need to.
|
||||
-Fixed bug with widget part overrides that contain widgets with part overrides. Easier mapping of widgets via new widget apis: mapKindToModuleId/convertKindToModulePath and mapKindToViewId/convertKindToViewPath. Widgets are now almost entirely built on composition so the standard composition lifecycle applies. Widgets are now composed of a view.html and a viewmodel.js (not controller.js). Settings are no longer passed to the constructor, but into the activate fuction.
|
||||
-New system module helper apis: resolveObject (can be used in TypeScript to return the viewmodel out of a module), assert, error, extend, wait, isElement, isArray, isObject, isBoolean, isArguments, isFunction, isString, isNumber, isDate and isRexExp. The acquire function's promise now correctly reports load errors through the standard promise error mechanism. Previously when passing multiple module ids to system.aqcuire, the promise would resolve with one argument per module. However, this causes problems when used with non-jQuery promises. As a result the acquire function was reworked so that if an array of ids is passed or
|
||||
multiple ids are passed then the promise resolves with an array of modules. system.error is plumbed throughout the framework to surface real errors as opposed to simple logs.
|
||||
-Added "fadeOnly" option to the entrance transition. Removing some bogus styles after the transition completes.
|
||||
-Removed app.adaptToDevice()...which was causing lots of confusion.
|
||||
-Removed the optimizer. It is now replaced by Weyland.
|
||||
-New samples and starter kits available for: raw HTML, Bower, .NET (Nuget and VSIX), and Mimosa.
|
||||
-Added support for Bower
|
||||
-Added more knockout samples
|
||||
-Better support for Q integration
|
||||
-Added api docs via YUIDoc
|
||||
-Lots of bug fixes
|
||||
-Updated docs and conversion guide
|
||||
-Official TypeScript definition file
|
||||
|
||||
1.2.0
|
||||
|
||||
-Fixed bugs in .NET's optimizer. Added a 'loader' options to specify 'almond' or 'require'.
|
||||
-Prevent popping when transitioning with the 'entrance' transition.
|
||||
-Passing activation data through the puggable beforeActivate function of the activator.
|
||||
-Added throwOnErrors to the view model binder. Errors will be thrown instead of logged when true.
|
||||
-Major fix in widgets which prevented proper databinding and broken/excessive rendering.
|
||||
-Improved settings construction for composition and widget binding handlers.
|
||||
-Upped the starting z index for modals to play better with bootstrap.
|
||||
-Added beforeBind and afterBind hooks to the view model binder.
|
||||
-Fixed the .NET optimizer config file generation for the 'require' loader option.
|
||||
-View engine now removes empty text nodes when parsing views.
|
||||
-Fixed a bug in the router which cuased non-hashed routes to malfunction.
|
||||
-Added a guardRoute hook to the router to allow, deny or redirect based on the route.
|
||||
-Fixed bugs in the implementation of app.adaptToDevice
|
||||
-Added a missing call to the deferred's promise() function in the view model module which caused issues with Q.
|
||||
-Made all the Durandal samples into a single app.
|
||||
-Switched Durandal over to dependency array module syntax to enable easier use with other AMD loaders.
|
||||
-Added hooks for the Dojo AMD loader.
|
||||
-Router navigateTo is only used for defined routes now.
|
||||
-Updated the .NET command line parser dependency to the latest version and fixed breaking changes.
|
||||
-Enabled modal dialogs to return multiple values to a promise.
|
||||
-Implemented route queuing for the router.
|
||||
-More unit tests added.
|
||||
-Fixed some invalid html generation in the view engine.
|
||||
-Styled the widget demo.
|
||||
-Fixed transitions so that they run even if there is no new child.
|
||||
-Router now uses route.caption for document title.
|
||||
-Router navigateTo now accepts a second parameter of 'skip' to skip the route handler or 'replace' to replace the url.
|
||||
-Removed the app module's startup dependency on the message box module.
|
||||
-Removed the setView hook that the view model binder called. Replaced it with beforeBind and afterBind hooks.
|
||||
21
demo/filebrowser-durandal-widget/lib/durandal/License.txt
Normal file
21
demo/filebrowser-durandal-widget/lib/durandal/License.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2012 Blue Spire Consulting, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
57
demo/filebrowser-durandal-widget/lib/durandal/README.md
Normal file
57
demo/filebrowser-durandal-widget/lib/durandal/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||

|
||||
|
||||
Durandal is a cross-device, cross-platform client framework written in JavaScript and designed to make Single Page Applications (SPAs) easy to create and maintain. We've used it to build apps for PC, Mac, Linux, iOS and Android...and now it's your turn...
|
||||
|
||||
[](https://travis-ci.org/BlueSpire/Durandal)
|
||||
|
||||
## Features
|
||||
|
||||
* Clean MV* Architecture
|
||||
* JS & HTML Modularity
|
||||
* Simple App Lifecycle
|
||||
* Eventing, Modals, Message Boxes, etc.
|
||||
* Navigation & Screen State Management
|
||||
* Consistent Async Programming w/ Promises
|
||||
* App Bundling and Optimization
|
||||
* Use any Backend Technology
|
||||
* Built on top of [jQuery](http://jquery.com/), [Knockout](http://knockoutjs.com/) & [RequireJS](http://requirejs.org/).
|
||||
* Integrates with popular CSS libraries such as [Bootstrap](http://twitter.github.com/bootstrap/) and [Foundation](http://foundation.zurb.com/).
|
||||
* Make your own templatable and data-bindable widgets.
|
||||
* Fully Testable
|
||||
|
||||
## Documentation
|
||||
|
||||
All the documentation is located on [the official site](http://durandaljs.com/), so have a look there for help on how to [get started](http://durandaljs.com/get-started.html), [read tutorials](http://durandaljs.com/docs.html), [view sample descriptions](http://durandaljs.com/documentation/Understanding-the-Samples.html) and peruse the module reference docs.
|
||||
|
||||
## Community & Support
|
||||
|
||||
Need help with something that the docs aren't providing an answer to?
|
||||
Visit our [google group](https://groups.google.com/forum/?fromgroups#!forum/durandaljs) and join in the conversation.
|
||||
|
||||
## Contributing
|
||||
|
||||
We'd love for you to contribute to the Durandal project! If you are interested, please have a read through our [contributing](/CONTRIBUTING.md) guide.
|
||||
|
||||
## License
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2012 Blue Spire Consulting, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
10
demo/filebrowser-durandal-widget/lib/durandal/bower.json
Normal file
10
demo/filebrowser-durandal-widget/lib/durandal/bower.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Durandal",
|
||||
"version": "2.1.0",
|
||||
"dependencies": {
|
||||
"jquery":"1.9.1",
|
||||
"requirejs":"2.1.11",
|
||||
"requirejs-text":"2.0.7",
|
||||
"knockout.js":"3.1.0"
|
||||
}
|
||||
}
|
||||
197
demo/filebrowser-durandal-widget/lib/durandal/css/durandal.css
Normal file
197
demo/filebrowser-durandal-widget/lib/durandal/css/durandal.css
Normal file
@@ -0,0 +1,197 @@
|
||||
/*!
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details
|
||||
*/
|
||||
|
||||
.modalBlockout {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
opacity: 0;
|
||||
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-backface-visibility: hidden;
|
||||
|
||||
-webkit-transition: opacity 0.1s linear;
|
||||
-moz-transition: opacity 0.1s linear;
|
||||
-o-transition: opacity 0.1s linear;
|
||||
transition: opacity 0.1s linear;
|
||||
}
|
||||
|
||||
.modalHost {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
|
||||
-webkit-backface-visibility: hidden;
|
||||
|
||||
-webkit-transition: opacity 0.1s linear;
|
||||
-moz-transition: opacity 0.1s linear;
|
||||
-o-transition: opacity 0.1s linear;
|
||||
transition: opacity 0.1s linear;
|
||||
}
|
||||
|
||||
.messageBox {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.durandal-view-404 {
|
||||
color: red;
|
||||
margin: 8px 0;
|
||||
padding: 8px;
|
||||
|
||||
-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
|
||||
-moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
|
||||
|
||||
border: 1px solid #999;
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeOut {
|
||||
0% {opacity: 1;}
|
||||
100% {opacity: 0;}
|
||||
}
|
||||
|
||||
@-moz-keyframes fadeOut {
|
||||
0% {opacity: 1;}
|
||||
100% {opacity: 0;}
|
||||
}
|
||||
|
||||
@-o-keyframes fadeOut {
|
||||
0% {opacity: 1;}
|
||||
100% {opacity: 0;}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
0% {opacity: 1;}
|
||||
100% {opacity: 0;}
|
||||
}
|
||||
|
||||
.entrance-out {
|
||||
-webkit-animation-fill-mode:both;
|
||||
-moz-animation-fill-mode:both;
|
||||
-ms-animation-fill-mode:both;
|
||||
-o-animation-fill-mode:both;
|
||||
animation-fill-mode:both;
|
||||
-webkit-animation-duration:0.1s;
|
||||
-moz-animation-duration:0.1s;
|
||||
-ms-animation-duration:0.1s;
|
||||
-o-animation-duration:0.1s;
|
||||
animation-duration:0.1s;
|
||||
-webkit-animation-name: fadeOut;
|
||||
-moz-animation-name: fadeOut;
|
||||
-o-animation-name: fadeOut;
|
||||
animation-name: fadeOut;
|
||||
}
|
||||
|
||||
@-webkit-keyframes slideInRight {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(20px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes slideInRight {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-moz-transform: translateX(20px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
-moz-transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes slideInRight {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-o-transform: translateX(20px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
-o-transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.entrance-in {
|
||||
-webkit-animation-fill-mode:both;
|
||||
-moz-animation-fill-mode:both;
|
||||
-ms-animation-fill-mode:both;
|
||||
-o-animation-fill-mode:both;
|
||||
animation-fill-mode:both;
|
||||
-webkit-animation-duration:0.5s;
|
||||
-moz-animation-duration:0.5s;
|
||||
-ms-animation-duration:0.5s;
|
||||
-o-animation-duration:0.5s;
|
||||
animation-duration:0.5s;
|
||||
-webkit-animation-name: slideInRight;
|
||||
-moz-animation-name: slideInRight;
|
||||
-o-animation-name: slideInRight;
|
||||
animation-name: slideInRight;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
@-moz-keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
@-o-keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
.entrance-in-fade {
|
||||
-webkit-animation-fill-mode:both;
|
||||
-moz-animation-fill-mode:both;
|
||||
-ms-animation-fill-mode:both;
|
||||
-o-animation-fill-mode:both;
|
||||
animation-fill-mode:both;
|
||||
-webkit-animation-duration:0.5s;
|
||||
-moz-animation-duration:0.5s;
|
||||
-ms-animation-duration:0.5s;
|
||||
-o-animation-duration:0.5s;
|
||||
animation-duration:0.5s;
|
||||
-webkit-animation-name: fadeIn;
|
||||
-moz-animation-name: fadeIn;
|
||||
-o-animation-name: fadeIn;
|
||||
animation-name: fadeIn;
|
||||
}
|
||||
BIN
demo/filebrowser-durandal-widget/lib/durandal/img/icon.png
Normal file
BIN
demo/filebrowser-durandal-widget/lib/durandal/img/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
645
demo/filebrowser-durandal-widget/lib/durandal/js/activator.js
Normal file
645
demo/filebrowser-durandal-widget/lib/durandal/js/activator.js
Normal file
@@ -0,0 +1,645 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The activator module encapsulates all logic related to screen/component activation.
|
||||
* An activator is essentially an asynchronous state machine that understands a particular state transition protocol.
|
||||
* The protocol ensures that the following series of events always occur: `canDeactivate` (previous state), `canActivate` (new state), `deactivate` (previous state), `activate` (new state).
|
||||
* Each of the _can_ callbacks may return a boolean, affirmative value or promise for one of those. If either of the _can_ functions yields a false result, then activation halts.
|
||||
* @module activator
|
||||
* @requires system
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'knockout'], function (system, ko) {
|
||||
var activator;
|
||||
var defaultOptions = {
|
||||
canDeactivate:true
|
||||
};
|
||||
|
||||
function ensureSettings(settings) {
|
||||
if (settings == undefined) {
|
||||
settings = {};
|
||||
}
|
||||
|
||||
if (!system.isBoolean(settings.closeOnDeactivate)) {
|
||||
settings.closeOnDeactivate = activator.defaults.closeOnDeactivate;
|
||||
}
|
||||
|
||||
if (!settings.beforeActivate) {
|
||||
settings.beforeActivate = activator.defaults.beforeActivate;
|
||||
}
|
||||
|
||||
if (!settings.afterDeactivate) {
|
||||
settings.afterDeactivate = activator.defaults.afterDeactivate;
|
||||
}
|
||||
|
||||
if(!settings.affirmations){
|
||||
settings.affirmations = activator.defaults.affirmations;
|
||||
}
|
||||
|
||||
if (!settings.interpretResponse) {
|
||||
settings.interpretResponse = activator.defaults.interpretResponse;
|
||||
}
|
||||
|
||||
if (!settings.areSameItem) {
|
||||
settings.areSameItem = activator.defaults.areSameItem;
|
||||
}
|
||||
|
||||
if (!settings.findChildActivator) {
|
||||
settings.findChildActivator = activator.defaults.findChildActivator;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
function invoke(target, method, data) {
|
||||
if (system.isArray(data)) {
|
||||
return target[method].apply(target, data);
|
||||
}
|
||||
|
||||
return target[method](data);
|
||||
}
|
||||
|
||||
function deactivate(item, close, settings, dfd, setter) {
|
||||
if (item && item.deactivate) {
|
||||
system.log('Deactivating', item);
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = item.deactivate(close);
|
||||
} catch(error) {
|
||||
system.log('ERROR: ' + error.message, error);
|
||||
dfd.resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result && result.then) {
|
||||
result.then(function() {
|
||||
settings.afterDeactivate(item, close, setter);
|
||||
dfd.resolve(true);
|
||||
}, function(reason) {
|
||||
system.log(reason);
|
||||
dfd.resolve(false);
|
||||
});
|
||||
} else {
|
||||
settings.afterDeactivate(item, close, setter);
|
||||
dfd.resolve(true);
|
||||
}
|
||||
} else {
|
||||
if (item) {
|
||||
settings.afterDeactivate(item, close, setter);
|
||||
}
|
||||
|
||||
dfd.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
function activate(newItem, activeItem, callback, activationData) {
|
||||
var result;
|
||||
|
||||
if(newItem && newItem.activate) {
|
||||
system.log('Activating', newItem);
|
||||
|
||||
try {
|
||||
result = invoke(newItem, 'activate', activationData);
|
||||
} catch(error) {
|
||||
system.log('ERROR: ' + error.message, error);
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(result && result.then) {
|
||||
result.then(function() {
|
||||
activeItem(newItem);
|
||||
callback(true);
|
||||
}, function(reason) {
|
||||
system.log('ERROR: ' + reason.message, reason);
|
||||
callback(false);
|
||||
});
|
||||
} else {
|
||||
activeItem(newItem);
|
||||
callback(true);
|
||||
}
|
||||
}
|
||||
|
||||
function canDeactivateItem(item, close, settings, options) {
|
||||
options = system.extend({}, defaultOptions, options);
|
||||
settings.lifecycleData = null;
|
||||
|
||||
return system.defer(function (dfd) {
|
||||
function continueCanDeactivate() {
|
||||
if (item && item.canDeactivate && options.canDeactivate) {
|
||||
var resultOrPromise;
|
||||
try {
|
||||
resultOrPromise = item.canDeactivate(close);
|
||||
} catch (error) {
|
||||
system.log('ERROR: ' + error.message, error);
|
||||
dfd.resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultOrPromise.then) {
|
||||
resultOrPromise.then(function (result) {
|
||||
settings.lifecycleData = result;
|
||||
dfd.resolve(settings.interpretResponse(result));
|
||||
}, function (reason) {
|
||||
system.log('ERROR: ' + reason.message, reason);
|
||||
dfd.resolve(false);
|
||||
});
|
||||
} else {
|
||||
settings.lifecycleData = resultOrPromise;
|
||||
dfd.resolve(settings.interpretResponse(resultOrPromise));
|
||||
}
|
||||
} else {
|
||||
dfd.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
var childActivator = settings.findChildActivator(item);
|
||||
if (childActivator) {
|
||||
childActivator.canDeactivate().then(function(result) {
|
||||
if (result) {
|
||||
continueCanDeactivate();
|
||||
} else {
|
||||
dfd.resolve(false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
continueCanDeactivate();
|
||||
}
|
||||
}).promise();
|
||||
};
|
||||
|
||||
function canActivateItem(newItem, activeItem, settings, activeData, newActivationData) {
|
||||
settings.lifecycleData = null;
|
||||
|
||||
return system.defer(function (dfd) {
|
||||
if (settings.areSameItem(activeItem(), newItem, activeData, newActivationData)) {
|
||||
dfd.resolve(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newItem && newItem.canActivate) {
|
||||
var resultOrPromise;
|
||||
try {
|
||||
resultOrPromise = invoke(newItem, 'canActivate', newActivationData);
|
||||
} catch (error) {
|
||||
system.log('ERROR: ' + error.message, error);
|
||||
dfd.resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultOrPromise.then) {
|
||||
resultOrPromise.then(function(result) {
|
||||
settings.lifecycleData = result;
|
||||
dfd.resolve(settings.interpretResponse(result));
|
||||
}, function(reason) {
|
||||
system.log('ERROR: ' + reason.message, reason);
|
||||
dfd.resolve(false);
|
||||
});
|
||||
} else {
|
||||
settings.lifecycleData = resultOrPromise;
|
||||
dfd.resolve(settings.interpretResponse(resultOrPromise));
|
||||
}
|
||||
} else {
|
||||
dfd.resolve(true);
|
||||
}
|
||||
}).promise();
|
||||
};
|
||||
|
||||
/**
|
||||
* An activator is a read/write computed observable that enforces the activation lifecycle whenever changing values.
|
||||
* @class Activator
|
||||
*/
|
||||
function createActivator(initialActiveItem, settings) {
|
||||
var activeItem = ko.observable(null);
|
||||
var activeData;
|
||||
|
||||
settings = ensureSettings(settings);
|
||||
|
||||
var computed = ko.computed({
|
||||
read: function () {
|
||||
return activeItem();
|
||||
},
|
||||
write: function (newValue) {
|
||||
computed.viaSetter = true;
|
||||
computed.activateItem(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
computed.__activator__ = true;
|
||||
|
||||
/**
|
||||
* The settings for this activator.
|
||||
* @property {ActivatorSettings} settings
|
||||
*/
|
||||
computed.settings = settings;
|
||||
settings.activator = computed;
|
||||
|
||||
/**
|
||||
* An observable which indicates whether or not the activator is currently in the process of activating an instance.
|
||||
* @method isActivating
|
||||
* @return {boolean}
|
||||
*/
|
||||
computed.isActivating = ko.observable(false);
|
||||
|
||||
computed.forceActiveItem = function (item) {
|
||||
activeItem(item);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether or not the specified item can be deactivated.
|
||||
* @method canDeactivateItem
|
||||
* @param {object} item The item to check.
|
||||
* @param {boolean} close Whether or not to check if close is possible.
|
||||
* @param {object} options Options for controlling the activation process.
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.canDeactivateItem = function (item, close, options) {
|
||||
return canDeactivateItem(item, close, settings, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deactivates the specified item.
|
||||
* @method deactivateItem
|
||||
* @param {object} item The item to deactivate.
|
||||
* @param {boolean} close Whether or not to close the item.
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.deactivateItem = function (item, close) {
|
||||
return system.defer(function(dfd) {
|
||||
computed.canDeactivateItem(item, close).then(function(canDeactivate) {
|
||||
if (canDeactivate) {
|
||||
deactivate(item, close, settings, dfd, activeItem);
|
||||
} else {
|
||||
computed.notifySubscribers();
|
||||
dfd.resolve(false);
|
||||
}
|
||||
});
|
||||
}).promise();
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether or not the specified item can be activated.
|
||||
* @method canActivateItem
|
||||
* @param {object} item The item to check.
|
||||
* @param {object} activationData Data associated with the activation.
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.canActivateItem = function (newItem, activationData) {
|
||||
return canActivateItem(newItem, activeItem, settings, activeData, activationData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Activates the specified item.
|
||||
* @method activateItem
|
||||
* @param {object} newItem The item to activate.
|
||||
* @param {object} newActivationData Data associated with the activation.
|
||||
* @param {object} options Options for controlling the activation process.
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.activateItem = function (newItem, newActivationData, options) {
|
||||
var viaSetter = computed.viaSetter;
|
||||
computed.viaSetter = false;
|
||||
|
||||
return system.defer(function (dfd) {
|
||||
if (computed.isActivating()) {
|
||||
dfd.resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
computed.isActivating(true);
|
||||
|
||||
var currentItem = activeItem();
|
||||
if (settings.areSameItem(currentItem, newItem, activeData, newActivationData)) {
|
||||
computed.isActivating(false);
|
||||
dfd.resolve(true);
|
||||
return;
|
||||
}
|
||||
|
||||
computed.canDeactivateItem(currentItem, settings.closeOnDeactivate, options).then(function (canDeactivate) {
|
||||
if (canDeactivate) {
|
||||
computed.canActivateItem(newItem, newActivationData).then(function (canActivate) {
|
||||
if (canActivate) {
|
||||
system.defer(function (dfd2) {
|
||||
deactivate(currentItem, settings.closeOnDeactivate, settings, dfd2);
|
||||
}).promise().then(function () {
|
||||
newItem = settings.beforeActivate(newItem, newActivationData);
|
||||
activate(newItem, activeItem, function (result) {
|
||||
activeData = newActivationData;
|
||||
computed.isActivating(false);
|
||||
dfd.resolve(result);
|
||||
}, newActivationData);
|
||||
});
|
||||
} else {
|
||||
if (viaSetter) {
|
||||
computed.notifySubscribers();
|
||||
}
|
||||
|
||||
computed.isActivating(false);
|
||||
dfd.resolve(false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (viaSetter) {
|
||||
computed.notifySubscribers();
|
||||
}
|
||||
|
||||
computed.isActivating(false);
|
||||
dfd.resolve(false);
|
||||
}
|
||||
});
|
||||
}).promise();
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether or not the activator, in its current state, can be activated.
|
||||
* @method canActivate
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.canActivate = function () {
|
||||
var toCheck;
|
||||
|
||||
if (initialActiveItem) {
|
||||
toCheck = initialActiveItem;
|
||||
initialActiveItem = false;
|
||||
} else {
|
||||
toCheck = computed();
|
||||
}
|
||||
|
||||
return computed.canActivateItem(toCheck);
|
||||
};
|
||||
|
||||
/**
|
||||
* Activates the activator, in its current state.
|
||||
* @method activate
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.activate = function () {
|
||||
var toActivate;
|
||||
|
||||
if (initialActiveItem) {
|
||||
toActivate = initialActiveItem;
|
||||
initialActiveItem = false;
|
||||
} else {
|
||||
toActivate = computed();
|
||||
}
|
||||
|
||||
return computed.activateItem(toActivate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether or not the activator, in its current state, can be deactivated.
|
||||
* @method canDeactivate
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.canDeactivate = function (close) {
|
||||
return computed.canDeactivateItem(computed(), close);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deactivates the activator, in its current state.
|
||||
* @method deactivate
|
||||
* @return {promise}
|
||||
*/
|
||||
computed.deactivate = function (close) {
|
||||
return computed.deactivateItem(computed(), close);
|
||||
};
|
||||
|
||||
computed.includeIn = function (includeIn) {
|
||||
includeIn.canActivate = function () {
|
||||
return computed.canActivate();
|
||||
};
|
||||
|
||||
includeIn.activate = function () {
|
||||
return computed.activate();
|
||||
};
|
||||
|
||||
includeIn.canDeactivate = function (close) {
|
||||
return computed.canDeactivate(close);
|
||||
};
|
||||
|
||||
includeIn.deactivate = function (close) {
|
||||
return computed.deactivate(close);
|
||||
};
|
||||
};
|
||||
|
||||
if (settings.includeIn) {
|
||||
computed.includeIn(settings.includeIn);
|
||||
} else if (initialActiveItem) {
|
||||
computed.activate();
|
||||
}
|
||||
|
||||
computed.forItems = function (items) {
|
||||
settings.closeOnDeactivate = false;
|
||||
|
||||
settings.determineNextItemToActivate = function (list, lastIndex) {
|
||||
var toRemoveAt = lastIndex - 1;
|
||||
|
||||
if (toRemoveAt == -1 && list.length > 1) {
|
||||
return list[1];
|
||||
}
|
||||
|
||||
if (toRemoveAt > -1 && toRemoveAt < list.length - 1) {
|
||||
return list[toRemoveAt];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
settings.beforeActivate = function (newItem) {
|
||||
var currentItem = computed();
|
||||
|
||||
if (!newItem) {
|
||||
newItem = settings.determineNextItemToActivate(items, currentItem ? items.indexOf(currentItem) : 0);
|
||||
} else {
|
||||
var index = items.indexOf(newItem);
|
||||
|
||||
if (index == -1) {
|
||||
items.push(newItem);
|
||||
} else {
|
||||
newItem = items()[index];
|
||||
}
|
||||
}
|
||||
|
||||
return newItem;
|
||||
};
|
||||
|
||||
settings.afterDeactivate = function (oldItem, close) {
|
||||
if (close) {
|
||||
items.remove(oldItem);
|
||||
}
|
||||
};
|
||||
|
||||
var originalCanDeactivate = computed.canDeactivate;
|
||||
computed.canDeactivate = function (close) {
|
||||
if (close) {
|
||||
return system.defer(function (dfd) {
|
||||
var list = items();
|
||||
var results = [];
|
||||
|
||||
function finish() {
|
||||
for (var j = 0; j < results.length; j++) {
|
||||
if (!results[j]) {
|
||||
dfd.resolve(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dfd.resolve(true);
|
||||
}
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
computed.canDeactivateItem(list[i], close).then(function (result) {
|
||||
results.push(result);
|
||||
if (results.length == list.length) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).promise();
|
||||
} else {
|
||||
return originalCanDeactivate();
|
||||
}
|
||||
};
|
||||
|
||||
var originalDeactivate = computed.deactivate;
|
||||
computed.deactivate = function (close) {
|
||||
if (close) {
|
||||
return system.defer(function (dfd) {
|
||||
var list = items();
|
||||
var results = 0;
|
||||
var listLength = list.length;
|
||||
|
||||
function doDeactivate(item) {
|
||||
setTimeout(function () {
|
||||
computed.deactivateItem(item, close).then(function () {
|
||||
results++;
|
||||
items.remove(item);
|
||||
if (results == listLength) {
|
||||
dfd.resolve();
|
||||
}
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
for (var i = 0; i < listLength; i++) {
|
||||
doDeactivate(list[i]);
|
||||
}
|
||||
}).promise();
|
||||
} else {
|
||||
return originalDeactivate();
|
||||
}
|
||||
};
|
||||
|
||||
return computed;
|
||||
};
|
||||
|
||||
return computed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class ActivatorSettings
|
||||
* @static
|
||||
*/
|
||||
var activatorSettings = {
|
||||
/**
|
||||
* The default value passed to an object's deactivate function as its close parameter.
|
||||
* @property {boolean} closeOnDeactivate
|
||||
* @default true
|
||||
*/
|
||||
closeOnDeactivate: true,
|
||||
/**
|
||||
* Lower-cased words which represent a truthy value.
|
||||
* @property {string[]} affirmations
|
||||
* @default ['yes', 'ok', 'true']
|
||||
*/
|
||||
affirmations: ['yes', 'ok', 'true'],
|
||||
/**
|
||||
* Interprets the response of a `canActivate` or `canDeactivate` call using the known affirmative values in the `affirmations` array.
|
||||
* @method interpretResponse
|
||||
* @param {object} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
interpretResponse: function(value) {
|
||||
if(system.isObject(value)) {
|
||||
value = value.can || false;
|
||||
}
|
||||
|
||||
if(system.isString(value)) {
|
||||
return ko.utils.arrayIndexOf(this.affirmations, value.toLowerCase()) !== -1;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* Determines whether or not the current item and the new item are the same.
|
||||
* @method areSameItem
|
||||
* @param {object} currentItem
|
||||
* @param {object} newItem
|
||||
* @param {object} currentActivationData
|
||||
* @param {object} newActivationData
|
||||
* @return {boolean}
|
||||
*/
|
||||
areSameItem: function(currentItem, newItem, currentActivationData, newActivationData) {
|
||||
return currentItem == newItem;
|
||||
},
|
||||
/**
|
||||
* Called immediately before the new item is activated.
|
||||
* @method beforeActivate
|
||||
* @param {object} newItem
|
||||
*/
|
||||
beforeActivate: function(newItem) {
|
||||
return newItem;
|
||||
},
|
||||
/**
|
||||
* Called immediately after the old item is deactivated.
|
||||
* @method afterDeactivate
|
||||
* @param {object} oldItem The previous item.
|
||||
* @param {boolean} close Whether or not the previous item was closed.
|
||||
* @param {function} setter The activate item setter function.
|
||||
*/
|
||||
afterDeactivate: function(oldItem, close, setter) {
|
||||
if(close && setter) {
|
||||
setter(null);
|
||||
}
|
||||
},
|
||||
findChildActivator: function(item){
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ActivatorModule
|
||||
* @static
|
||||
*/
|
||||
activator = {
|
||||
/**
|
||||
* The default settings used by activators.
|
||||
* @property {ActivatorSettings} defaults
|
||||
*/
|
||||
defaults: activatorSettings,
|
||||
/**
|
||||
* Creates a new activator.
|
||||
* @method create
|
||||
* @param {object} [initialActiveItem] The item which should be immediately activated upon creation of the ativator.
|
||||
* @param {ActivatorSettings} [settings] Per activator overrides of the default activator settings.
|
||||
* @return {Activator} The created activator.
|
||||
*/
|
||||
create: createActivator,
|
||||
/**
|
||||
* Determines whether or not the provided object is an activator or not.
|
||||
* @method isActivator
|
||||
* @param {object} object Any object you wish to verify as an activator or not.
|
||||
* @return {boolean} True if the object is an activator; false otherwise.
|
||||
*/
|
||||
isActivator:function(object){
|
||||
return object && object.__activator__;
|
||||
}
|
||||
};
|
||||
|
||||
return activator;
|
||||
});
|
||||
172
demo/filebrowser-durandal-widget/lib/durandal/js/app.js
Normal file
172
demo/filebrowser-durandal-widget/lib/durandal/js/app.js
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The app module controls app startup, plugin loading/configuration and root visual display.
|
||||
* @module app
|
||||
* @requires system
|
||||
* @requires viewEngine
|
||||
* @requires composition
|
||||
* @requires events
|
||||
* @requires jquery
|
||||
*/
|
||||
define(['durandal/system', 'durandal/viewEngine', 'durandal/composition', 'durandal/events', 'jquery'], function(system, viewEngine, composition, Events, $) {
|
||||
var app,
|
||||
allPluginIds = [],
|
||||
allPluginConfigs = [];
|
||||
|
||||
function loadPlugins(){
|
||||
return system.defer(function(dfd){
|
||||
if(allPluginIds.length == 0){
|
||||
dfd.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
system.acquire(allPluginIds).then(function(loaded){
|
||||
for(var i = 0; i < loaded.length; i++){
|
||||
var currentModule = loaded[i];
|
||||
|
||||
if(currentModule.install){
|
||||
var config = allPluginConfigs[i];
|
||||
if(!system.isObject(config)){
|
||||
config = {};
|
||||
}
|
||||
|
||||
currentModule.install(config);
|
||||
system.log('Plugin:Installed ' + allPluginIds[i]);
|
||||
}else{
|
||||
system.log('Plugin:Loaded ' + allPluginIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dfd.resolve();
|
||||
}).fail(function(err){
|
||||
system.error('Failed to load plugin(s). Details: ' + err.message);
|
||||
});
|
||||
}).promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class AppModule
|
||||
* @static
|
||||
* @uses Events
|
||||
*/
|
||||
app = {
|
||||
/**
|
||||
* The title of your application.
|
||||
* @property {string} title
|
||||
*/
|
||||
title: 'Application',
|
||||
/**
|
||||
* Configures one or more plugins to be loaded and installed into the application.
|
||||
* @method configurePlugins
|
||||
* @param {object} config Keys are plugin names. Values can be truthy, to simply install the plugin, or a configuration object to pass to the plugin.
|
||||
* @param {string} [baseUrl] The base url to load the plugins from.
|
||||
*/
|
||||
configurePlugins:function(config, baseUrl){
|
||||
var pluginIds = system.keys(config);
|
||||
baseUrl = baseUrl || 'plugins/';
|
||||
|
||||
if(baseUrl.indexOf('/', baseUrl.length - 1) === -1){
|
||||
baseUrl += '/';
|
||||
}
|
||||
|
||||
for(var i = 0; i < pluginIds.length; i++){
|
||||
var key = pluginIds[i];
|
||||
allPluginIds.push(baseUrl + key);
|
||||
allPluginConfigs.push(config[key]);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Starts the application.
|
||||
* @method start
|
||||
* @return {promise}
|
||||
*/
|
||||
start: function() {
|
||||
system.log('Application:Starting');
|
||||
|
||||
if (this.title) {
|
||||
document.title = this.title;
|
||||
}
|
||||
|
||||
return system.defer(function (dfd) {
|
||||
$(function() {
|
||||
loadPlugins().then(function(){
|
||||
dfd.resolve();
|
||||
system.log('Application:Started');
|
||||
});
|
||||
});
|
||||
}).promise();
|
||||
},
|
||||
/**
|
||||
* Sets the root module/view for the application.
|
||||
* @method setRoot
|
||||
* @param {string} root The root view or module.
|
||||
* @param {string} [transition] The transition to use from the previous root (or splash screen) into the new root.
|
||||
* @param {string} [applicationHost] The application host element or id. By default the id 'applicationHost' will be used.
|
||||
*/
|
||||
setRoot: function(root, transition, applicationHost) {
|
||||
var hostElement, settings = { activate:true, transition: transition };
|
||||
|
||||
if (!applicationHost || system.isString(applicationHost)) {
|
||||
hostElement = document.getElementById(applicationHost || 'applicationHost');
|
||||
} else {
|
||||
hostElement = applicationHost;
|
||||
}
|
||||
|
||||
if (system.isString(root)) {
|
||||
if (viewEngine.isViewUrl(root)) {
|
||||
settings.view = root;
|
||||
} else {
|
||||
settings.model = root;
|
||||
}
|
||||
} else {
|
||||
settings.model = root;
|
||||
}
|
||||
|
||||
function finishComposition() {
|
||||
if(settings.model) {
|
||||
if (settings.model.canActivate) {
|
||||
try {
|
||||
var result = settings.model.canActivate();
|
||||
if (result && result.then) {
|
||||
result.then(function (actualResult) {
|
||||
if (actualResult) {
|
||||
composition.compose(hostElement, settings);
|
||||
}
|
||||
}).fail(function (err) {
|
||||
system.error(err);
|
||||
});
|
||||
} else if (result) {
|
||||
composition.compose(hostElement, settings);
|
||||
}
|
||||
} catch (er) {
|
||||
system.error(er);
|
||||
}
|
||||
} else {
|
||||
composition.compose(hostElement, settings);
|
||||
}
|
||||
} else {
|
||||
composition.compose(hostElement, settings);
|
||||
}
|
||||
}
|
||||
|
||||
if(system.isString(settings.model)) {
|
||||
system.acquire(settings.model).then(function(module) {
|
||||
settings.model = system.resolveObject(module);
|
||||
finishComposition();
|
||||
}).fail(function(err) {
|
||||
system.error('Failed to load root module (' + settings.model + '). Details: ' + err.message);
|
||||
});
|
||||
} else {
|
||||
finishComposition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Events.includeIn(app);
|
||||
|
||||
return app;
|
||||
});
|
||||
152
demo/filebrowser-durandal-widget/lib/durandal/js/binder.js
Normal file
152
demo/filebrowser-durandal-widget/lib/durandal/js/binder.js
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The binder joins an object instance and a DOM element tree by applying databinding and/or invoking binding lifecycle callbacks (binding and bindingComplete).
|
||||
* @module binder
|
||||
* @requires system
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'knockout'], function (system, ko) {
|
||||
var binder,
|
||||
insufficientInfoMessage = 'Insufficient Information to Bind',
|
||||
unexpectedViewMessage = 'Unexpected View Type',
|
||||
bindingInstructionKey = 'durandal-binding-instruction',
|
||||
koBindingContextKey = '__ko_bindingContext__';
|
||||
|
||||
function normalizeBindingInstruction(result){
|
||||
if(result === undefined){
|
||||
return { applyBindings: true };
|
||||
}
|
||||
|
||||
if(system.isBoolean(result)){
|
||||
return { applyBindings:result };
|
||||
}
|
||||
|
||||
if(result.applyBindings === undefined){
|
||||
result.applyBindings = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function doBind(obj, view, bindingTarget, data){
|
||||
if (!view || !bindingTarget) {
|
||||
if (binder.throwOnErrors) {
|
||||
system.error(insufficientInfoMessage);
|
||||
} else {
|
||||
system.log(insufficientInfoMessage, view, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view.getAttribute) {
|
||||
if (binder.throwOnErrors) {
|
||||
system.error(unexpectedViewMessage);
|
||||
} else {
|
||||
system.log(unexpectedViewMessage, view, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var viewName = view.getAttribute('data-view');
|
||||
|
||||
try {
|
||||
var instruction;
|
||||
|
||||
if (obj && obj.binding) {
|
||||
instruction = obj.binding(view);
|
||||
}
|
||||
|
||||
instruction = normalizeBindingInstruction(instruction);
|
||||
binder.binding(data, view, instruction);
|
||||
|
||||
if(instruction.applyBindings){
|
||||
system.log('Binding', viewName, data);
|
||||
ko.applyBindings(bindingTarget, view);
|
||||
}else if(obj){
|
||||
ko.utils.domData.set(view, koBindingContextKey, { $data:obj });
|
||||
}
|
||||
|
||||
binder.bindingComplete(data, view, instruction);
|
||||
|
||||
if (obj && obj.bindingComplete) {
|
||||
obj.bindingComplete(view);
|
||||
}
|
||||
|
||||
ko.utils.domData.set(view, bindingInstructionKey, instruction);
|
||||
return instruction;
|
||||
} catch (e) {
|
||||
e.message = e.message + ';\nView: ' + viewName + ";\nModuleId: " + system.getModuleId(data);
|
||||
if (binder.throwOnErrors) {
|
||||
system.error(e);
|
||||
} else {
|
||||
system.log(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class BinderModule
|
||||
* @static
|
||||
*/
|
||||
return binder = {
|
||||
/**
|
||||
* Called before every binding operation. Does nothing by default.
|
||||
* @method binding
|
||||
* @param {object} data The data that is about to be bound.
|
||||
* @param {DOMElement} view The view that is about to be bound.
|
||||
* @param {object} instruction The object that carries the binding instructions.
|
||||
*/
|
||||
binding: system.noop,
|
||||
/**
|
||||
* Called after every binding operation. Does nothing by default.
|
||||
* @method bindingComplete
|
||||
* @param {object} data The data that has just been bound.
|
||||
* @param {DOMElement} view The view that has just been bound.
|
||||
* @param {object} instruction The object that carries the binding instructions.
|
||||
*/
|
||||
bindingComplete: system.noop,
|
||||
/**
|
||||
* Indicates whether or not the binding system should throw errors or not.
|
||||
* @property {boolean} throwOnErrors
|
||||
* @default false The binding system will not throw errors by default. Instead it will log them.
|
||||
*/
|
||||
throwOnErrors: false,
|
||||
/**
|
||||
* Gets the binding instruction that was associated with a view when it was bound.
|
||||
* @method getBindingInstruction
|
||||
* @param {DOMElement} view The view that was previously bound.
|
||||
* @return {object} The object that carries the binding instructions.
|
||||
*/
|
||||
getBindingInstruction:function(view){
|
||||
return ko.utils.domData.get(view, bindingInstructionKey);
|
||||
},
|
||||
/**
|
||||
* Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context.
|
||||
* @method bindContext
|
||||
* @param {KnockoutBindingContext} bindingContext The current binding context.
|
||||
* @param {DOMElement} view The view to bind.
|
||||
* @param {object} [obj] The data to bind to, causing the creation of a child binding context if present.
|
||||
* @param {string} [dataAlias] An alias for $data if present.
|
||||
*/
|
||||
bindContext: function(bindingContext, view, obj, dataAlias) {
|
||||
if (obj && bindingContext) {
|
||||
bindingContext = bindingContext.createChildContext(obj, typeof(dataAlias) === 'string' ? dataAlias : null);
|
||||
}
|
||||
|
||||
return doBind(obj, view, bindingContext, obj || (bindingContext ? bindingContext.$data : null));
|
||||
},
|
||||
/**
|
||||
* Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context.
|
||||
* @method bind
|
||||
* @param {object} obj The data to bind to.
|
||||
* @param {DOMElement} view The view to bind.
|
||||
*/
|
||||
bind: function(obj, view) {
|
||||
return doBind(obj, view, obj, obj);
|
||||
}
|
||||
};
|
||||
});
|
||||
732
demo/filebrowser-durandal-widget/lib/durandal/js/composition.js
Normal file
732
demo/filebrowser-durandal-widget/lib/durandal/js/composition.js
Normal file
@@ -0,0 +1,732 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The composition module encapsulates all functionality related to visual composition.
|
||||
* @module composition
|
||||
* @requires system
|
||||
* @requires viewLocator
|
||||
* @requires binder
|
||||
* @requires viewEngine
|
||||
* @requires activator
|
||||
* @requires jquery
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'durandal/viewLocator', 'durandal/binder', 'durandal/viewEngine', 'durandal/activator', 'jquery', 'knockout'], function (system, viewLocator, binder, viewEngine, activator, $, ko) {
|
||||
var dummyModel = {},
|
||||
activeViewAttributeName = 'data-active-view',
|
||||
composition,
|
||||
compositionCompleteCallbacks = [],
|
||||
compositionCount = 0,
|
||||
compositionDataKey = 'durandal-composition-data',
|
||||
partAttributeName = 'data-part',
|
||||
bindableSettings = ['model', 'view', 'transition', 'area', 'strategy', 'activationData', 'onError'],
|
||||
visibilityKey = "durandal-visibility-data",
|
||||
composeBindings = ['compose:'];
|
||||
|
||||
function onError(context, error, element) {
|
||||
try {
|
||||
if (context.onError) {
|
||||
try {
|
||||
context.onError(error, element);
|
||||
} catch (e) {
|
||||
system.error(e);
|
||||
}
|
||||
} else {
|
||||
system.error(error);
|
||||
}
|
||||
} finally {
|
||||
endComposition(context, element, true);
|
||||
}
|
||||
}
|
||||
|
||||
function getHostState(parent) {
|
||||
var elements = [];
|
||||
var state = {
|
||||
childElements: elements,
|
||||
activeView: null
|
||||
};
|
||||
|
||||
var child = ko.virtualElements.firstChild(parent);
|
||||
|
||||
while (child) {
|
||||
if (child.nodeType == 1) {
|
||||
elements.push(child);
|
||||
if (child.getAttribute(activeViewAttributeName)) {
|
||||
state.activeView = child;
|
||||
}
|
||||
}
|
||||
|
||||
child = ko.virtualElements.nextSibling(child);
|
||||
}
|
||||
|
||||
if(!state.activeView){
|
||||
state.activeView = elements[0];
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function endComposition(context, element, error) {
|
||||
compositionCount--;
|
||||
|
||||
if(compositionCount === 0) {
|
||||
var callBacks = compositionCompleteCallbacks;
|
||||
compositionCompleteCallbacks = [];
|
||||
|
||||
if (!error) {
|
||||
setTimeout(function () {
|
||||
var i = callBacks.length;
|
||||
|
||||
while (i--) {
|
||||
try {
|
||||
callBacks[i]();
|
||||
} catch (e) {
|
||||
onError(context, e, element);
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp(context);
|
||||
}
|
||||
|
||||
function cleanUp(context){
|
||||
delete context.activeView;
|
||||
delete context.viewElements;
|
||||
}
|
||||
|
||||
function tryActivate(context, successCallback, skipActivation, element) {
|
||||
if(skipActivation){
|
||||
successCallback();
|
||||
} else if (context.activate && context.model && context.model.activate) {
|
||||
var result;
|
||||
|
||||
try{
|
||||
if(system.isArray(context.activationData)) {
|
||||
result = context.model.activate.apply(context.model, context.activationData);
|
||||
} else {
|
||||
result = context.model.activate(context.activationData);
|
||||
}
|
||||
|
||||
if(result && result.then) {
|
||||
result.then(successCallback, function(reason) {
|
||||
onError(context, reason, element);
|
||||
successCallback();
|
||||
});
|
||||
} else if(result || result === undefined) {
|
||||
successCallback();
|
||||
} else {
|
||||
endComposition(context, element);
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
onError(context, e, element);
|
||||
}
|
||||
} else {
|
||||
successCallback();
|
||||
}
|
||||
}
|
||||
|
||||
function triggerAttach(context, element) {
|
||||
var context = this;
|
||||
|
||||
if (context.activeView) {
|
||||
context.activeView.removeAttribute(activeViewAttributeName);
|
||||
}
|
||||
|
||||
if (context.child) {
|
||||
try{
|
||||
if (context.model && context.model.attached) {
|
||||
if (context.composingNewView || context.alwaysTriggerAttach) {
|
||||
context.model.attached(context.child, context.parent, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.attached) {
|
||||
context.attached(context.child, context.parent, context);
|
||||
}
|
||||
|
||||
context.child.setAttribute(activeViewAttributeName, true);
|
||||
|
||||
if (context.composingNewView && context.model && context.model.detached) {
|
||||
ko.utils.domNodeDisposal.addDisposeCallback(context.child, function () {
|
||||
try{
|
||||
context.model.detached(context.child, context.parent, context);
|
||||
}catch(e2){
|
||||
onError(context, e2, element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}catch(e){
|
||||
onError(context, e, element);
|
||||
}
|
||||
}
|
||||
|
||||
context.triggerAttach = system.noop;
|
||||
}
|
||||
|
||||
function shouldTransition(context) {
|
||||
if (system.isString(context.transition)) {
|
||||
if (context.activeView) {
|
||||
if (context.activeView == context.child) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!context.child) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.skipTransitionOnSameViewId) {
|
||||
var currentViewId = context.activeView.getAttribute('data-view');
|
||||
var newViewId = context.child.getAttribute('data-view');
|
||||
return currentViewId != newViewId;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function cloneNodes(nodesArray) {
|
||||
for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
|
||||
var clonedNode = nodesArray[i].cloneNode(true);
|
||||
newNodesArray.push(clonedNode);
|
||||
}
|
||||
return newNodesArray;
|
||||
}
|
||||
|
||||
function replaceParts(context){
|
||||
var parts = cloneNodes(context.parts);
|
||||
var replacementParts = composition.getParts(parts);
|
||||
var standardParts = composition.getParts(context.child);
|
||||
|
||||
for (var partId in replacementParts) {
|
||||
var toReplace = standardParts[partId];
|
||||
if (!toReplace) {
|
||||
toReplace = $('[data-part="' + partId + '"]', context.child).get(0);
|
||||
if (!toReplace) {
|
||||
system.log('Could not find part to override: ' + partId);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
toReplace.parentNode.replaceChild(replacementParts[partId], toReplace);
|
||||
}
|
||||
}
|
||||
|
||||
function removePreviousView(context){
|
||||
var children = ko.virtualElements.childNodes(context.parent), i, len;
|
||||
|
||||
if(!system.isArray(children)){
|
||||
var arrayChildren = [];
|
||||
for(i = 0, len = children.length; i < len; i++){
|
||||
arrayChildren[i] = children[i];
|
||||
}
|
||||
children = arrayChildren;
|
||||
}
|
||||
|
||||
for(i = 1,len = children.length; i < len; i++){
|
||||
ko.removeNode(children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function hide(view) {
|
||||
ko.utils.domData.set(view, visibilityKey, view.style.display);
|
||||
view.style.display = 'none';
|
||||
}
|
||||
|
||||
function show(view) {
|
||||
var displayStyle = ko.utils.domData.get(view, visibilityKey);
|
||||
view.style.display = displayStyle === 'none' ? 'block' : displayStyle;
|
||||
}
|
||||
|
||||
function hasComposition(element){
|
||||
var dataBind = element.getAttribute('data-bind');
|
||||
if(!dataBind){
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0, length = composeBindings.length; i < length; i++){
|
||||
if(dataBind.indexOf(composeBindings[i]) > -1){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class CompositionTransaction
|
||||
* @static
|
||||
*/
|
||||
var compositionTransaction = {
|
||||
/**
|
||||
* Registers a callback which will be invoked when the current composition transaction has completed. The transaction includes all parent and children compositions.
|
||||
* @method complete
|
||||
* @param {function} callback The callback to be invoked when composition is complete.
|
||||
*/
|
||||
complete: function (callback) {
|
||||
compositionCompleteCallbacks.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class CompositionModule
|
||||
* @static
|
||||
*/
|
||||
composition = {
|
||||
/**
|
||||
* An array of all the binding handler names (includeing :) that trigger a composition.
|
||||
* @property {string} composeBindings
|
||||
* @default ['compose:']
|
||||
*/
|
||||
composeBindings:composeBindings,
|
||||
/**
|
||||
* Converts a transition name to its moduleId.
|
||||
* @method convertTransitionToModuleId
|
||||
* @param {string} name The name of the transtion.
|
||||
* @return {string} The moduleId.
|
||||
*/
|
||||
convertTransitionToModuleId: function (name) {
|
||||
return 'transitions/' + name;
|
||||
},
|
||||
/**
|
||||
* The name of the transition to use in all compositions.
|
||||
* @property {string} defaultTransitionName
|
||||
* @default null
|
||||
*/
|
||||
defaultTransitionName: null,
|
||||
/**
|
||||
* Represents the currently executing composition transaction.
|
||||
* @property {CompositionTransaction} current
|
||||
*/
|
||||
current: compositionTransaction,
|
||||
/**
|
||||
* Registers a binding handler that will be invoked when the current composition transaction is complete.
|
||||
* @method addBindingHandler
|
||||
* @param {string} name The name of the binding handler.
|
||||
* @param {object} [config] The binding handler instance. If none is provided, the name will be used to look up an existing handler which will then be converted to a composition handler.
|
||||
* @param {function} [initOptionsFactory] If the registered binding needs to return options from its init call back to knockout, this function will server as a factory for those options. It will receive the same parameters that the init function does.
|
||||
*/
|
||||
addBindingHandler:function(name, config, initOptionsFactory){
|
||||
var key,
|
||||
dataKey = 'composition-handler-' + name,
|
||||
handler;
|
||||
|
||||
config = config || ko.bindingHandlers[name];
|
||||
initOptionsFactory = initOptionsFactory || function(){ return undefined; };
|
||||
|
||||
handler = ko.bindingHandlers[name] = {
|
||||
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||
if(compositionCount > 0){
|
||||
var data = {
|
||||
trigger:ko.observable(null)
|
||||
};
|
||||
|
||||
composition.current.complete(function(){
|
||||
if(config.init){
|
||||
config.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
|
||||
}
|
||||
|
||||
if(config.update){
|
||||
ko.utils.domData.set(element, dataKey, config);
|
||||
data.trigger('trigger');
|
||||
}
|
||||
});
|
||||
|
||||
ko.utils.domData.set(element, dataKey, data);
|
||||
}else{
|
||||
ko.utils.domData.set(element, dataKey, config);
|
||||
|
||||
if(config.init){
|
||||
config.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
return initOptionsFactory(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
|
||||
},
|
||||
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||
var data = ko.utils.domData.get(element, dataKey);
|
||||
|
||||
if(data.update){
|
||||
return data.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
|
||||
}
|
||||
|
||||
if(data.trigger){
|
||||
data.trigger();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (key in config) {
|
||||
if (key !== "init" && key !== "update") {
|
||||
handler[key] = config[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Gets an object keyed with all the elements that are replacable parts, found within the supplied elements. The key will be the part name and the value will be the element itself.
|
||||
* @method getParts
|
||||
* @param {DOMElement\DOMElement[]} elements The element(s) to search for parts.
|
||||
* @return {object} An object keyed by part.
|
||||
*/
|
||||
getParts: function(elements, parts) {
|
||||
parts = parts || {};
|
||||
|
||||
if (!elements) {
|
||||
return parts;
|
||||
}
|
||||
|
||||
if (elements.length === undefined) {
|
||||
elements = [elements];
|
||||
}
|
||||
|
||||
for (var i = 0, length = elements.length; i < length; i++) {
|
||||
var element = elements[i],
|
||||
id;
|
||||
|
||||
if (element.getAttribute) {
|
||||
id = element.getAttribute(partAttributeName);
|
||||
if (id) {
|
||||
parts[id] = element;
|
||||
}
|
||||
|
||||
if (element.hasChildNodes() && !hasComposition(element)) {
|
||||
composition.getParts(element.childNodes, parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
},
|
||||
cloneNodes:cloneNodes,
|
||||
finalize: function (context, element) {
|
||||
if(context.transition === undefined) {
|
||||
context.transition = this.defaultTransitionName;
|
||||
}
|
||||
|
||||
if(!context.child && !context.activeView){
|
||||
if (!context.cacheViews) {
|
||||
ko.virtualElements.emptyNode(context.parent);
|
||||
}
|
||||
|
||||
context.triggerAttach(context, element);
|
||||
endComposition(context, element);
|
||||
} else if (shouldTransition(context)) {
|
||||
var transitionModuleId = this.convertTransitionToModuleId(context.transition);
|
||||
|
||||
system.acquire(transitionModuleId).then(function (transition) {
|
||||
context.transition = transition;
|
||||
|
||||
transition(context).then(function () {
|
||||
if (!context.cacheViews) {
|
||||
if(!context.child){
|
||||
ko.virtualElements.emptyNode(context.parent);
|
||||
}else{
|
||||
removePreviousView(context);
|
||||
}
|
||||
}else if(context.activeView){
|
||||
var instruction = binder.getBindingInstruction(context.activeView);
|
||||
if(instruction && instruction.cacheViews != undefined && !instruction.cacheViews){
|
||||
ko.removeNode(context.activeView);
|
||||
}else{
|
||||
hide(context.activeView);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.child) {
|
||||
show(context.child);
|
||||
}
|
||||
|
||||
context.triggerAttach(context, element);
|
||||
endComposition(context, element);
|
||||
});
|
||||
}).fail(function(err){
|
||||
onError(context, 'Failed to load transition (' + transitionModuleId + '). Details: ' + err.message, element);
|
||||
});
|
||||
} else {
|
||||
if (context.child != context.activeView) {
|
||||
if (context.cacheViews && context.activeView) {
|
||||
var instruction = binder.getBindingInstruction(context.activeView);
|
||||
if(!instruction || (instruction.cacheViews != undefined && !instruction.cacheViews)){
|
||||
ko.removeNode(context.activeView);
|
||||
}else{
|
||||
hide(context.activeView);
|
||||
}
|
||||
}
|
||||
|
||||
if (!context.child) {
|
||||
if (!context.cacheViews) {
|
||||
ko.virtualElements.emptyNode(context.parent);
|
||||
}
|
||||
} else {
|
||||
if (!context.cacheViews) {
|
||||
removePreviousView(context);
|
||||
}
|
||||
|
||||
show(context.child);
|
||||
}
|
||||
}
|
||||
|
||||
context.triggerAttach(context, element);
|
||||
endComposition(context, element);
|
||||
}
|
||||
},
|
||||
bindAndShow: function (child, element, context, skipActivation) {
|
||||
context.child = child;
|
||||
context.parent.__composition_context = context;
|
||||
|
||||
if (context.cacheViews) {
|
||||
context.composingNewView = (ko.utils.arrayIndexOf(context.viewElements, child) == -1);
|
||||
} else {
|
||||
context.composingNewView = true;
|
||||
}
|
||||
|
||||
tryActivate(context, function () {
|
||||
if (context.parent.__composition_context == context) {
|
||||
delete context.parent.__composition_context;
|
||||
|
||||
if (context.binding) {
|
||||
context.binding(context.child, context.parent, context);
|
||||
}
|
||||
|
||||
if (context.preserveContext && context.bindingContext) {
|
||||
if (context.composingNewView) {
|
||||
if(context.parts){
|
||||
replaceParts(context);
|
||||
}
|
||||
|
||||
hide(child);
|
||||
ko.virtualElements.prepend(context.parent, child);
|
||||
|
||||
binder.bindContext(context.bindingContext, child, context.model, context.as);
|
||||
}
|
||||
} else if (child) {
|
||||
var modelToBind = context.model || dummyModel;
|
||||
var currentModel = ko.dataFor(child);
|
||||
|
||||
if (currentModel != modelToBind) {
|
||||
if (!context.composingNewView) {
|
||||
ko.removeNode(child);
|
||||
viewEngine.createView(child.getAttribute('data-view')).then(function(recreatedView) {
|
||||
composition.bindAndShow(recreatedView, element, context, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if(context.parts){
|
||||
replaceParts(context);
|
||||
}
|
||||
|
||||
hide(child);
|
||||
ko.virtualElements.prepend(context.parent, child);
|
||||
|
||||
binder.bind(modelToBind, child);
|
||||
}
|
||||
}
|
||||
|
||||
composition.finalize(context, element);
|
||||
} else {
|
||||
endComposition(context, element);
|
||||
}
|
||||
}, skipActivation, element);
|
||||
},
|
||||
/**
|
||||
* Eecutes the default view location strategy.
|
||||
* @method defaultStrategy
|
||||
* @param {object} context The composition context containing the model and possibly existing viewElements.
|
||||
* @return {promise} A promise for the view.
|
||||
*/
|
||||
defaultStrategy: function (context) {
|
||||
return viewLocator.locateViewForObject(context.model, context.area, context.viewElements);
|
||||
},
|
||||
getSettings: function (valueAccessor, element) {
|
||||
var value = valueAccessor(),
|
||||
settings = ko.utils.unwrapObservable(value) || {},
|
||||
activatorPresent = activator.isActivator(value),
|
||||
moduleId;
|
||||
|
||||
if (system.isString(settings)) {
|
||||
if (viewEngine.isViewUrl(settings)) {
|
||||
settings = {
|
||||
view: settings
|
||||
};
|
||||
} else {
|
||||
settings = {
|
||||
model: settings,
|
||||
activate: !activatorPresent
|
||||
};
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
moduleId = system.getModuleId(settings);
|
||||
if (moduleId) {
|
||||
settings = {
|
||||
model: settings,
|
||||
activate: !activatorPresent
|
||||
};
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
if(!activatorPresent && settings.model) {
|
||||
activatorPresent = activator.isActivator(settings.model);
|
||||
}
|
||||
|
||||
for (var attrName in settings) {
|
||||
if (ko.utils.arrayIndexOf(bindableSettings, attrName) != -1) {
|
||||
settings[attrName] = ko.utils.unwrapObservable(settings[attrName]);
|
||||
} else {
|
||||
settings[attrName] = settings[attrName];
|
||||
}
|
||||
}
|
||||
|
||||
if (activatorPresent) {
|
||||
settings.activate = false;
|
||||
} else if (settings.activate === undefined) {
|
||||
settings.activate = true;
|
||||
}
|
||||
|
||||
return settings;
|
||||
},
|
||||
executeStrategy: function (context, element) {
|
||||
context.strategy(context).then(function (child) {
|
||||
composition.bindAndShow(child, element, context);
|
||||
});
|
||||
},
|
||||
inject: function (context, element) {
|
||||
if (!context.model) {
|
||||
this.bindAndShow(null, element, context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.view) {
|
||||
viewLocator.locateView(context.view, context.area, context.viewElements).then(function (child) {
|
||||
composition.bindAndShow(child, element, context);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.strategy) {
|
||||
context.strategy = this.defaultStrategy;
|
||||
}
|
||||
|
||||
if (system.isString(context.strategy)) {
|
||||
system.acquire(context.strategy).then(function (strategy) {
|
||||
context.strategy = strategy;
|
||||
composition.executeStrategy(context, element);
|
||||
}).fail(function (err) {
|
||||
onError(context, 'Failed to load view strategy (' + context.strategy + '). Details: ' + err.message, element);
|
||||
});
|
||||
} else {
|
||||
this.executeStrategy(context, element);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Initiates a composition.
|
||||
* @method compose
|
||||
* @param {DOMElement} element The DOMElement or knockout virtual element that serves as the parent for the composition.
|
||||
* @param {object} settings The composition settings.
|
||||
* @param {object} [bindingContext] The current binding context.
|
||||
*/
|
||||
compose: function (element, settings, bindingContext, fromBinding) {
|
||||
compositionCount++;
|
||||
|
||||
if(!fromBinding){
|
||||
settings = composition.getSettings(function() { return settings; }, element);
|
||||
}
|
||||
|
||||
if (settings.compositionComplete) {
|
||||
compositionCompleteCallbacks.push(function () {
|
||||
settings.compositionComplete(settings.child, settings.parent, settings);
|
||||
});
|
||||
}
|
||||
|
||||
compositionCompleteCallbacks.push(function () {
|
||||
if(settings.composingNewView && settings.model && settings.model.compositionComplete){
|
||||
settings.model.compositionComplete(settings.child, settings.parent, settings);
|
||||
}
|
||||
});
|
||||
|
||||
var hostState = getHostState(element);
|
||||
|
||||
settings.activeView = hostState.activeView;
|
||||
settings.parent = element;
|
||||
settings.triggerAttach = triggerAttach;
|
||||
settings.bindingContext = bindingContext;
|
||||
|
||||
if (settings.cacheViews && !settings.viewElements) {
|
||||
settings.viewElements = hostState.childElements;
|
||||
}
|
||||
|
||||
if (!settings.model) {
|
||||
if (!settings.view) {
|
||||
this.bindAndShow(null, element, settings);
|
||||
} else {
|
||||
settings.area = settings.area || 'partial';
|
||||
settings.preserveContext = true;
|
||||
|
||||
viewLocator.locateView(settings.view, settings.area, settings.viewElements).then(function (child) {
|
||||
composition.bindAndShow(child, element, settings);
|
||||
});
|
||||
}
|
||||
} else if (system.isString(settings.model)) {
|
||||
system.acquire(settings.model).then(function (module) {
|
||||
settings.model = system.resolveObject(module);
|
||||
composition.inject(settings, element);
|
||||
}).fail(function (err) {
|
||||
onError(settings, 'Failed to load composed module (' + settings.model + '). Details: ' + err.message, element);
|
||||
});
|
||||
} else {
|
||||
composition.inject(settings, element);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ko.bindingHandlers.compose = {
|
||||
init: function() {
|
||||
return { controlsDescendantBindings: true };
|
||||
},
|
||||
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||
var settings = composition.getSettings(valueAccessor, element);
|
||||
if(settings.mode){
|
||||
var data = ko.utils.domData.get(element, compositionDataKey);
|
||||
if(!data){
|
||||
var childNodes = ko.virtualElements.childNodes(element);
|
||||
data = {};
|
||||
|
||||
if(settings.mode === 'inline'){
|
||||
data.view = viewEngine.ensureSingleElement(childNodes);
|
||||
}else if(settings.mode === 'templated'){
|
||||
data.parts = cloneNodes(childNodes);
|
||||
}
|
||||
|
||||
ko.virtualElements.emptyNode(element);
|
||||
ko.utils.domData.set(element, compositionDataKey, data);
|
||||
}
|
||||
|
||||
if(settings.mode === 'inline'){
|
||||
settings.view = data.view.cloneNode(true);
|
||||
}else if(settings.mode === 'templated'){
|
||||
settings.parts = data.parts;
|
||||
}
|
||||
|
||||
settings.preserveContext = true;
|
||||
}
|
||||
|
||||
composition.compose(element, settings, bindingContext, true);
|
||||
}
|
||||
};
|
||||
|
||||
ko.virtualElements.allowedBindings.compose = true;
|
||||
|
||||
return composition;
|
||||
});
|
||||
216
demo/filebrowser-durandal-widget/lib/durandal/js/events.js
Normal file
216
demo/filebrowser-durandal-widget/lib/durandal/js/events.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* Durandal events originate from backbone.js but also combine some ideas from signals.js as well as some additional improvements.
|
||||
* Events can be installed into any object and are installed into the `app` module by default for convenient app-wide eventing.
|
||||
* @module events
|
||||
* @requires system
|
||||
*/
|
||||
define(['durandal/system'], function (system) {
|
||||
var eventSplitter = /\s+/;
|
||||
var Events = function() { };
|
||||
|
||||
/**
|
||||
* Represents an event subscription.
|
||||
* @class Subscription
|
||||
*/
|
||||
var Subscription = function(owner, events) {
|
||||
this.owner = owner;
|
||||
this.events = events;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches a callback to the event subscription.
|
||||
* @method then
|
||||
* @param {function} callback The callback function to invoke when the event is triggered.
|
||||
* @param {object} [context] An object to use as `this` when invoking the `callback`.
|
||||
* @chainable
|
||||
*/
|
||||
Subscription.prototype.then = function (callback, context) {
|
||||
this.callback = callback || this.callback;
|
||||
this.context = context || this.context;
|
||||
|
||||
if (!this.callback) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.owner.on(this.events, this.callback, this.context);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches a callback to the event subscription.
|
||||
* @method on
|
||||
* @param {function} [callback] The callback function to invoke when the event is triggered. If `callback` is not provided, the previous callback will be re-activated.
|
||||
* @param {object} [context] An object to use as `this` when invoking the `callback`.
|
||||
* @chainable
|
||||
*/
|
||||
Subscription.prototype.on = Subscription.prototype.then;
|
||||
|
||||
/**
|
||||
* Cancels the subscription.
|
||||
* @method off
|
||||
* @chainable
|
||||
*/
|
||||
Subscription.prototype.off = function () {
|
||||
this.owner.off(this.events, this.callback, this.context);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object with eventing capabilities.
|
||||
* @class Events
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a subscription or registers a callback for the specified event.
|
||||
* @method on
|
||||
* @param {string} events One or more events, separated by white space.
|
||||
* @param {function} [callback] The callback function to invoke when the event is triggered. If `callback` is not provided, a subscription instance is returned.
|
||||
* @param {object} [context] An object to use as `this` when invoking the `callback`.
|
||||
* @return {Subscription|Events} A subscription is returned if no callback is supplied, otherwise the events object is returned for chaining.
|
||||
*/
|
||||
Events.prototype.on = function(events, callback, context) {
|
||||
var calls, event, list;
|
||||
|
||||
if (!callback) {
|
||||
return new Subscription(this, events);
|
||||
} else {
|
||||
calls = this.callbacks || (this.callbacks = {});
|
||||
events = events.split(eventSplitter);
|
||||
|
||||
while (event = events.shift()) {
|
||||
list = calls[event] || (calls[event] = []);
|
||||
list.push(callback, context);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the callbacks for the specified events.
|
||||
* @method off
|
||||
* @param {string} [events] One or more events, separated by white space to turn off. If no events are specified, then the callbacks will be removed.
|
||||
* @param {function} [callback] The callback function to remove. If `callback` is not provided, all callbacks for the specified events will be removed.
|
||||
* @param {object} [context] The object that was used as `this`. Callbacks with this context will be removed.
|
||||
* @chainable
|
||||
*/
|
||||
Events.prototype.off = function(events, callback, context) {
|
||||
var event, calls, list, i;
|
||||
|
||||
// No events
|
||||
if (!(calls = this.callbacks)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//removing all
|
||||
if (!(events || callback || context)) {
|
||||
delete this.callbacks;
|
||||
return this;
|
||||
}
|
||||
|
||||
events = events ? events.split(eventSplitter) : system.keys(calls);
|
||||
|
||||
// Loop through the callback list, splicing where appropriate.
|
||||
while (event = events.shift()) {
|
||||
if (!(list = calls[event]) || !(callback || context)) {
|
||||
delete calls[event];
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = list.length - 2; i >= 0; i -= 2) {
|
||||
if (!(callback && list[i] !== callback || context && list[i + 1] !== context)) {
|
||||
list.splice(i, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the specified events.
|
||||
* @method trigger
|
||||
* @param {string} [events] One or more events, separated by white space to trigger.
|
||||
* @chainable
|
||||
*/
|
||||
Events.prototype.trigger = function(events) {
|
||||
var event, calls, list, i, length, args, all, rest;
|
||||
if (!(calls = this.callbacks)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
rest = [];
|
||||
events = events.split(eventSplitter);
|
||||
for (i = 1, length = arguments.length; i < length; i++) {
|
||||
rest[i - 1] = arguments[i];
|
||||
}
|
||||
|
||||
// For each event, walk through the list of callbacks twice, first to
|
||||
// trigger the event, then to trigger any `"all"` callbacks.
|
||||
while (event = events.shift()) {
|
||||
// Copy callback lists to prevent modification.
|
||||
if (all = calls.all) {
|
||||
all = all.slice();
|
||||
}
|
||||
|
||||
if (list = calls[event]) {
|
||||
list = list.slice();
|
||||
}
|
||||
|
||||
// Execute event callbacks.
|
||||
if (list) {
|
||||
for (i = 0, length = list.length; i < length; i += 2) {
|
||||
list[i].apply(list[i + 1] || this, rest);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute "all" callbacks.
|
||||
if (all) {
|
||||
args = [event].concat(rest);
|
||||
for (i = 0, length = all.length; i < length; i += 2) {
|
||||
all[i].apply(all[i + 1] || this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a function that will trigger the specified events when called. Simplifies proxying jQuery (or other) events through to the events object.
|
||||
* @method proxy
|
||||
* @param {string} events One or more events, separated by white space to trigger by invoking the returned function.
|
||||
* @return {function} Calling the function will invoke the previously specified events on the events object.
|
||||
*/
|
||||
Events.prototype.proxy = function(events) {
|
||||
var that = this;
|
||||
return (function(arg) {
|
||||
that.trigger(events, arg);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object with eventing capabilities.
|
||||
* @class EventsModule
|
||||
* @static
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds eventing capabilities to the specified object.
|
||||
* @method includeIn
|
||||
* @param {object} targetObject The object to add eventing capabilities to.
|
||||
*/
|
||||
Events.includeIn = function(targetObject) {
|
||||
targetObject.on = Events.prototype.on;
|
||||
targetObject.off = Events.prototype.off;
|
||||
targetObject.trigger = Events.prototype.trigger;
|
||||
targetObject.proxy = Events.prototype.proxy;
|
||||
};
|
||||
|
||||
return Events;
|
||||
});
|
||||
@@ -0,0 +1,570 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The dialog module enables the display of message boxes, custom modal dialogs and other overlays or slide-out UI abstractions. Dialogs are constructed by the composition system which interacts with a user defined dialog context. The dialog module enforced the activator lifecycle.
|
||||
* @module dialog
|
||||
* @requires system
|
||||
* @requires app
|
||||
* @requires composition
|
||||
* @requires activator
|
||||
* @requires viewEngine
|
||||
* @requires jquery
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'durandal/app', 'durandal/composition', 'durandal/activator', 'durandal/viewEngine', 'jquery', 'knockout'], function (system, app, composition, activator, viewEngine, $, ko) {
|
||||
var contexts = {},
|
||||
dialogCount = ko.observable(0),
|
||||
dialog;
|
||||
|
||||
/**
|
||||
* Models a message box's message, title and options.
|
||||
* @class MessageBox
|
||||
*/
|
||||
var MessageBox = function (message, title, options, autoclose, settings) {
|
||||
this.message = message;
|
||||
this.title = title || MessageBox.defaultTitle;
|
||||
this.options = options || MessageBox.defaultOptions;
|
||||
this.autoclose = autoclose || false;
|
||||
this.settings = $.extend({}, MessageBox.defaultSettings, settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects an option and closes the message box, returning the selected option through the dialog system's promise.
|
||||
* @method selectOption
|
||||
* @param {string} dialogResult The result to select.
|
||||
*/
|
||||
MessageBox.prototype.selectOption = function (dialogResult) {
|
||||
dialog.close(this, dialogResult);
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides the view to the composition system.
|
||||
* @method getView
|
||||
* @return {DOMElement} The view of the message box.
|
||||
*/
|
||||
MessageBox.prototype.getView = function () {
|
||||
return viewEngine.processMarkup(MessageBox.defaultViewMarkup);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures a custom view to use when displaying message boxes.
|
||||
* @method setViewUrl
|
||||
* @param {string} viewUrl The view url relative to the base url which the view locator will use to find the message box's view.
|
||||
* @static
|
||||
*/
|
||||
MessageBox.setViewUrl = function (viewUrl) {
|
||||
delete MessageBox.prototype.getView;
|
||||
MessageBox.prototype.viewUrl = viewUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* The title to be used for the message box if one is not provided.
|
||||
* @property {string} defaultTitle
|
||||
* @default Application
|
||||
* @static
|
||||
*/
|
||||
MessageBox.defaultTitle = app.title || 'Application';
|
||||
|
||||
/**
|
||||
* The options to display in the message box if none are specified.
|
||||
* @property {string[]} defaultOptions
|
||||
* @default ['Ok']
|
||||
* @static
|
||||
*/
|
||||
MessageBox.defaultOptions = ['Ok'];
|
||||
|
||||
|
||||
MessageBox.defaultSettings = { buttonClass: "btn btn-default", primaryButtonClass: "btn-primary autofocus", secondaryButtonClass: "", "class": "modal-content messageBox", style: null };
|
||||
|
||||
/**
|
||||
* Sets the classes and styles used throughout the message box markup.
|
||||
* @method setDefaults
|
||||
* @param {object} settings A settings object containing the following optional properties: buttonClass, primaryButtonClass, secondaryButtonClass, class, style.
|
||||
*/
|
||||
MessageBox.setDefaults = function (settings) {
|
||||
$.extend(MessageBox.defaultSettings, settings);
|
||||
};
|
||||
|
||||
MessageBox.prototype.getButtonClass = function ($index) {
|
||||
var c = "";
|
||||
if (this.settings) {
|
||||
if (this.settings.buttonClass) {
|
||||
c = this.settings.buttonClass;
|
||||
}
|
||||
if ($index() === 0 && this.settings.primaryButtonClass) {
|
||||
if (c.length > 0) {
|
||||
c += " ";
|
||||
}
|
||||
c += this.settings.primaryButtonClass;
|
||||
}
|
||||
if ($index() > 0 && this.settings.secondaryButtonClass) {
|
||||
if (c.length > 0) {
|
||||
c += " ";
|
||||
}
|
||||
c += this.settings.secondaryButtonClass;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
MessageBox.prototype.getClass = function () {
|
||||
if (this.settings) {
|
||||
return this.settings["class"];
|
||||
}
|
||||
return "messageBox";
|
||||
};
|
||||
|
||||
MessageBox.prototype.getStyle = function () {
|
||||
if (this.settings) {
|
||||
return this.settings.style;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
MessageBox.prototype.getButtonText = function (stringOrObject) {
|
||||
var t = $.type(stringOrObject);
|
||||
if (t === "string") {
|
||||
return stringOrObject;
|
||||
}
|
||||
else if (t === "object") {
|
||||
if ($.type(stringOrObject.text) === "string") {
|
||||
return stringOrObject.text;
|
||||
} else {
|
||||
system.error('The object for a MessageBox button does not have a text property that is a string.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
system.error('Object for a MessageBox button is not a string or object but ' + t + '.');
|
||||
return null;
|
||||
};
|
||||
|
||||
MessageBox.prototype.getButtonValue = function (stringOrObject) {
|
||||
var t = $.type(stringOrObject);
|
||||
if (t === "string") {
|
||||
return stringOrObject;
|
||||
}
|
||||
else if (t === "object") {
|
||||
if ($.type(stringOrObject.text) === "undefined") {
|
||||
system.error('The object for a MessageBox button does not have a value property defined.');
|
||||
return null;
|
||||
} else {
|
||||
return stringOrObject.value;
|
||||
}
|
||||
}
|
||||
system.error('Object for a MessageBox button is not a string or object but ' + t + '.');
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* The markup for the message box's view.
|
||||
* @property {string} defaultViewMarkup
|
||||
* @static
|
||||
*/
|
||||
MessageBox.defaultViewMarkup = [
|
||||
'<div data-view="plugins/messageBox" data-bind="css: getClass(), style: getStyle()">',
|
||||
'<div class="modal-header">',
|
||||
'<h3 data-bind="html: title"></h3>',
|
||||
'</div>',
|
||||
'<div class="modal-body">',
|
||||
'<p class="message" data-bind="html: message"></p>',
|
||||
'</div>',
|
||||
'<div class="modal-footer">',
|
||||
'<!-- ko foreach: options -->',
|
||||
'<button data-bind="click: function () { $parent.selectOption($parent.getButtonValue($data)); }, text: $parent.getButtonText($data), css: $parent.getButtonClass($index)"></button>',
|
||||
'<!-- /ko -->',
|
||||
'<div style="clear:both;"></div>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('\n');
|
||||
|
||||
function ensureDialogInstance(objOrModuleId) {
|
||||
return system.defer(function (dfd) {
|
||||
if (system.isString(objOrModuleId)) {
|
||||
system.acquire(objOrModuleId).then(function (module) {
|
||||
dfd.resolve(system.resolveObject(module));
|
||||
}).fail(function (err) {
|
||||
system.error('Failed to load dialog module (' + objOrModuleId + '). Details: ' + err.message);
|
||||
});
|
||||
} else {
|
||||
dfd.resolve(objOrModuleId);
|
||||
}
|
||||
}).promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DialogModule
|
||||
* @static
|
||||
*/
|
||||
dialog = {
|
||||
/**
|
||||
* The constructor function used to create message boxes.
|
||||
* @property {MessageBox} MessageBox
|
||||
*/
|
||||
MessageBox: MessageBox,
|
||||
/**
|
||||
* The css zIndex that the last dialog was displayed at.
|
||||
* @property {number} currentZIndex
|
||||
*/
|
||||
currentZIndex: 1050,
|
||||
/**
|
||||
* Gets the next css zIndex at which a dialog should be displayed.
|
||||
* @method getNextZIndex
|
||||
* @return {number} The next usable zIndex.
|
||||
*/
|
||||
getNextZIndex: function () {
|
||||
return ++this.currentZIndex;
|
||||
},
|
||||
/**
|
||||
* Determines whether or not there are any dialogs open.
|
||||
* @method isOpen
|
||||
* @return {boolean} True if a dialog is open. false otherwise.
|
||||
*/
|
||||
isOpen: ko.computed(function() {
|
||||
return dialogCount() > 0;
|
||||
}),
|
||||
/**
|
||||
* Gets the dialog context by name or returns the default context if no name is specified.
|
||||
* @method getContext
|
||||
* @param {string} [name] The name of the context to retrieve.
|
||||
* @return {DialogContext} True context.
|
||||
*/
|
||||
getContext: function (name) {
|
||||
return contexts[name || 'default'];
|
||||
},
|
||||
/**
|
||||
* Adds (or replaces) a dialog context.
|
||||
* @method addContext
|
||||
* @param {string} name The name of the context to add.
|
||||
* @param {DialogContext} dialogContext The context to add.
|
||||
*/
|
||||
addContext: function (name, dialogContext) {
|
||||
dialogContext.name = name;
|
||||
contexts[name] = dialogContext;
|
||||
|
||||
var helperName = 'show' + name.substr(0, 1).toUpperCase() + name.substr(1);
|
||||
this[helperName] = function (obj, activationData) {
|
||||
return this.show(obj, activationData, name);
|
||||
};
|
||||
},
|
||||
createCompositionSettings: function (obj, dialogContext) {
|
||||
var settings = {
|
||||
model: obj,
|
||||
activate: false,
|
||||
transition: false
|
||||
};
|
||||
|
||||
if (dialogContext.binding) {
|
||||
settings.binding = dialogContext.binding;
|
||||
}
|
||||
|
||||
if (dialogContext.attached) {
|
||||
settings.attached = dialogContext.attached;
|
||||
}
|
||||
|
||||
if (dialogContext.compositionComplete) {
|
||||
settings.compositionComplete = dialogContext.compositionComplete;
|
||||
}
|
||||
|
||||
return settings;
|
||||
},
|
||||
/**
|
||||
* Gets the dialog model that is associated with the specified object.
|
||||
* @method getDialog
|
||||
* @param {object} obj The object for whom to retrieve the dialog.
|
||||
* @return {Dialog} The dialog model.
|
||||
*/
|
||||
getDialog: function (obj) {
|
||||
if (obj) {
|
||||
return obj.__dialog__;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
/**
|
||||
* Closes the dialog associated with the specified object.
|
||||
* @method close
|
||||
* @param {object} obj The object whose dialog should be closed.
|
||||
* @param {object} results* The results to return back to the dialog caller after closing.
|
||||
*/
|
||||
close: function (obj) {
|
||||
var theDialog = this.getDialog(obj);
|
||||
if (theDialog) {
|
||||
var rest = Array.prototype.slice.call(arguments, 1);
|
||||
theDialog.close.apply(theDialog, rest);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Shows a dialog.
|
||||
* @method show
|
||||
* @param {object|string} obj The object (or moduleId) to display as a dialog.
|
||||
* @param {object} [activationData] The data that should be passed to the object upon activation.
|
||||
* @param {string} [context] The name of the dialog context to use. Uses the default context if none is specified.
|
||||
* @return {Promise} A promise that resolves when the dialog is closed and returns any data passed at the time of closing.
|
||||
*/
|
||||
show: function (obj, activationData, context) {
|
||||
var that = this;
|
||||
var dialogContext = contexts[context || 'default'];
|
||||
|
||||
return system.defer(function (dfd) {
|
||||
ensureDialogInstance(obj).then(function (instance) {
|
||||
var dialogActivator = activator.create();
|
||||
|
||||
dialogActivator.activateItem(instance, activationData).then(function (success) {
|
||||
if (success) {
|
||||
var theDialog = instance.__dialog__ = {
|
||||
owner: instance,
|
||||
context: dialogContext,
|
||||
activator: dialogActivator,
|
||||
close: function () {
|
||||
var args = arguments;
|
||||
dialogActivator.deactivateItem(instance, true).then(function (closeSuccess) {
|
||||
if (closeSuccess) {
|
||||
dialogCount(dialogCount() - 1);
|
||||
dialogContext.removeHost(theDialog);
|
||||
delete instance.__dialog__;
|
||||
|
||||
if (args.length === 0) {
|
||||
dfd.resolve();
|
||||
} else if (args.length === 1) {
|
||||
dfd.resolve(args[0]);
|
||||
} else {
|
||||
dfd.resolve.apply(dfd, args);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
theDialog.settings = that.createCompositionSettings(instance, dialogContext);
|
||||
dialogContext.addHost(theDialog);
|
||||
|
||||
dialogCount(dialogCount() + 1);
|
||||
composition.compose(theDialog.host, theDialog.settings);
|
||||
} else {
|
||||
dfd.resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}).promise();
|
||||
},
|
||||
/**
|
||||
* Shows a message box.
|
||||
* @method showMessage
|
||||
* @param {string} message The message to display in the dialog.
|
||||
* @param {string} [title] The title message.
|
||||
* @param {string[]} [options] The options to provide to the user.
|
||||
* @param {boolean} [autoclose] Automatically close the the message box when clicking outside?
|
||||
* @param {Object} [settings] Custom settings for this instance of the messsage box, used to change classes and styles.
|
||||
* @return {Promise} A promise that resolves when the message box is closed and returns the selected option.
|
||||
*/
|
||||
showMessage: function (message, title, options, autoclose, settings) {
|
||||
if (system.isString(this.MessageBox)) {
|
||||
return dialog.show(this.MessageBox, [
|
||||
message,
|
||||
title || MessageBox.defaultTitle,
|
||||
options || MessageBox.defaultOptions,
|
||||
autoclose || false,
|
||||
settings || {}
|
||||
]);
|
||||
}
|
||||
|
||||
return dialog.show(new this.MessageBox(message, title, options, autoclose, settings));
|
||||
},
|
||||
/**
|
||||
* Installs this module into Durandal; called by the framework. Adds `app.showDialog` and `app.showMessage` convenience methods.
|
||||
* @method install
|
||||
* @param {object} [config] Add a `messageBox` property to supply a custom message box constructor. Add a `messageBoxView` property to supply custom view markup for the built-in message box. You can also use messageBoxViewUrl to specify the view url.
|
||||
*/
|
||||
install: function (config) {
|
||||
app.showDialog = function (obj, activationData, context) {
|
||||
return dialog.show(obj, activationData, context);
|
||||
};
|
||||
|
||||
app.closeDialog = function () {
|
||||
return dialog.close.apply(dialog, arguments);
|
||||
};
|
||||
|
||||
app.showMessage = function (message, title, options, autoclose, settings) {
|
||||
return dialog.showMessage(message, title, options, autoclose, settings);
|
||||
};
|
||||
|
||||
if (config.messageBox) {
|
||||
dialog.MessageBox = config.messageBox;
|
||||
}
|
||||
|
||||
if (config.messageBoxView) {
|
||||
dialog.MessageBox.prototype.getView = function () {
|
||||
return viewEngine.processMarkup(config.messageBoxView);
|
||||
};
|
||||
}
|
||||
|
||||
if (config.messageBoxViewUrl) {
|
||||
dialog.MessageBox.setViewUrl(config.messageBoxViewUrl);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class DialogContext
|
||||
*/
|
||||
dialog.addContext('default', {
|
||||
blockoutOpacity: 0.2,
|
||||
removeDelay: 200,
|
||||
/**
|
||||
* In this function, you are expected to add a DOM element to the tree which will serve as the "host" for the modal's composed view. You must add a property called host to the modalWindow object which references the dom element. It is this host which is passed to the composition module.
|
||||
* @method addHost
|
||||
* @param {Dialog} theDialog The dialog model.
|
||||
*/
|
||||
addHost: function (theDialog) {
|
||||
var body = $('body');
|
||||
var blockout = $('<div class="modalBlockout"></div>')
|
||||
.css({ 'z-index': dialog.getNextZIndex(), 'opacity': this.blockoutOpacity })
|
||||
.appendTo(body);
|
||||
|
||||
var host = $('<div class="modalHost"></div>')
|
||||
.css({ 'z-index': dialog.getNextZIndex() })
|
||||
.appendTo(body);
|
||||
|
||||
theDialog.host = host.get(0);
|
||||
theDialog.blockout = blockout.get(0);
|
||||
|
||||
if (!dialog.isOpen()) {
|
||||
theDialog.oldBodyMarginRight = body.css("margin-right");
|
||||
theDialog.oldInlineMarginRight = body.get(0).style.marginRight;
|
||||
|
||||
var html = $("html");
|
||||
var oldBodyOuterWidth = body.outerWidth(true);
|
||||
var oldScrollTop = html.scrollTop();
|
||||
$("html").css("overflow-y", "hidden");
|
||||
var newBodyOuterWidth = $("body").outerWidth(true);
|
||||
body.css("margin-right", (newBodyOuterWidth - oldBodyOuterWidth + parseInt(theDialog.oldBodyMarginRight, 10)) + "px");
|
||||
html.scrollTop(oldScrollTop); // necessary for Firefox
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This function is expected to remove any DOM machinery associated with the specified dialog and do any other necessary cleanup.
|
||||
* @method removeHost
|
||||
* @param {Dialog} theDialog The dialog model.
|
||||
*/
|
||||
removeHost: function (theDialog) {
|
||||
$(theDialog.host).css('opacity', 0);
|
||||
$(theDialog.blockout).css('opacity', 0);
|
||||
|
||||
setTimeout(function () {
|
||||
ko.removeNode(theDialog.host);
|
||||
ko.removeNode(theDialog.blockout);
|
||||
}, this.removeDelay);
|
||||
|
||||
if (!dialog.isOpen()) {
|
||||
var html = $("html");
|
||||
var oldScrollTop = html.scrollTop(); // necessary for Firefox.
|
||||
html.css("overflow-y", "").scrollTop(oldScrollTop);
|
||||
|
||||
if (theDialog.oldInlineMarginRight) {
|
||||
$("body").css("margin-right", theDialog.oldBodyMarginRight);
|
||||
} else {
|
||||
$("body").css("margin-right", '');
|
||||
}
|
||||
}
|
||||
},
|
||||
attached: function (view) {
|
||||
//To prevent flickering in IE8, we set visibility to hidden first, and later restore it
|
||||
$(view).css("visibility", "hidden");
|
||||
},
|
||||
/**
|
||||
* This function is called after the modal is fully composed into the DOM, allowing your implementation to do any final modifications, such as positioning or animation. You can obtain the original dialog object by using `getDialog` on context.model.
|
||||
* @method compositionComplete
|
||||
* @param {DOMElement} child The dialog view.
|
||||
* @param {DOMElement} parent The parent view.
|
||||
* @param {object} context The composition context.
|
||||
*/
|
||||
compositionComplete: function (child, parent, context) {
|
||||
var theDialog = dialog.getDialog(context.model);
|
||||
var $child = $(child);
|
||||
var loadables = $child.find("img").filter(function () {
|
||||
//Remove images with known width and height
|
||||
var $this = $(this);
|
||||
return !(this.style.width && this.style.height) && !($this.attr("width") && $this.attr("height"));
|
||||
});
|
||||
|
||||
$child.data("predefinedWidth", $child.get(0).style.width);
|
||||
|
||||
var setDialogPosition = function (childView, objDialog) {
|
||||
//Setting a short timeout is need in IE8, otherwise we could do this straight away
|
||||
setTimeout(function () {
|
||||
var $childView = $(childView);
|
||||
|
||||
objDialog.context.reposition(childView);
|
||||
|
||||
$(objDialog.host).css('opacity', 1);
|
||||
$childView.css("visibility", "visible");
|
||||
|
||||
$childView.find('.autofocus').first().focus();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
setDialogPosition(child, theDialog);
|
||||
loadables.load(function () {
|
||||
setDialogPosition(child, theDialog);
|
||||
});
|
||||
|
||||
if ($child.hasClass('autoclose') || context.model.autoclose) {
|
||||
$(theDialog.blockout).click(function () {
|
||||
theDialog.close();
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This function is called to reposition the model view.
|
||||
* @method reposition
|
||||
* @param {DOMElement} view The dialog view.
|
||||
*/
|
||||
reposition: function (view) {
|
||||
var $view = $(view),
|
||||
$window = $(window);
|
||||
|
||||
//We will clear and then set width for dialogs without width set
|
||||
if (!$view.data("predefinedWidth")) {
|
||||
$view.css({ width: '' }); //Reset width
|
||||
}
|
||||
var width = $view.outerWidth(false),
|
||||
height = $view.outerHeight(false),
|
||||
windowHeight = $window.height() - 10, //leave at least 10 pixels free
|
||||
windowWidth = $window.width() - 10, //leave at least 10 pixels free
|
||||
constrainedHeight = Math.min(height, windowHeight),
|
||||
constrainedWidth = Math.min(width, windowWidth);
|
||||
|
||||
$view.css({
|
||||
'margin-top': (-constrainedHeight / 2).toString() + 'px',
|
||||
'margin-left': (-constrainedWidth / 2).toString() + 'px'
|
||||
});
|
||||
|
||||
if (height > windowHeight) {
|
||||
$view.css("overflow-y", "auto").outerHeight(windowHeight);
|
||||
} else {
|
||||
$view.css({
|
||||
"overflow-y": "",
|
||||
"height": ""
|
||||
});
|
||||
}
|
||||
|
||||
if (width > windowWidth) {
|
||||
$view.css("overflow-x", "auto").outerWidth(windowWidth);
|
||||
} else {
|
||||
$view.css("overflow-x", "");
|
||||
|
||||
if (!$view.data("predefinedWidth")) {
|
||||
//Ensure the correct width after margin-left has been set
|
||||
$view.outerWidth(constrainedWidth);
|
||||
} else {
|
||||
$view.css("width", $view.data("predefinedWidth"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
});
|
||||
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* This module is based on Backbone's core history support. It abstracts away the low level details of working with browser history and url changes in order to provide a solid foundation for a router.
|
||||
* @module history
|
||||
* @requires system
|
||||
* @requires jquery
|
||||
*/
|
||||
define(['durandal/system', 'jquery'], function (system, $) {
|
||||
// Cached regex for stripping a leading hash/slash and trailing space.
|
||||
var routeStripper = /^[#\/]|\s+$/g;
|
||||
|
||||
// Cached regex for stripping leading and trailing slashes.
|
||||
var rootStripper = /^\/+|\/+$/g;
|
||||
|
||||
// Cached regex for detecting MSIE.
|
||||
var isExplorer = /msie [\w.]+/;
|
||||
|
||||
// Cached regex for removing a trailing slash.
|
||||
var trailingSlash = /\/$/;
|
||||
|
||||
// Update the hash location, either replacing the current entry, or adding
|
||||
// a new one to the browser history.
|
||||
function updateHash(location, fragment, replace) {
|
||||
if (replace) {
|
||||
var href = location.href.replace(/(javascript:|#).*$/, '');
|
||||
|
||||
if (history.history.replaceState) {
|
||||
history.history.replaceState({}, document.title, href + '#' + fragment); // using history.replaceState instead of location.replace to work around chrom bug
|
||||
} else {
|
||||
location.replace(href + '#' + fragment);
|
||||
}
|
||||
} else {
|
||||
// Some browsers require that `hash` contains a leading #.
|
||||
location.hash = '#' + fragment;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class HistoryModule
|
||||
* @static
|
||||
*/
|
||||
var history = {
|
||||
/**
|
||||
* The setTimeout interval used when the browser does not support hash change events.
|
||||
* @property {string} interval
|
||||
* @default 50
|
||||
*/
|
||||
interval: 50,
|
||||
/**
|
||||
* Indicates whether or not the history module is actively tracking history.
|
||||
* @property {string} active
|
||||
*/
|
||||
active: false
|
||||
};
|
||||
|
||||
// Ensure that `History` can be used outside of the browser.
|
||||
if (typeof window !== 'undefined') {
|
||||
history.location = window.location;
|
||||
history.history = window.history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the true hash value. Cannot use location.hash directly due to a bug in Firefox where location.hash will always be decoded.
|
||||
* @method getHash
|
||||
* @param {string} [window] The optional window instance
|
||||
* @return {string} The hash.
|
||||
*/
|
||||
history.getHash = function(window) {
|
||||
var match = (window || history).location.href.match(/#(.*)$/);
|
||||
return match ? match[1] : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the cross-browser normalized URL fragment, either from the URL, the hash, or the override.
|
||||
* @method getFragment
|
||||
* @param {string} fragment The fragment.
|
||||
* @param {boolean} forcePushState Should we force push state?
|
||||
* @return {string} he fragment.
|
||||
*/
|
||||
history.getFragment = function(fragment, forcePushState) {
|
||||
if (fragment == null) {
|
||||
if (history._hasPushState || !history._wantsHashChange || forcePushState) {
|
||||
fragment = history.location.pathname + history.location.search;
|
||||
var root = history.root.replace(trailingSlash, '');
|
||||
if (!fragment.indexOf(root)) {
|
||||
fragment = fragment.substr(root.length);
|
||||
}
|
||||
} else {
|
||||
fragment = history.getHash();
|
||||
}
|
||||
}
|
||||
|
||||
return fragment.replace(routeStripper, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* Activate the hash change handling, returning `true` if the current URL matches an existing route, and `false` otherwise.
|
||||
* @method activate
|
||||
* @param {HistoryOptions} options.
|
||||
* @return {boolean|undefined} Returns true/false from loading the url unless the silent option was selected.
|
||||
*/
|
||||
history.activate = function(options) {
|
||||
if (history.active) {
|
||||
system.error("History has already been activated.");
|
||||
}
|
||||
|
||||
history.active = true;
|
||||
|
||||
// Figure out the initial configuration. Do we need an iframe?
|
||||
// Is pushState desired ... is it available?
|
||||
history.options = system.extend({}, { root: '/' }, history.options, options);
|
||||
history.root = history.options.root;
|
||||
history._wantsHashChange = history.options.hashChange !== false;
|
||||
history._wantsPushState = !!history.options.pushState;
|
||||
history._hasPushState = !!(history.options.pushState && history.history && history.history.pushState);
|
||||
|
||||
var fragment = history.getFragment();
|
||||
var docMode = document.documentMode;
|
||||
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
|
||||
|
||||
// Normalize root to always include a leading and trailing slash.
|
||||
history.root = ('/' + history.root + '/').replace(rootStripper, '/');
|
||||
|
||||
if (oldIE && history._wantsHashChange) {
|
||||
history.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
|
||||
history.navigate(fragment, false);
|
||||
}
|
||||
|
||||
// Depending on whether we're using pushState or hashes, and whether
|
||||
// 'onhashchange' is supported, determine how we check the URL state.
|
||||
if (history._hasPushState) {
|
||||
$(window).on('popstate', history.checkUrl);
|
||||
} else if (history._wantsHashChange && ('onhashchange' in window) && !oldIE) {
|
||||
$(window).on('hashchange', history.checkUrl);
|
||||
} else if (history._wantsHashChange) {
|
||||
history._checkUrlInterval = setInterval(history.checkUrl, history.interval);
|
||||
}
|
||||
|
||||
// Determine if we need to change the base url, for a pushState link
|
||||
// opened by a non-pushState browser.
|
||||
history.fragment = fragment;
|
||||
var loc = history.location;
|
||||
var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === history.root;
|
||||
|
||||
// Transition from hashChange to pushState or vice versa if both are requested.
|
||||
if (history._wantsHashChange && history._wantsPushState) {
|
||||
// If we've started off with a route from a `pushState`-enabled
|
||||
// browser, but we're currently in a browser that doesn't support it...
|
||||
if (!history._hasPushState && !atRoot) {
|
||||
history.fragment = history.getFragment(null, true);
|
||||
history.location.replace(history.root + history.location.search + '#' + history.fragment);
|
||||
// Return immediately as browser will do redirect to new url
|
||||
return true;
|
||||
|
||||
// Or if we've started out with a hash-based route, but we're currently
|
||||
// in a browser where it could be `pushState`-based instead...
|
||||
} else if (history._hasPushState && atRoot && loc.hash) {
|
||||
this.fragment = history.getHash().replace(routeStripper, '');
|
||||
this.history.replaceState({}, document.title, history.root + history.fragment + loc.search);
|
||||
}
|
||||
}
|
||||
|
||||
if (!history.options.silent) {
|
||||
return history.loadUrl(options.startRoute);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable history, perhaps temporarily. Not useful in a real app, but possibly useful for unit testing Routers.
|
||||
* @method deactivate
|
||||
*/
|
||||
history.deactivate = function() {
|
||||
$(window).off('popstate', history.checkUrl).off('hashchange', history.checkUrl);
|
||||
clearInterval(history._checkUrlInterval);
|
||||
history.active = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks the current URL to see if it has changed, and if it has, calls `loadUrl`, normalizing across the hidden iframe.
|
||||
* @method checkUrl
|
||||
* @return {boolean} Returns true/false from loading the url.
|
||||
*/
|
||||
history.checkUrl = function() {
|
||||
var current = history.getFragment();
|
||||
if (current === history.fragment && history.iframe) {
|
||||
current = history.getFragment(history.getHash(history.iframe));
|
||||
}
|
||||
|
||||
if (current === history.fragment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (history.iframe) {
|
||||
history.navigate(current, false);
|
||||
}
|
||||
|
||||
history.loadUrl();
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to load the current URL fragment. A pass-through to options.routeHandler.
|
||||
* @method loadUrl
|
||||
* @return {boolean} Returns true/false from the route handler.
|
||||
*/
|
||||
history.loadUrl = function(fragmentOverride) {
|
||||
var fragment = history.fragment = history.getFragment(fragmentOverride);
|
||||
|
||||
return history.options.routeHandler ?
|
||||
history.options.routeHandler(fragment) :
|
||||
false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Save a fragment into the hash history, or replace the URL state if the
|
||||
* 'replace' option is passed. You are responsible for properly URL-encoding
|
||||
* the fragment in advance.
|
||||
* The options object can contain `trigger: false` if you wish to not have the
|
||||
* route callback be fired, or `replace: true`, if
|
||||
* you wish to modify the current URL without adding an entry to the history.
|
||||
* @method navigate
|
||||
* @param {string} fragment The url fragment to navigate to.
|
||||
* @param {object|boolean} options An options object with optional trigger and replace flags. You can also pass a boolean directly to set the trigger option. Trigger is `true` by default.
|
||||
* @return {boolean} Returns true/false from loading the url.
|
||||
*/
|
||||
history.navigate = function(fragment, options) {
|
||||
if (!history.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(options === undefined) {
|
||||
options = {
|
||||
trigger: true
|
||||
};
|
||||
}else if(system.isBoolean(options)) {
|
||||
options = {
|
||||
trigger: options
|
||||
};
|
||||
}
|
||||
|
||||
fragment = history.getFragment(fragment || '');
|
||||
|
||||
if (history.fragment === fragment) {
|
||||
return;
|
||||
}
|
||||
|
||||
history.fragment = fragment;
|
||||
|
||||
var url = history.root + fragment;
|
||||
|
||||
// Don't include a trailing slash on the root.
|
||||
if(fragment === '' && url !== '/') {
|
||||
url = url.slice(0, -1);
|
||||
}
|
||||
|
||||
// If pushState is available, we use it to set the fragment as a real URL.
|
||||
if (history._hasPushState) {
|
||||
history.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
|
||||
|
||||
// If hash changes haven't been explicitly disabled, update the hash
|
||||
// fragment to store history.
|
||||
} else if (history._wantsHashChange) {
|
||||
updateHash(history.location, fragment, options.replace);
|
||||
|
||||
if (history.iframe && (fragment !== history.getFragment(history.getHash(history.iframe)))) {
|
||||
// Opening and closing the iframe tricks IE7 and earlier to push a
|
||||
// history entry on hash-tag change. When replace is true, we don't
|
||||
// want history.
|
||||
if (!options.replace) {
|
||||
history.iframe.document.open().close();
|
||||
}
|
||||
|
||||
updateHash(history.iframe.location, fragment, options.replace);
|
||||
}
|
||||
|
||||
// If you've told us that you explicitly don't want fallback hashchange-
|
||||
// based history, then `navigate` becomes a page refresh.
|
||||
} else {
|
||||
return history.location.assign(url);
|
||||
}
|
||||
|
||||
if (options.trigger) {
|
||||
return history.loadUrl(fragment);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Navigates back in the browser history.
|
||||
* @method navigateBack
|
||||
*/
|
||||
history.navigateBack = function() {
|
||||
history.history.back();
|
||||
};
|
||||
|
||||
/**
|
||||
* @class HistoryOptions
|
||||
* @static
|
||||
*/
|
||||
|
||||
/**
|
||||
* The function that will be called back when the fragment changes.
|
||||
* @property {function} routeHandler
|
||||
*/
|
||||
|
||||
/**
|
||||
* The url root used to extract the fragment when using push state.
|
||||
* @property {string} root
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use hash change when present.
|
||||
* @property {boolean} hashChange
|
||||
* @default true
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use push state when present.
|
||||
* @property {boolean} pushState
|
||||
* @default false
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prevents loading of the current url when activating history.
|
||||
* @property {boolean} silent
|
||||
* @default false
|
||||
*/
|
||||
|
||||
return history;
|
||||
});
|
||||
126
demo/filebrowser-durandal-widget/lib/durandal/js/plugins/http.js
Normal file
126
demo/filebrowser-durandal-widget/lib/durandal/js/plugins/http.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* Enables common http request scenarios.
|
||||
* @module http
|
||||
* @requires jquery
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['jquery', 'knockout'], function ($, ko) {
|
||||
/**
|
||||
* @class HTTPModule
|
||||
* @static
|
||||
*/
|
||||
return {
|
||||
/**
|
||||
* The name of the callback parameter to inject into jsonp requests by default.
|
||||
* @property {string} callbackParam
|
||||
* @default callback
|
||||
*/
|
||||
callbackParam: 'callback',
|
||||
/**
|
||||
* Converts the data to JSON.
|
||||
* @method toJSON
|
||||
* @param {object} data The data to convert to JSON.
|
||||
* @return {string} JSON.
|
||||
*/
|
||||
toJSON: function(data) {
|
||||
return ko.toJSON(data);
|
||||
},
|
||||
/**
|
||||
* Makes an HTTP GET request.
|
||||
* @method get
|
||||
* @param {string} url The url to send the get request to.
|
||||
* @param {object} [query] An optional key/value object to transform into query string parameters.
|
||||
* @param {object} [headers] The data to add to the request header. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @return {Promise} A promise of the get response data.
|
||||
*/
|
||||
get: function (url, query, headers) {
|
||||
return $.ajax(url, { data: query, headers: ko.toJS(headers) });
|
||||
},
|
||||
/**
|
||||
* Makes an JSONP request.
|
||||
* @method jsonp
|
||||
* @param {string} url The url to send the get request to.
|
||||
* @param {object} [query] An optional key/value object to transform into query string parameters.
|
||||
* @param {string} [callbackParam] The name of the callback parameter the api expects (overrides the default callbackParam).
|
||||
* @param {object} [headers] The data to add to the request header. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @return {Promise} A promise of the response data.
|
||||
*/
|
||||
jsonp: function (url, query, callbackParam, headers) {
|
||||
if (url.indexOf('=?') == -1) {
|
||||
callbackParam = callbackParam || this.callbackParam;
|
||||
|
||||
if (url.indexOf('?') == -1) {
|
||||
url += '?';
|
||||
} else {
|
||||
url += '&';
|
||||
}
|
||||
|
||||
url += callbackParam + '=?';
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
url: url,
|
||||
dataType: 'jsonp',
|
||||
data: query,
|
||||
headers: ko.toJS(headers)
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Makes an HTTP PUT request.
|
||||
* @method put
|
||||
* @param {string} url The url to send the put request to.
|
||||
* @param {object} data The data to put. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @param {object} [headers] The data to add to the request header. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @return {Promise} A promise of the response data.
|
||||
*/
|
||||
put:function(url, data, headers) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
data: this.toJSON(data),
|
||||
type: 'PUT',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
headers: ko.toJS(headers)
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Makes an HTTP POST request.
|
||||
* @method post
|
||||
* @param {string} url The url to send the post request to.
|
||||
* @param {object} data The data to post. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @param {object} [headers] The data to add to the request header. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @return {Promise} A promise of the response data.
|
||||
*/
|
||||
post: function (url, data, headers) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
data: this.toJSON(data),
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
headers: ko.toJS(headers)
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Makes an HTTP DELETE request.
|
||||
* @method remove
|
||||
* @param {string} url The url to send the delete request to.
|
||||
* @param {object} [query] An optional key/value object to transform into query string parameters.
|
||||
* @param {object} [headers] The data to add to the request header. It will be converted to JSON. If the data contains Knockout observables, they will be converted into normal properties before serialization.
|
||||
* @return {Promise} A promise of the get response data.
|
||||
*/
|
||||
remove:function(url, query, headers) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
data: query,
|
||||
type: 'DELETE',
|
||||
headers: ko.toJS(headers)
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,410 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* Enables automatic observability of plain javascript object for ES5 compatible browsers. Also, converts promise properties into observables that are updated when the promise resolves.
|
||||
* @module observable
|
||||
* @requires system
|
||||
* @requires binder
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'durandal/binder', 'knockout'], function(system, binder, ko) {
|
||||
var observableModule,
|
||||
toString = Object.prototype.toString,
|
||||
nonObservableTypes = ['[object Function]', '[object String]', '[object Boolean]', '[object Number]', '[object Date]', '[object RegExp]'],
|
||||
observableArrayMethods = ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'],
|
||||
arrayMethods = ['pop', 'reverse', 'sort', 'shift', 'slice'],
|
||||
additiveArrayFunctions = ['push', 'unshift'],
|
||||
es5Functions = ['filter', 'map', 'reduce', 'reduceRight', 'forEach', 'every', 'some'],
|
||||
arrayProto = Array.prototype,
|
||||
observableArrayFunctions = ko.observableArray.fn,
|
||||
logConversion = false,
|
||||
changeDetectionMethod = undefined,
|
||||
skipPromises = false,
|
||||
shouldIgnorePropertyName;
|
||||
|
||||
/**
|
||||
* You can call observable(obj, propertyName) to get the observable function for the specified property on the object.
|
||||
* @class ObservableModule
|
||||
*/
|
||||
|
||||
if (!('getPropertyDescriptor' in Object)) {
|
||||
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
||||
var getPrototypeOf = Object.getPrototypeOf;
|
||||
|
||||
Object['getPropertyDescriptor'] = function(o, name) {
|
||||
var proto = o, descriptor;
|
||||
|
||||
while(proto && !(descriptor = getOwnPropertyDescriptor(proto, name))) {
|
||||
proto = getPrototypeOf(proto);
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
function defaultShouldIgnorePropertyName(propertyName){
|
||||
var first = propertyName[0];
|
||||
return first === '_' || first === '$' || (changeDetectionMethod && propertyName === changeDetectionMethod);
|
||||
}
|
||||
|
||||
function isNode(obj) {
|
||||
return !!(obj && obj.nodeType !== undefined && system.isNumber(obj.nodeType));
|
||||
}
|
||||
|
||||
function canConvertType(value) {
|
||||
if (!value || isNode(value) || value.ko === ko || value.jquery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = toString.call(value);
|
||||
|
||||
return nonObservableTypes.indexOf(type) == -1 && !(value === true || value === false);
|
||||
}
|
||||
|
||||
function createLookup(obj) {
|
||||
var value = {};
|
||||
|
||||
Object.defineProperty(obj, "__observable__", {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: value
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function makeObservableArray(original, observable, hasChanged) {
|
||||
var lookup = original.__observable__, notify = true;
|
||||
|
||||
if(lookup && lookup.__full__){
|
||||
return;
|
||||
}
|
||||
|
||||
lookup = lookup || createLookup(original);
|
||||
lookup.__full__ = true;
|
||||
|
||||
es5Functions.forEach(function (methodName) {
|
||||
observable[methodName] = function () {
|
||||
return arrayProto[methodName].apply(original, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
observableArrayMethods.forEach(function(methodName) {
|
||||
original[methodName] = function() {
|
||||
notify = false;
|
||||
var methodCallResult = observableArrayFunctions[methodName].apply(observable, arguments);
|
||||
notify = true;
|
||||
return methodCallResult;
|
||||
};
|
||||
});
|
||||
|
||||
arrayMethods.forEach(function(methodName) {
|
||||
original[methodName] = function() {
|
||||
if(notify){
|
||||
observable.valueWillMutate();
|
||||
}
|
||||
|
||||
var methodCallResult = arrayProto[methodName].apply(original, arguments);
|
||||
|
||||
if(notify){
|
||||
observable.valueHasMutated();
|
||||
}
|
||||
|
||||
return methodCallResult;
|
||||
};
|
||||
});
|
||||
|
||||
additiveArrayFunctions.forEach(function(methodName){
|
||||
original[methodName] = function() {
|
||||
for (var i = 0, len = arguments.length; i < len; i++) {
|
||||
convertObject(arguments[i], hasChanged);
|
||||
}
|
||||
|
||||
if(notify){
|
||||
observable.valueWillMutate();
|
||||
}
|
||||
|
||||
var methodCallResult = arrayProto[methodName].apply(original, arguments);
|
||||
|
||||
if(notify){
|
||||
observable.valueHasMutated();
|
||||
}
|
||||
|
||||
return methodCallResult;
|
||||
};
|
||||
});
|
||||
|
||||
original['splice'] = function() {
|
||||
for (var i = 2, len = arguments.length; i < len; i++) {
|
||||
convertObject(arguments[i], hasChanged);
|
||||
}
|
||||
|
||||
if(notify){
|
||||
observable.valueWillMutate();
|
||||
}
|
||||
|
||||
var methodCallResult = arrayProto['splice'].apply(original, arguments);
|
||||
|
||||
if(notify){
|
||||
observable.valueHasMutated();
|
||||
}
|
||||
|
||||
return methodCallResult;
|
||||
};
|
||||
|
||||
for (var i = 0, len = original.length; i < len; i++) {
|
||||
convertObject(original[i], hasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an entire object into an observable object by re-writing its attributes using ES5 getters and setters. Attributes beginning with '_' or '$' are ignored.
|
||||
* @method convertObject
|
||||
* @param {object} obj The target object to convert.
|
||||
*/
|
||||
function convertObject(obj, hasChanged) {
|
||||
var lookup, value;
|
||||
|
||||
if (changeDetectionMethod) {
|
||||
if(obj && obj[changeDetectionMethod]) {
|
||||
if (hasChanged) {
|
||||
hasChanged = hasChanged.slice(0);
|
||||
} else {
|
||||
hasChanged = [];
|
||||
}
|
||||
hasChanged.push(obj[changeDetectionMethod]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!canConvertType(obj)){
|
||||
return;
|
||||
}
|
||||
|
||||
lookup = obj.__observable__;
|
||||
|
||||
if(lookup && lookup.__full__){
|
||||
return;
|
||||
}
|
||||
|
||||
lookup = lookup || createLookup(obj);
|
||||
lookup.__full__ = true;
|
||||
|
||||
if (system.isArray(obj)) {
|
||||
var observable = ko.observableArray(obj);
|
||||
makeObservableArray(obj, observable, hasChanged);
|
||||
} else {
|
||||
for (var propertyName in obj) {
|
||||
if(shouldIgnorePropertyName(propertyName)){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!lookup[propertyName]) {
|
||||
var descriptor = Object.getPropertyDescriptor(obj, propertyName);
|
||||
if (descriptor && (descriptor.get || descriptor.set)) {
|
||||
defineProperty(obj, propertyName, {
|
||||
get:descriptor.get,
|
||||
set:descriptor.set
|
||||
});
|
||||
} else {
|
||||
value = obj[propertyName];
|
||||
|
||||
if(!system.isFunction(value)) {
|
||||
convertProperty(obj, propertyName, value, hasChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(logConversion) {
|
||||
system.log('Converted', obj);
|
||||
}
|
||||
}
|
||||
|
||||
function innerSetter(observable, newValue, isArray) {
|
||||
//if this was originally an observableArray, then always check to see if we need to add/replace the array methods (if newValue was an entirely new array)
|
||||
if (isArray) {
|
||||
if (!newValue) {
|
||||
//don't allow null, force to an empty array
|
||||
newValue = [];
|
||||
makeObservableArray(newValue, observable);
|
||||
}
|
||||
else if (!newValue.destroyAll) {
|
||||
makeObservableArray(newValue, observable);
|
||||
}
|
||||
} else {
|
||||
convertObject(newValue);
|
||||
}
|
||||
|
||||
//call the update to the observable after the array as been updated.
|
||||
observable(newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a normal property into an observable property using ES5 getters and setters.
|
||||
* @method convertProperty
|
||||
* @param {object} obj The target object on which the property to convert lives.
|
||||
* @param {string} propertyName The name of the property to convert.
|
||||
* @param {object} [original] The original value of the property. If not specified, it will be retrieved from the object.
|
||||
* @return {KnockoutObservable} The underlying observable.
|
||||
*/
|
||||
function convertProperty(obj, propertyName, original, hasChanged) {
|
||||
var observable,
|
||||
isArray,
|
||||
lookup = obj.__observable__ || createLookup(obj);
|
||||
|
||||
if(original === undefined){
|
||||
original = obj[propertyName];
|
||||
}
|
||||
|
||||
if (system.isArray(original)) {
|
||||
observable = ko.observableArray(original);
|
||||
makeObservableArray(original, observable, hasChanged);
|
||||
isArray = true;
|
||||
} else if (typeof original == "function") {
|
||||
if(ko.isObservable(original)){
|
||||
observable = original;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
} else if(!skipPromises && system.isPromise(original)) {
|
||||
observable = ko.observable();
|
||||
|
||||
original.then(function (result) {
|
||||
if(system.isArray(result)) {
|
||||
var oa = ko.observableArray(result);
|
||||
makeObservableArray(result, oa, hasChanged);
|
||||
result = oa;
|
||||
}
|
||||
|
||||
observable(result);
|
||||
});
|
||||
} else {
|
||||
observable = ko.observable(original);
|
||||
convertObject(original, hasChanged);
|
||||
}
|
||||
|
||||
if (hasChanged && hasChanged.length > 0) {
|
||||
hasChanged.forEach(function (func) {
|
||||
if (system.isArray(original)) {
|
||||
observable.subscribe(function (arrayChanges) {
|
||||
func(obj, propertyName, null, arrayChanges);
|
||||
}, null, "arrayChange");
|
||||
} else {
|
||||
observable.subscribe(function (newValue) {
|
||||
func(obj, propertyName, newValue, null);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, propertyName, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: observable,
|
||||
set: ko.isWriteableObservable(observable) ? (function (newValue) {
|
||||
if (newValue && system.isPromise(newValue) && !skipPromises) {
|
||||
newValue.then(function (result) {
|
||||
innerSetter(observable, result, system.isArray(result));
|
||||
});
|
||||
} else {
|
||||
innerSetter(observable, newValue, isArray);
|
||||
}
|
||||
}) : undefined
|
||||
});
|
||||
|
||||
lookup[propertyName] = observable;
|
||||
return observable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a computed property using ES5 getters and setters.
|
||||
* @method defineProperty
|
||||
* @param {object} obj The target object on which to create the property.
|
||||
* @param {string} propertyName The name of the property to define.
|
||||
* @param {function|object} evaluatorOrOptions The Knockout computed function or computed options object.
|
||||
* @return {KnockoutObservable} The underlying computed observable.
|
||||
*/
|
||||
function defineProperty(obj, propertyName, evaluatorOrOptions) {
|
||||
var computedOptions = { owner: obj, deferEvaluation: true },
|
||||
computed;
|
||||
|
||||
if (typeof evaluatorOrOptions === 'function') {
|
||||
computedOptions.read = evaluatorOrOptions;
|
||||
} else {
|
||||
if ('value' in evaluatorOrOptions) {
|
||||
system.error('For defineProperty, you must not specify a "value" for the property. You must provide a "get" function.');
|
||||
}
|
||||
|
||||
if (typeof evaluatorOrOptions.get !== 'function' && typeof evaluatorOrOptions.read !== 'function') {
|
||||
system.error('For defineProperty, the third parameter must be either an evaluator function, or an options object containing a function called "get".');
|
||||
}
|
||||
|
||||
computedOptions.read = evaluatorOrOptions.get || evaluatorOrOptions.read;
|
||||
computedOptions.write = evaluatorOrOptions.set || evaluatorOrOptions.write;
|
||||
}
|
||||
|
||||
computed = ko.computed(computedOptions);
|
||||
obj[propertyName] = computed;
|
||||
|
||||
return convertProperty(obj, propertyName, computed);
|
||||
}
|
||||
|
||||
observableModule = function(obj, propertyName){
|
||||
var lookup, observable, value;
|
||||
|
||||
if (!obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
lookup = obj.__observable__;
|
||||
if(lookup){
|
||||
observable = lookup[propertyName];
|
||||
if(observable){
|
||||
return observable;
|
||||
}
|
||||
}
|
||||
|
||||
value = obj[propertyName];
|
||||
|
||||
if(ko.isObservable(value)){
|
||||
return value;
|
||||
}
|
||||
|
||||
return convertProperty(obj, propertyName, value);
|
||||
};
|
||||
|
||||
observableModule.defineProperty = defineProperty;
|
||||
observableModule.convertProperty = convertProperty;
|
||||
observableModule.convertObject = convertObject;
|
||||
|
||||
/**
|
||||
* Installs the plugin into the view model binder's `beforeBind` hook so that objects are automatically converted before being bound.
|
||||
* @method install
|
||||
*/
|
||||
observableModule.install = function(options) {
|
||||
var original = binder.binding;
|
||||
|
||||
binder.binding = function(obj, view, instruction) {
|
||||
if(instruction.applyBindings && !instruction.skipConversion){
|
||||
convertObject(obj);
|
||||
}
|
||||
|
||||
original(obj, view);
|
||||
};
|
||||
|
||||
logConversion = options.logConversion;
|
||||
if (options.changeDetection) {
|
||||
changeDetectionMethod = options.changeDetection;
|
||||
}
|
||||
|
||||
skipPromises = options.skipPromises;
|
||||
shouldIgnorePropertyName = options.shouldIgnorePropertyName || defaultShouldIgnorePropertyName;
|
||||
};
|
||||
|
||||
return observableModule;
|
||||
});
|
||||
1130
demo/filebrowser-durandal-widget/lib/durandal/js/plugins/router.js
Normal file
1130
demo/filebrowser-durandal-widget/lib/durandal/js/plugins/router.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* Serializes and deserializes data to/from JSON.
|
||||
* @module serializer
|
||||
* @requires system
|
||||
*/
|
||||
define(['durandal/system'], function(system) {
|
||||
/**
|
||||
* @class SerializerModule
|
||||
* @static
|
||||
*/
|
||||
return {
|
||||
/**
|
||||
* The name of the attribute that the serializer should use to identify an object's type.
|
||||
* @property {string} typeAttribute
|
||||
* @default type
|
||||
*/
|
||||
typeAttribute: 'type',
|
||||
/**
|
||||
* The amount of space to use for indentation when writing out JSON.
|
||||
* @property {string|number} space
|
||||
* @default undefined
|
||||
*/
|
||||
space:undefined,
|
||||
/**
|
||||
* The default replacer function used during serialization. By default properties starting with '_' or '$' are removed from the serialized object.
|
||||
* @method replacer
|
||||
* @param {string} key The object key to check.
|
||||
* @param {object} value The object value to check.
|
||||
* @return {object} The value to serialize.
|
||||
*/
|
||||
replacer: function(key, value) {
|
||||
if(key){
|
||||
var first = key[0];
|
||||
if(first === '_' || first === '$'){
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* Serializes the object.
|
||||
* @method serialize
|
||||
* @param {object} object The object to serialize.
|
||||
* @param {object} [settings] Settings can specify a replacer or space to override the serializer defaults.
|
||||
* @return {string} The JSON string.
|
||||
*/
|
||||
serialize: function(object, settings) {
|
||||
settings = (settings === undefined) ? {} : settings;
|
||||
|
||||
if(system.isString(settings) || system.isNumber(settings)) {
|
||||
settings = { space: settings };
|
||||
}
|
||||
|
||||
return JSON.stringify(object, settings.replacer || this.replacer, settings.space || this.space);
|
||||
},
|
||||
/**
|
||||
* Gets the type id for an object instance, using the configured `typeAttribute`.
|
||||
* @method getTypeId
|
||||
* @param {object} object The object to serialize.
|
||||
* @return {string} The type.
|
||||
*/
|
||||
getTypeId: function(object) {
|
||||
if (object) {
|
||||
return object[this.typeAttribute];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
/**
|
||||
* Maps type ids to object constructor functions. Keys are type ids and values are functions.
|
||||
* @property {object} typeMap.
|
||||
*/
|
||||
typeMap: {},
|
||||
/**
|
||||
* Adds a type id/constructor function mampping to the `typeMap`.
|
||||
* @method registerType
|
||||
* @param {string} typeId The type id.
|
||||
* @param {function} constructor The constructor.
|
||||
*/
|
||||
registerType: function() {
|
||||
var first = arguments[0];
|
||||
|
||||
if (arguments.length == 1) {
|
||||
var id = first[this.typeAttribute] || system.getModuleId(first);
|
||||
this.typeMap[id] = first;
|
||||
} else {
|
||||
this.typeMap[first] = arguments[1];
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The default reviver function used during deserialization. By default is detects type properties on objects and uses them to re-construct the correct object using the provided constructor mapping.
|
||||
* @method reviver
|
||||
* @param {string} key The attribute key.
|
||||
* @param {object} value The object value associated with the key.
|
||||
* @param {function} getTypeId A custom function used to get the type id from a value.
|
||||
* @param {object} getConstructor A custom function used to get the constructor function associated with a type id.
|
||||
* @return {object} The value.
|
||||
*/
|
||||
reviver: function(key, value, getTypeId, getConstructor) {
|
||||
var typeId = getTypeId(value);
|
||||
if (typeId) {
|
||||
var ctor = getConstructor(typeId);
|
||||
if (ctor) {
|
||||
if (ctor.fromJSON) {
|
||||
return ctor.fromJSON(value);
|
||||
}
|
||||
|
||||
return new ctor(value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* Deserialize the JSON.
|
||||
* @method deserialize
|
||||
* @param {string} text The JSON string.
|
||||
* @param {object} [settings] Settings can specify a reviver, getTypeId function or getConstructor function.
|
||||
* @return {object} The deserialized object.
|
||||
*/
|
||||
deserialize: function(text, settings) {
|
||||
var that = this;
|
||||
settings = settings || {};
|
||||
|
||||
var getTypeId = settings.getTypeId || function(object) { return that.getTypeId(object); };
|
||||
var getConstructor = settings.getConstructor || function(id) { return that.typeMap[id]; };
|
||||
var reviver = settings.reviver || function(key, value) { return that.reviver(key, value, getTypeId, getConstructor); };
|
||||
|
||||
return JSON.parse(text, reviver);
|
||||
},
|
||||
/**
|
||||
* Clone the object.
|
||||
* @method clone
|
||||
* @param {object} obj The object to clone.
|
||||
* @param {object} [settings] Settings can specify any of the options allowed by the serialize or deserialize methods.
|
||||
* @return {object} The new clone.
|
||||
*/
|
||||
clone:function(obj, settings) {
|
||||
return this.deserialize(this.serialize(obj, settings), settings);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* Layers the widget sugar on top of the composition system.
|
||||
* @module widget
|
||||
* @requires system
|
||||
* @requires composition
|
||||
* @requires jquery
|
||||
* @requires knockout
|
||||
*/
|
||||
define(['durandal/system', 'durandal/composition', 'jquery', 'knockout'], function(system, composition, $, ko) {
|
||||
var kindModuleMaps = {},
|
||||
kindViewMaps = {},
|
||||
bindableSettings = ['model', 'view', 'kind'],
|
||||
widgetDataKey = 'durandal-widget-data';
|
||||
|
||||
function extractParts(element, settings){
|
||||
var data = ko.utils.domData.get(element, widgetDataKey);
|
||||
|
||||
if(!data){
|
||||
data = {
|
||||
parts:composition.cloneNodes(ko.virtualElements.childNodes(element))
|
||||
};
|
||||
|
||||
ko.virtualElements.emptyNode(element);
|
||||
ko.utils.domData.set(element, widgetDataKey, data);
|
||||
}
|
||||
|
||||
settings.parts = data.parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class WidgetModule
|
||||
* @static
|
||||
*/
|
||||
var widget = {
|
||||
getSettings: function(valueAccessor) {
|
||||
var settings = ko.utils.unwrapObservable(valueAccessor()) || {};
|
||||
|
||||
if (system.isString(settings)) {
|
||||
return { kind: settings };
|
||||
}
|
||||
|
||||
for (var attrName in settings) {
|
||||
if (ko.utils.arrayIndexOf(bindableSettings, attrName) != -1) {
|
||||
settings[attrName] = ko.utils.unwrapObservable(settings[attrName]);
|
||||
} else {
|
||||
settings[attrName] = settings[attrName];
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
},
|
||||
/**
|
||||
* Creates a ko binding handler for the specified kind.
|
||||
* @method registerKind
|
||||
* @param {string} kind The kind to create a custom binding handler for.
|
||||
*/
|
||||
registerKind: function(kind) {
|
||||
ko.bindingHandlers[kind] = {
|
||||
init: function() {
|
||||
return { controlsDescendantBindings: true };
|
||||
},
|
||||
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||
var settings = widget.getSettings(valueAccessor);
|
||||
settings.kind = kind;
|
||||
extractParts(element, settings);
|
||||
widget.create(element, settings, bindingContext, true);
|
||||
}
|
||||
};
|
||||
|
||||
ko.virtualElements.allowedBindings[kind] = true;
|
||||
composition.composeBindings.push(kind + ':');
|
||||
},
|
||||
/**
|
||||
* Maps views and module to the kind identifier if a non-standard pattern is desired.
|
||||
* @method mapKind
|
||||
* @param {string} kind The kind name.
|
||||
* @param {string} [viewId] The unconventional view id to map the kind to.
|
||||
* @param {string} [moduleId] The unconventional module id to map the kind to.
|
||||
*/
|
||||
mapKind: function(kind, viewId, moduleId) {
|
||||
if (viewId) {
|
||||
kindViewMaps[kind] = viewId;
|
||||
}
|
||||
|
||||
if (moduleId) {
|
||||
kindModuleMaps[kind] = moduleId;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Maps a kind name to it's module id. First it looks up a custom mapped kind, then falls back to `convertKindToModulePath`.
|
||||
* @method mapKindToModuleId
|
||||
* @param {string} kind The kind name.
|
||||
* @return {string} The module id.
|
||||
*/
|
||||
mapKindToModuleId: function(kind) {
|
||||
return kindModuleMaps[kind] || widget.convertKindToModulePath(kind);
|
||||
},
|
||||
/**
|
||||
* Converts a kind name to it's module path. Used to conventionally map kinds who aren't explicitly mapped through `mapKind`.
|
||||
* @method convertKindToModulePath
|
||||
* @param {string} kind The kind name.
|
||||
* @return {string} The module path.
|
||||
*/
|
||||
convertKindToModulePath: function(kind) {
|
||||
return 'widgets/' + kind + '/viewmodel';
|
||||
},
|
||||
/**
|
||||
* Maps a kind name to it's view id. First it looks up a custom mapped kind, then falls back to `convertKindToViewPath`.
|
||||
* @method mapKindToViewId
|
||||
* @param {string} kind The kind name.
|
||||
* @return {string} The view id.
|
||||
*/
|
||||
mapKindToViewId: function(kind) {
|
||||
return kindViewMaps[kind] || widget.convertKindToViewPath(kind);
|
||||
},
|
||||
/**
|
||||
* Converts a kind name to it's view id. Used to conventionally map kinds who aren't explicitly mapped through `mapKind`.
|
||||
* @method convertKindToViewPath
|
||||
* @param {string} kind The kind name.
|
||||
* @return {string} The view id.
|
||||
*/
|
||||
convertKindToViewPath: function(kind) {
|
||||
return 'widgets/' + kind + '/view';
|
||||
},
|
||||
createCompositionSettings: function(element, settings) {
|
||||
if (!settings.model) {
|
||||
settings.model = this.mapKindToModuleId(settings.kind);
|
||||
}
|
||||
|
||||
if (!settings.view) {
|
||||
settings.view = this.mapKindToViewId(settings.kind);
|
||||
}
|
||||
|
||||
settings.preserveContext = true;
|
||||
settings.activate = true;
|
||||
settings.activationData = settings;
|
||||
settings.mode = 'templated';
|
||||
|
||||
return settings;
|
||||
},
|
||||
/**
|
||||
* Creates a widget.
|
||||
* @method create
|
||||
* @param {DOMElement} element The DOMElement or knockout virtual element that serves as the target element for the widget.
|
||||
* @param {object} settings The widget settings.
|
||||
* @param {object} [bindingContext] The current binding context.
|
||||
*/
|
||||
create: function(element, settings, bindingContext, fromBinding) {
|
||||
if(!fromBinding){
|
||||
settings = widget.getSettings(function() { return settings; }, element);
|
||||
}
|
||||
|
||||
var compositionSettings = widget.createCompositionSettings(element, settings);
|
||||
|
||||
composition.compose(element, compositionSettings, bindingContext);
|
||||
},
|
||||
/**
|
||||
* Installs the widget module by adding the widget binding handler and optionally registering kinds.
|
||||
* @method install
|
||||
* @param {object} config The module config. Add a `kinds` array with the names of widgets to automatically register. You can also specify a `bindingName` if you wish to use another name for the widget binding, such as "control" for example.
|
||||
*/
|
||||
install:function(config){
|
||||
config.bindingName = config.bindingName || 'widget';
|
||||
|
||||
if(config.kinds){
|
||||
var toRegister = config.kinds;
|
||||
|
||||
for(var i = 0; i < toRegister.length; i++){
|
||||
widget.registerKind(toRegister[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ko.bindingHandlers[config.bindingName] = {
|
||||
init: function() {
|
||||
return { controlsDescendantBindings: true };
|
||||
},
|
||||
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||
var settings = widget.getSettings(valueAccessor);
|
||||
extractParts(element, settings);
|
||||
widget.create(element, settings, bindingContext, true);
|
||||
}
|
||||
};
|
||||
|
||||
composition.composeBindings.push(config.bindingName + ':');
|
||||
ko.virtualElements.allowedBindings[config.bindingName] = true;
|
||||
}
|
||||
};
|
||||
|
||||
return widget;
|
||||
});
|
||||
455
demo/filebrowser-durandal-widget/lib/durandal/js/system.js
Normal file
455
demo/filebrowser-durandal-widget/lib/durandal/js/system.js
Normal file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The system module encapsulates the most basic features used by other modules.
|
||||
* @module system
|
||||
* @requires require
|
||||
* @requires jquery
|
||||
*/
|
||||
define(['require', 'jquery'], function(require, $) {
|
||||
var isDebugging = false,
|
||||
nativeKeys = Object.keys,
|
||||
hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
toString = Object.prototype.toString,
|
||||
system,
|
||||
treatAsIE8 = false,
|
||||
nativeIsArray = Array.isArray,
|
||||
slice = Array.prototype.slice;
|
||||
|
||||
//polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
|
||||
if (!String.prototype.trim) {
|
||||
String.prototype.trim = function () {
|
||||
return this.replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
}
|
||||
|
||||
//see http://patik.com/blog/complete-cross-browser-console-log/
|
||||
// Tell IE9 to use its built-in console
|
||||
if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log == 'object') {
|
||||
try {
|
||||
['log', 'info', 'warn', 'error', 'assert', 'dir', 'clear', 'profile', 'profileEnd']
|
||||
.forEach(function(method) {
|
||||
console[method] = this.call(console[method], console);
|
||||
}, Function.prototype.bind);
|
||||
} catch (ex) {
|
||||
treatAsIE8 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// callback for dojo's loader
|
||||
// note: if you wish to use Durandal with dojo's AMD loader,
|
||||
// currently you must fork the dojo source with the following
|
||||
// dojo/dojo.js, line 1187, the last line of the finishExec() function:
|
||||
// (add) signal("moduleLoaded", [module.result, module.mid]);
|
||||
// an enhancement request has been submitted to dojo to make this
|
||||
// a permanent change. To view the status of this request, visit:
|
||||
// http://bugs.dojotoolkit.org/ticket/16727
|
||||
|
||||
if (require.on) {
|
||||
require.on("moduleLoaded", function(module, mid) {
|
||||
system.setModuleId(module, mid);
|
||||
});
|
||||
}
|
||||
|
||||
// callback for require.js loader
|
||||
if (typeof requirejs !== 'undefined') {
|
||||
requirejs.onResourceLoad = function(context, map, depArray) {
|
||||
system.setModuleId(context.defined[map.id], map.id);
|
||||
};
|
||||
}
|
||||
|
||||
var noop = function() { };
|
||||
|
||||
var log = function() {
|
||||
try {
|
||||
// Modern browsers
|
||||
if (typeof console != 'undefined' && typeof console.log == 'function') {
|
||||
// Opera 11
|
||||
if (window.opera) {
|
||||
var i = 0;
|
||||
while (i < arguments.length) {
|
||||
console.log('Item ' + (i + 1) + ': ' + arguments[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// All other modern browsers
|
||||
else if ((slice.call(arguments)).length == 1 && typeof slice.call(arguments)[0] == 'string') {
|
||||
console.log((slice.call(arguments)).toString());
|
||||
} else {
|
||||
console.log.apply(console, slice.call(arguments));
|
||||
}
|
||||
}
|
||||
// IE8
|
||||
else if ((!Function.prototype.bind || treatAsIE8) && typeof console != 'undefined' && typeof console.log == 'object') {
|
||||
Function.prototype.call.call(console.log, console, slice.call(arguments));
|
||||
}
|
||||
|
||||
// IE7 and lower, and other old browsers
|
||||
} catch (ignore) { }
|
||||
};
|
||||
|
||||
var logError = function(error, err) {
|
||||
var exception;
|
||||
|
||||
if(error instanceof Error){
|
||||
exception = error;
|
||||
} else {
|
||||
exception = new Error(error);
|
||||
}
|
||||
|
||||
exception.innerError = err;
|
||||
|
||||
//Report the error as an error, not as a log
|
||||
try {
|
||||
// Modern browsers (it's only a single item, no need for argument splitting as in log() above)
|
||||
if (typeof console != 'undefined' && typeof console.error == 'function') {
|
||||
console.error(exception);
|
||||
}
|
||||
// IE8
|
||||
else if ((!Function.prototype.bind || treatAsIE8) && typeof console != 'undefined' && typeof console.error == 'object') {
|
||||
Function.prototype.call.call(console.error, console, exception);
|
||||
}
|
||||
// IE7 and lower, and other old browsers
|
||||
} catch (ignore) { }
|
||||
|
||||
throw exception;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class SystemModule
|
||||
* @static
|
||||
*/
|
||||
system = {
|
||||
/**
|
||||
* Durandal's version.
|
||||
* @property {string} version
|
||||
*/
|
||||
version: "2.1.0",
|
||||
/**
|
||||
* A noop function.
|
||||
* @method noop
|
||||
*/
|
||||
noop: noop,
|
||||
/**
|
||||
* Gets the module id for the specified object.
|
||||
* @method getModuleId
|
||||
* @param {object} obj The object whose module id you wish to determine.
|
||||
* @return {string} The module id.
|
||||
*/
|
||||
getModuleId: function(obj) {
|
||||
if (!obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof obj == 'function' && obj.prototype) {
|
||||
return obj.prototype.__moduleId__;
|
||||
}
|
||||
|
||||
if (typeof obj == 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return obj.__moduleId__;
|
||||
},
|
||||
/**
|
||||
* Sets the module id for the specified object.
|
||||
* @method setModuleId
|
||||
* @param {object} obj The object whose module id you wish to set.
|
||||
* @param {string} id The id to set for the specified object.
|
||||
*/
|
||||
setModuleId: function(obj, id) {
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof obj == 'function' && obj.prototype) {
|
||||
obj.prototype.__moduleId__ = id;
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof obj == 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
obj.__moduleId__ = id;
|
||||
},
|
||||
/**
|
||||
* Resolves the default object instance for a module. If the module is an object, the module is returned. If the module is a function, that function is called with `new` and it's result is returned.
|
||||
* @method resolveObject
|
||||
* @param {object} module The module to use to get/create the default object for.
|
||||
* @return {object} The default object for the module.
|
||||
*/
|
||||
resolveObject: function(module) {
|
||||
if (system.isFunction(module)) {
|
||||
return new module();
|
||||
} else {
|
||||
return module;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Gets/Sets whether or not Durandal is in debug mode.
|
||||
* @method debug
|
||||
* @param {boolean} [enable] Turns on/off debugging.
|
||||
* @return {boolean} Whether or not Durandal is current debugging.
|
||||
*/
|
||||
debug: function(enable) {
|
||||
if (arguments.length == 1) {
|
||||
isDebugging = enable;
|
||||
if (isDebugging) {
|
||||
this.log = log;
|
||||
this.error = logError;
|
||||
this.log('Debug:Enabled');
|
||||
} else {
|
||||
this.log('Debug:Disabled');
|
||||
this.log = noop;
|
||||
this.error = noop;
|
||||
}
|
||||
}
|
||||
|
||||
return isDebugging;
|
||||
},
|
||||
/**
|
||||
* Logs data to the console. Pass any number of parameters to be logged. Log output is not processed if the framework is not running in debug mode.
|
||||
* @method log
|
||||
* @param {object} info* The objects to log.
|
||||
*/
|
||||
log: noop,
|
||||
/**
|
||||
* Logs an error.
|
||||
* @method error
|
||||
* @param {string|Error} obj The error to report.
|
||||
*/
|
||||
error: noop,
|
||||
/**
|
||||
* Asserts a condition by throwing an error if the condition fails.
|
||||
* @method assert
|
||||
* @param {boolean} condition The condition to check.
|
||||
* @param {string} message The message to report in the error if the condition check fails.
|
||||
*/
|
||||
assert: function (condition, message) {
|
||||
if (!condition) {
|
||||
system.error(new Error(message || 'Assert:Failed'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Creates a deferred object which can be used to create a promise. Optionally pass a function action to perform which will be passed an object used in resolving the promise.
|
||||
* @method defer
|
||||
* @param {function} [action] The action to defer. You will be passed the deferred object as a paramter.
|
||||
* @return {Deferred} The deferred object.
|
||||
*/
|
||||
defer: function(action) {
|
||||
return $.Deferred(action);
|
||||
},
|
||||
/**
|
||||
* Creates a simple V4 UUID. This should not be used as a PK in your database. It can be used to generate internal, unique ids. For a more robust solution see [node-uuid](https://github.com/broofa/node-uuid).
|
||||
* @method guid
|
||||
* @return {string} The guid.
|
||||
*/
|
||||
guid: function() {
|
||||
var d = new Date().getTime();
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d/16);
|
||||
return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Uses require.js to obtain a module. This function returns a promise which resolves with the module instance. You can pass more than one module id to this function or an array of ids. If more than one or an array is passed, then the promise will resolve with an array of module instances.
|
||||
* @method acquire
|
||||
* @param {string|string[]} moduleId The id(s) of the modules to load.
|
||||
* @return {Promise} A promise for the loaded module(s).
|
||||
*/
|
||||
acquire: function() {
|
||||
var modules,
|
||||
first = arguments[0],
|
||||
arrayRequest = false;
|
||||
|
||||
if(system.isArray(first)){
|
||||
modules = first;
|
||||
arrayRequest = true;
|
||||
}else{
|
||||
modules = slice.call(arguments, 0);
|
||||
}
|
||||
|
||||
return this.defer(function(dfd) {
|
||||
require(modules, function() {
|
||||
var args = arguments;
|
||||
setTimeout(function() {
|
||||
if(args.length > 1 || arrayRequest){
|
||||
dfd.resolve(slice.call(args, 0));
|
||||
}else{
|
||||
dfd.resolve(args[0]);
|
||||
}
|
||||
}, 1);
|
||||
}, function(err){
|
||||
dfd.reject(err);
|
||||
});
|
||||
}).promise();
|
||||
},
|
||||
/**
|
||||
* Extends the first object with the properties of the following objects.
|
||||
* @method extend
|
||||
* @param {object} obj The target object to extend.
|
||||
* @param {object} extension* Uses to extend the target object.
|
||||
*/
|
||||
extend: function(obj) {
|
||||
var rest = slice.call(arguments, 1);
|
||||
|
||||
for (var i = 0; i < rest.length; i++) {
|
||||
var source = rest[i];
|
||||
|
||||
if (source) {
|
||||
for (var prop in source) {
|
||||
obj[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
},
|
||||
/**
|
||||
* Uses a setTimeout to wait the specified milliseconds.
|
||||
* @method wait
|
||||
* @param {number} milliseconds The number of milliseconds to wait.
|
||||
* @return {Promise}
|
||||
*/
|
||||
wait: function(milliseconds) {
|
||||
return system.defer(function(dfd) {
|
||||
setTimeout(dfd.resolve, milliseconds);
|
||||
}).promise();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets all the owned keys of the specified object.
|
||||
* @method keys
|
||||
* @param {object} object The object whose owned keys should be returned.
|
||||
* @return {string[]} The keys.
|
||||
*/
|
||||
system.keys = nativeKeys || function(obj) {
|
||||
if (obj !== Object(obj)) {
|
||||
throw new TypeError('Invalid object');
|
||||
}
|
||||
|
||||
var keys = [];
|
||||
|
||||
for (var key in obj) {
|
||||
if (hasOwnProperty.call(obj, key)) {
|
||||
keys[keys.length] = key;
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is an html element.
|
||||
* @method isElement
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
system.isElement = function(obj) {
|
||||
return !!(obj && obj.nodeType === 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is an array.
|
||||
* @method isArray
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
system.isArray = nativeIsArray || function(obj) {
|
||||
return toString.call(obj) == '[object Array]';
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is...an object. ie. Not an array, string, etc.
|
||||
* @method isObject
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
system.isObject = function(obj) {
|
||||
return obj === Object(obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a boolean.
|
||||
* @method isBoolean
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
system.isBoolean = function(obj) {
|
||||
return typeof(obj) === "boolean";
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a promise.
|
||||
* @method isPromise
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
system.isPromise = function(obj) {
|
||||
return obj && system.isFunction(obj.then);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a function arguments object.
|
||||
* @method isArguments
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a function.
|
||||
* @method isFunction
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a string.
|
||||
* @method isString
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a number.
|
||||
* @method isNumber
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a date.
|
||||
* @method isDate
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if the specified object is a boolean.
|
||||
* @method isBoolean
|
||||
* @param {object} object The object to check.
|
||||
* @return {boolean} True if matches the type, false otherwise.
|
||||
*/
|
||||
|
||||
//isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
||||
var isChecks = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'];
|
||||
|
||||
function makeIsFunction(name) {
|
||||
var value = '[object ' + name + ']';
|
||||
system['is' + name] = function(obj) {
|
||||
return toString.call(obj) == value;
|
||||
};
|
||||
}
|
||||
|
||||
for (var i = 0; i < isChecks.length; i++) {
|
||||
makeIsFunction(isChecks[i]);
|
||||
}
|
||||
|
||||
return system;
|
||||
});
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The entrance transition module.
|
||||
* @module entrance
|
||||
* @requires system
|
||||
* @requires composition
|
||||
* @requires jquery
|
||||
*/
|
||||
define(['durandal/system', 'durandal/composition', 'jquery'], function(system, composition, $) {
|
||||
var fadeOutDuration = 100;
|
||||
var endValues = {
|
||||
left: '0px',
|
||||
opacity: 1
|
||||
};
|
||||
var clearValues = {
|
||||
left: '',
|
||||
top: '',
|
||||
right: '',
|
||||
bottom:'',
|
||||
position:'',
|
||||
opacity: ''
|
||||
};
|
||||
|
||||
var isIE = navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/MSIE/);
|
||||
|
||||
var animation = false,
|
||||
domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
|
||||
elm = document.createElement('div');
|
||||
|
||||
if(elm.style.animationName !== undefined) {
|
||||
animation = true;
|
||||
}
|
||||
|
||||
if(!animation) {
|
||||
for(var i = 0; i < domPrefixes.length; i++) {
|
||||
if(elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(animation) {
|
||||
if(isIE){
|
||||
system.log('Using CSS3/jQuery mixed animations.');
|
||||
}else{
|
||||
system.log('Using CSS3 animations.');
|
||||
}
|
||||
} else {
|
||||
system.log('Using jQuery animations.');
|
||||
}
|
||||
|
||||
function removeAnimationClasses(ele, fadeOnly){
|
||||
ele.classList.remove(fadeOnly ? 'entrance-in-fade' : 'entrance-in');
|
||||
ele.classList.remove('entrance-out');
|
||||
}
|
||||
|
||||
/**
|
||||
* @class EntranceModule
|
||||
* @constructor
|
||||
*/
|
||||
var entrance = function(context) {
|
||||
return system.defer(function(dfd) {
|
||||
function endTransition() {
|
||||
dfd.resolve();
|
||||
}
|
||||
|
||||
function scrollIfNeeded() {
|
||||
if (!context.keepScrollPosition) {
|
||||
$(document).scrollTop(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!context.child) {
|
||||
$(context.activeView).fadeOut(fadeOutDuration, endTransition);
|
||||
} else {
|
||||
var duration = context.duration || 500;
|
||||
var $child = $(context.child);
|
||||
var fadeOnly = !!context.fadeOnly;
|
||||
var startValues = {
|
||||
display: 'block',
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
left: fadeOnly || animation ? '0px' : '20px',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0
|
||||
};
|
||||
|
||||
function startTransition() {
|
||||
scrollIfNeeded();
|
||||
context.triggerAttach();
|
||||
|
||||
if (animation) {
|
||||
removeAnimationClasses(context.child, fadeOnly);
|
||||
context.child.classList.add(fadeOnly ? 'entrance-in-fade' : 'entrance-in');
|
||||
setTimeout(function () {
|
||||
removeAnimationClasses(context.child, fadeOnly);
|
||||
if(context.activeView){
|
||||
removeAnimationClasses(context.activeView, fadeOnly);
|
||||
}
|
||||
$child.css(clearValues);
|
||||
endTransition();
|
||||
}, duration);
|
||||
} else {
|
||||
$child.animate(endValues, {
|
||||
duration: duration,
|
||||
easing: 'swing',
|
||||
always: function() {
|
||||
$child.css(clearValues);
|
||||
endTransition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$child.css(startValues);
|
||||
|
||||
if(context.activeView) {
|
||||
if (animation && !isIE) {
|
||||
removeAnimationClasses(context.activeView, fadeOnly);
|
||||
context.activeView.classList.add('entrance-out');
|
||||
setTimeout(startTransition, fadeOutDuration);
|
||||
} else {
|
||||
$(context.activeView).fadeOut({ duration: fadeOutDuration, always: startTransition });
|
||||
}
|
||||
} else {
|
||||
startTransition();
|
||||
}
|
||||
}
|
||||
}).promise();
|
||||
};
|
||||
|
||||
return entrance;
|
||||
});
|
||||
194
demo/filebrowser-durandal-widget/lib/durandal/js/viewEngine.js
Normal file
194
demo/filebrowser-durandal-widget/lib/durandal/js/viewEngine.js
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The viewEngine module provides information to the viewLocator module which is used to locate the view's source file. The viewEngine also transforms a view id into a view instance.
|
||||
* @module viewEngine
|
||||
* @requires system
|
||||
* @requires jquery
|
||||
*/
|
||||
define(['durandal/system', 'jquery'], function (system, $) {
|
||||
var parseMarkup;
|
||||
|
||||
if ($.parseHTML) {
|
||||
parseMarkup = function (html) {
|
||||
return $.parseHTML(html);
|
||||
};
|
||||
} else {
|
||||
parseMarkup = function (html) {
|
||||
return $(html).get();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @class ViewEngineModule
|
||||
* @static
|
||||
*/
|
||||
return {
|
||||
cache:{},
|
||||
/**
|
||||
* The file extension that view source files are expected to have.
|
||||
* @property {string} viewExtension
|
||||
* @default .html
|
||||
*/
|
||||
viewExtension: '.html',
|
||||
/**
|
||||
* The name of the RequireJS loader plugin used by the viewLocator to obtain the view source. (Use requirejs to map the plugin's full path).
|
||||
* @property {string} viewPlugin
|
||||
* @default text
|
||||
*/
|
||||
viewPlugin: 'text',
|
||||
/**
|
||||
* Parameters passed to the RequireJS loader plugin used by the viewLocator to obtain the view source.
|
||||
* @property {string} viewPluginParameters
|
||||
* @default The empty string by default.
|
||||
*/
|
||||
viewPluginParameters: '',
|
||||
/**
|
||||
* Determines if the url is a url for a view, according to the view engine.
|
||||
* @method isViewUrl
|
||||
* @param {string} url The potential view url.
|
||||
* @return {boolean} True if the url is a view url, false otherwise.
|
||||
*/
|
||||
isViewUrl: function (url) {
|
||||
return url.indexOf(this.viewExtension, url.length - this.viewExtension.length) !== -1;
|
||||
},
|
||||
/**
|
||||
* Converts a view url into a view id.
|
||||
* @method convertViewUrlToViewId
|
||||
* @param {string} url The url to convert.
|
||||
* @return {string} The view id.
|
||||
*/
|
||||
convertViewUrlToViewId: function (url) {
|
||||
return url.substring(0, url.length - this.viewExtension.length);
|
||||
},
|
||||
/**
|
||||
* Converts a view id into a full RequireJS path.
|
||||
* @method convertViewIdToRequirePath
|
||||
* @param {string} viewId The view id to convert.
|
||||
* @return {string} The require path.
|
||||
*/
|
||||
convertViewIdToRequirePath: function (viewId) {
|
||||
var plugin = this.viewPlugin ? this.viewPlugin + '!' : '';
|
||||
return plugin + viewId + this.viewExtension + this.viewPluginParameters;
|
||||
},
|
||||
/**
|
||||
* Parses the view engine recognized markup and returns DOM elements.
|
||||
* @method parseMarkup
|
||||
* @param {string} markup The markup to parse.
|
||||
* @return {DOMElement[]} The elements.
|
||||
*/
|
||||
parseMarkup: parseMarkup,
|
||||
/**
|
||||
* Calls `parseMarkup` and then pipes the results through `ensureSingleElement`.
|
||||
* @method processMarkup
|
||||
* @param {string} markup The markup to process.
|
||||
* @return {DOMElement} The view.
|
||||
*/
|
||||
processMarkup: function (markup) {
|
||||
var allElements = this.parseMarkup(markup);
|
||||
return this.ensureSingleElement(allElements);
|
||||
},
|
||||
/**
|
||||
* Converts an array of elements into a single element. White space and comments are removed. If a single element does not remain, then the elements are wrapped.
|
||||
* @method ensureSingleElement
|
||||
* @param {DOMElement[]} allElements The elements.
|
||||
* @return {DOMElement} A single element.
|
||||
*/
|
||||
ensureSingleElement:function(allElements){
|
||||
if (allElements.length == 1) {
|
||||
return allElements[0];
|
||||
}
|
||||
|
||||
var withoutCommentsOrEmptyText = [];
|
||||
|
||||
for (var i = 0; i < allElements.length; i++) {
|
||||
var current = allElements[i];
|
||||
if (current.nodeType != 8) {
|
||||
if (current.nodeType == 3) {
|
||||
var result = /\S/.test(current.nodeValue);
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
withoutCommentsOrEmptyText.push(current);
|
||||
}
|
||||
}
|
||||
|
||||
if (withoutCommentsOrEmptyText.length > 1) {
|
||||
return $(withoutCommentsOrEmptyText).wrapAll('<div class="durandal-wrapper"></div>').parent().get(0);
|
||||
}
|
||||
|
||||
return withoutCommentsOrEmptyText[0];
|
||||
},
|
||||
/**
|
||||
* Gets the view associated with the id from the cache of parsed views.
|
||||
* @method tryGetViewFromCache
|
||||
* @param {string} id The view id to lookup in the cache.
|
||||
* @return {DOMElement|null} The cached view or null if it's not in the cache.
|
||||
*/
|
||||
tryGetViewFromCache:function(id) {
|
||||
return this.cache[id];
|
||||
},
|
||||
/**
|
||||
* Puts the view associated with the id into the cache of parsed views.
|
||||
* @method putViewInCache
|
||||
* @param {string} id The view id whose view should be cached.
|
||||
* @param {DOMElement} view The view to cache.
|
||||
*/
|
||||
putViewInCache: function (id, view) {
|
||||
this.cache[id] = view;
|
||||
},
|
||||
/**
|
||||
* Creates the view associated with the view id.
|
||||
* @method createView
|
||||
* @param {string} viewId The view id whose view should be created.
|
||||
* @return {Promise} A promise of the view.
|
||||
*/
|
||||
createView: function(viewId) {
|
||||
var that = this;
|
||||
var requirePath = this.convertViewIdToRequirePath(viewId);
|
||||
var existing = this.tryGetViewFromCache(requirePath);
|
||||
|
||||
if (existing) {
|
||||
return system.defer(function(dfd) {
|
||||
dfd.resolve(existing.cloneNode(true));
|
||||
}).promise();
|
||||
}
|
||||
|
||||
return system.defer(function(dfd) {
|
||||
system.acquire(requirePath).then(function(markup) {
|
||||
var element = that.processMarkup(markup);
|
||||
element.setAttribute('data-view', viewId);
|
||||
that.putViewInCache(requirePath, element);
|
||||
dfd.resolve(element.cloneNode(true));
|
||||
}).fail(function(err) {
|
||||
that.createFallbackView(viewId, requirePath, err).then(function(element) {
|
||||
element.setAttribute('data-view', viewId);
|
||||
that.cache[requirePath] = element;
|
||||
dfd.resolve(element.cloneNode(true));
|
||||
});
|
||||
});
|
||||
}).promise();
|
||||
},
|
||||
/**
|
||||
* Called when a view cannot be found to provide the opportunity to locate or generate a fallback view. Mainly used to ease development.
|
||||
* @method createFallbackView
|
||||
* @param {string} viewId The view id whose view should be created.
|
||||
* @param {string} requirePath The require path that was attempted.
|
||||
* @param {Error} requirePath The error that was returned from the attempt to locate the default view.
|
||||
* @return {Promise} A promise for the fallback view.
|
||||
*/
|
||||
createFallbackView: function (viewId, requirePath, err) {
|
||||
var that = this,
|
||||
message = 'View Not Found. Searched for "' + viewId + '" via path "' + requirePath + '".';
|
||||
|
||||
return system.defer(function(dfd) {
|
||||
dfd.resolve(that.processMarkup('<div class="durandal-view-404">' + message + '</div>'));
|
||||
}).promise();
|
||||
}
|
||||
};
|
||||
});
|
||||
158
demo/filebrowser-durandal-widget/lib/durandal/js/viewLocator.js
Normal file
158
demo/filebrowser-durandal-widget/lib/durandal/js/viewLocator.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
|
||||
* Available via the MIT license.
|
||||
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
|
||||
*/
|
||||
/**
|
||||
* The viewLocator module collaborates with the viewEngine module to provide views (literally dom sub-trees) to other parts of the framework as needed. The primary consumer of the viewLocator is the composition module.
|
||||
* @module viewLocator
|
||||
* @requires system
|
||||
* @requires viewEngine
|
||||
*/
|
||||
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
|
||||
function findInElements(nodes, url) {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var current = nodes[i];
|
||||
var existingUrl = current.getAttribute('data-view');
|
||||
if (existingUrl == url) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function escape(str) {
|
||||
return (str + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||
}
|
||||
|
||||
/**
|
||||
* @class ViewLocatorModule
|
||||
* @static
|
||||
*/
|
||||
return {
|
||||
/**
|
||||
* Allows you to set up a convention for mapping module folders to view folders. It is a convenience method that customizes `convertModuleIdToViewId` and `translateViewIdToArea` under the covers.
|
||||
* @method useConvention
|
||||
* @param {string} [modulesPath] A string to match in the path and replace with the viewsPath. If not specified, the match is 'viewmodels'.
|
||||
* @param {string} [viewsPath] The replacement for the modulesPath. If not specified, the replacement is 'views'.
|
||||
* @param {string} [areasPath] Partial views are mapped to the "views" folder if not specified. Use this parameter to change their location.
|
||||
*/
|
||||
useConvention: function(modulesPath, viewsPath, areasPath) {
|
||||
modulesPath = modulesPath || 'viewmodels';
|
||||
viewsPath = viewsPath || 'views';
|
||||
areasPath = areasPath || viewsPath;
|
||||
|
||||
var reg = new RegExp(escape(modulesPath), 'gi');
|
||||
|
||||
this.convertModuleIdToViewId = function (moduleId) {
|
||||
return moduleId.replace(reg, viewsPath);
|
||||
};
|
||||
|
||||
this.translateViewIdToArea = function (viewId, area) {
|
||||
if (!area || area == 'partial') {
|
||||
return areasPath + '/' + viewId;
|
||||
}
|
||||
|
||||
return areasPath + '/' + area + '/' + viewId;
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Maps an object instance to a view instance.
|
||||
* @method locateViewForObject
|
||||
* @param {object} obj The object to locate the view for.
|
||||
* @param {string} [area] The area to translate the view to.
|
||||
* @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
|
||||
* @return {Promise} A promise of the view.
|
||||
*/
|
||||
locateViewForObject: function(obj, area, elementsToSearch) {
|
||||
var view;
|
||||
|
||||
if (obj.getView) {
|
||||
view = obj.getView();
|
||||
if (view) {
|
||||
return this.locateView(view, area, elementsToSearch);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.viewUrl) {
|
||||
return this.locateView(obj.viewUrl, area, elementsToSearch);
|
||||
}
|
||||
|
||||
var id = system.getModuleId(obj);
|
||||
if (id) {
|
||||
return this.locateView(this.convertModuleIdToViewId(id), area, elementsToSearch);
|
||||
}
|
||||
|
||||
return this.locateView(this.determineFallbackViewId(obj), area, elementsToSearch);
|
||||
},
|
||||
/**
|
||||
* Converts a module id into a view id. By default the ids are the same.
|
||||
* @method convertModuleIdToViewId
|
||||
* @param {string} moduleId The module id.
|
||||
* @return {string} The view id.
|
||||
*/
|
||||
convertModuleIdToViewId: function(moduleId) {
|
||||
return moduleId;
|
||||
},
|
||||
/**
|
||||
* If no view id can be determined, this function is called to genreate one. By default it attempts to determine the object's type and use that.
|
||||
* @method determineFallbackViewId
|
||||
* @param {object} obj The object to determine the fallback id for.
|
||||
* @return {string} The view id.
|
||||
*/
|
||||
determineFallbackViewId: function (obj) {
|
||||
var funcNameRegex = /function (.{1,})\(/;
|
||||
var results = (funcNameRegex).exec((obj).constructor.toString());
|
||||
var typeName = (results && results.length > 1) ? results[1] : "";
|
||||
typeName = typeName.trim();
|
||||
return 'views/' + typeName;
|
||||
},
|
||||
/**
|
||||
* Takes a view id and translates it into a particular area. By default, no translation occurs.
|
||||
* @method translateViewIdToArea
|
||||
* @param {string} viewId The view id.
|
||||
* @param {string} area The area to translate the view to.
|
||||
* @return {string} The translated view id.
|
||||
*/
|
||||
translateViewIdToArea: function (viewId, area) {
|
||||
return viewId;
|
||||
},
|
||||
/**
|
||||
* Locates the specified view.
|
||||
* @method locateView
|
||||
* @param {string|DOMElement} viewOrUrlOrId A view, view url or view id to locate.
|
||||
* @param {string} [area] The area to translate the view to.
|
||||
* @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
|
||||
* @return {Promise} A promise of the view.
|
||||
*/
|
||||
locateView: function(viewOrUrlOrId, area, elementsToSearch) {
|
||||
if (typeof viewOrUrlOrId === 'string') {
|
||||
var viewId;
|
||||
|
||||
if (viewEngine.isViewUrl(viewOrUrlOrId)) {
|
||||
viewId = viewEngine.convertViewUrlToViewId(viewOrUrlOrId);
|
||||
} else {
|
||||
viewId = viewOrUrlOrId;
|
||||
}
|
||||
|
||||
if (area) {
|
||||
viewId = this.translateViewIdToArea(viewId, area);
|
||||
}
|
||||
|
||||
if (elementsToSearch) {
|
||||
var existing = findInElements(elementsToSearch, viewId);
|
||||
if (existing) {
|
||||
return system.defer(function(dfd) {
|
||||
dfd.resolve(existing);
|
||||
}).promise();
|
||||
}
|
||||
}
|
||||
|
||||
return viewEngine.createView(viewId);
|
||||
}
|
||||
|
||||
return system.defer(function(dfd) {
|
||||
dfd.resolve(viewOrUrlOrId);
|
||||
}).promise();
|
||||
}
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user