-
Notifications
You must be signed in to change notification settings - Fork 636
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new LibraryViewExtension project based on System.Windows.Controls…
….WebBrowser (#10241) * add new project add make core internals visible add duplicate files as required * build of libjswebview seems to work added package references * add resource files as links so dont duplicate them in repo * move to .net 4.7.2 to avoid package ref issues namespace adds dynamo use new namespace to reference resources that are embedded. * move back to 4.7 to see if we can get a build on self serve * log msbuild version in appyveyor * try using buildxml which restores a bit differently * image should not be under env - bah * revet back to nuget restore and build dynamo all * working branch in acad * icons from host registered streams supported now * this functions but startup time is slow. visibility fixed with startPage loads acad icons from resource streams that are registered using existing resource dict * add some stopwatch logging to resource loading remove superflous resourcestream handler add cache to main iconProvider entrypoint as first step in resolving icon data use string builder to construct base64 data strings * missed changes * semi working lazy load - small change made to librariejs to raise event whenever any item is clicked we also cache the original url before falling back to the default icon so we can load the real icon later. * some cleanup * update namespace to reflect what components are actually used update some todos update comments * drop back to packges config rename project, rename folder rename extension class * assembly and type names changed * remove value tuple use set version number to auto increment for now - keep at 1.0.x until we have a longer term plan for this project * get rid of value tuple * recase some methods comments add readme * address review comments
- Loading branch information
1 parent
bde6733
commit 35c9497
Showing
26 changed files
with
4,052 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
using System; | ||
using System.Threading; | ||
|
||
namespace Dynamo.LibraryViewExtensionMSWebBrowser | ||
{ | ||
/// <summary> | ||
/// A class that observes an event and notifies the clients with a transformed | ||
/// data as configured using reduce function. | ||
/// </summary> | ||
/// <typeparam name="TValue">Type of value passed when event is raised</typeparam> | ||
/// <typeparam name="TResult">Type of transformed data to notify to the client</typeparam> | ||
class EventObserver<TValue, TResult> : IDisposable | ||
{ | ||
private Timer throttler = null; | ||
private TimeSpan duetime; | ||
private bool accumulate = false; | ||
private bool disposed = false; | ||
|
||
private TResult result; | ||
private Func<TResult, TValue, TResult> reducer; | ||
private Action<TResult> observer; | ||
|
||
private object root = new object(); | ||
|
||
/// <summary> | ||
/// This event is fired when this object is disposed, clients can | ||
/// register a callback for Dispose. | ||
/// </summary> | ||
public event Action Disposed; | ||
|
||
/// <summary> | ||
/// Creates the event observer with a registered observe action and | ||
/// a reduce function for notification. | ||
/// </summary> | ||
/// <param name="observe">This action will be invoked to notify the client</param> | ||
/// <param name="reduce">This function will be invoked to reduce the | ||
/// actual event parameter together with last reduced value returned by this reducer.</param> | ||
public EventObserver(Action<TResult> observe, Func<TResult, TValue, TResult> reduce) | ||
{ | ||
observer = observe; | ||
reducer = reduce; | ||
accumulate = true; | ||
result = default(TResult); | ||
} | ||
|
||
/// <summary> | ||
/// Creates the event observer with a registered observe action and | ||
/// a reduce function for notification. | ||
/// </summary> | ||
/// <param name="observe">This action will be invoked to notify the client</param> | ||
/// <param name="transform">This function will be invoked to transform the | ||
/// actual event parameter.</param> | ||
public EventObserver(Action<TResult> observe, Func<TValue, TResult> transform) | ||
{ | ||
observer = observe; | ||
reducer = (x, y) => transform(y); | ||
result = default(TResult); | ||
} | ||
|
||
public static TValue Identity(TValue last, TValue current) | ||
{ | ||
return current; | ||
} | ||
|
||
/// <summary> | ||
/// The client need to register this method as an event callback for | ||
/// the event that needs to be observed. | ||
/// </summary> | ||
/// <param name="value">Event parameter passed</param> | ||
public void OnEvent(TValue value) | ||
{ | ||
if (disposed) return; | ||
|
||
lock (root) { result = reducer(result, value); } | ||
|
||
OnEventCore(value); | ||
} | ||
|
||
/// <summary> | ||
/// The core implementation for OnEvent, if throttle is active it will | ||
/// update the throttle timer with the due time, so that if no subsequent | ||
/// event is raised within the given throttle due time, the client will | ||
/// be notified. | ||
/// </summary> | ||
/// <param name="value"></param> | ||
protected virtual void OnEventCore(TValue value) | ||
{ | ||
if (throttler != null) | ||
{ | ||
throttler.Change(duetime, TimeSpan.FromMilliseconds(0)); | ||
} | ||
else | ||
{ | ||
Notify(this); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates an observer that throttle the stream of notification | ||
/// for a given duetime i.e. notification will be fired only if duetime | ||
/// is ellapsed from the last event trigger, if the event trigger is | ||
/// sooner then the observer will again wait for the given duetime | ||
/// to notify the client. | ||
/// </summary> | ||
/// <param name="duetime">Due time for throttle</param> | ||
/// <returns>The modified event Observer which throttle the events</returns> | ||
public EventObserver<TValue, TResult> Throttle(TimeSpan duetime) | ||
{ | ||
if (disposed) throw new ObjectDisposedException("EventObserver"); | ||
|
||
this.duetime = duetime; | ||
this.throttler = new Timer(Notify, this, Timeout.Infinite, Timeout.Infinite); | ||
//when throttled, reset the result after notification is fired. | ||
accumulate = false; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Notify the client, could be triggered from throttle timer or | ||
/// called directly by passing this object as state. | ||
/// </summary> | ||
/// <param name="state"></param> | ||
protected void Notify(object state) | ||
{ | ||
if (disposed) throw new ObjectDisposedException("EventObserver"); | ||
|
||
TResult r; | ||
lock (root) | ||
{ | ||
r = result; | ||
if (!accumulate) result = default(TResult); | ||
} | ||
observer(r); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if (!disposed) | ||
{ | ||
disposed = true; | ||
if (Disposed != null) { Disposed(); } | ||
Disposed = null; | ||
observer = null; | ||
reducer = null; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Implements IDisposable to invoke a given dispose action on Dispose(). | ||
/// </summary> | ||
class AnonymousDisposable : IDisposable | ||
{ | ||
private Action dispose; | ||
|
||
public AnonymousDisposable(Action dispose) | ||
{ | ||
this.dispose = dispose; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if(dispose != null) { dispose(); } | ||
dispose = null; | ||
} | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/LibraryViewExtensionMSWebBrowser/Handlers/DllResourceProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Dynamo.LibraryViewExtensionMSWebBrowser.Handlers | ||
{ | ||
/// <summary> | ||
/// A simple DllResourceProvider, which provides embedded resources from the dll. | ||
/// </summary> | ||
public class DllResourceProvider : ResourceProviderBase | ||
{ | ||
/// <summary> | ||
/// Creates a resource provider to get embedded resources from a given assembly. | ||
/// </summary> | ||
/// <param name="baseUrl">The base url from where the request is served.</param> | ||
/// <param name="rootNamespace">Root namespace for this resource provider.</param> | ||
/// <param name="assembly">Assembly from where the resources are to be obtained.</param> | ||
public DllResourceProvider(string baseUrl, string rootNamespace, Assembly assembly = null) | ||
{ | ||
RootNamespace = rootNamespace; | ||
BaseUrl = baseUrl; | ||
Assembly = assembly; | ||
if (Assembly == null) | ||
Assembly = Assembly.GetExecutingAssembly(); | ||
} | ||
|
||
/// <summary> | ||
/// Root namespace for this resource provider. For an example, if this provider | ||
/// serves resources at "Dynamo.LibraryUI.Web.Xxxx" (where "Xxxx" is the actual | ||
/// name of the resource), then root namespace would be "Dynamo.LibraryUI.Web". | ||
/// </summary> | ||
public string RootNamespace { get; private set; } | ||
|
||
/// <summary> | ||
/// The base url from where the request is served. For example, if this provider | ||
/// serves requests at http://localhost/dist/v0.0.1/Xxxx (where "Xxxx" is the name | ||
/// of the request), then the base url is "http://localhost/dist/v0.0.1". | ||
/// </summary> | ||
public string BaseUrl { get; private set; } | ||
|
||
/// <summary> | ||
/// Assembly from where the resources are to be obtained. | ||
/// </summary> | ||
public Assembly Assembly { get; private set; } | ||
|
||
/// <summary> | ||
/// Call this method to get the stream for a given requested resource. | ||
/// </summary> | ||
/// <param name="url">The requested url.</param> | ||
/// <param name="extension">Output parameter whose value is the extension | ||
/// of the requested resource. This extension does not contain "." character.</param> | ||
/// <returns>Returns the stream if the requested resource can be found, or null | ||
/// otherwise.</returns> | ||
public override Stream GetResource(string url, out string extension) | ||
{ | ||
extension = "txt"; | ||
var uri = new Uri(url); | ||
string resourceName; | ||
var assembly = GetResourceAssembly(uri, out resourceName); | ||
if (null == assembly) | ||
{ | ||
return null; | ||
} | ||
|
||
var stream = assembly.GetManifestResourceStream(resourceName); | ||
var idx = resourceName.LastIndexOf('.'); | ||
if (idx > 0) | ||
{ | ||
extension = resourceName.Substring(idx + 1); | ||
} | ||
|
||
return stream; | ||
} | ||
|
||
protected virtual Assembly GetResourceAssembly(Uri url, out string resourceName) | ||
{ | ||
var path = url.AbsoluteUri.Replace(BaseUrl, "").Replace('/', '.'); | ||
resourceName = RootNamespace + path; | ||
return this.Assembly; | ||
} | ||
} | ||
} |
Oops, something went wrong.