public static void pushState <T>( this History h, T state, string url, bool exclusive, Action <HistoryScope <T> > yield ) { // exclusive parent means a sub state will undo parent, so they wont exist at the same time // https://sites.google.com/a/jsc-solutions.net/backlog/knowledge-base/2013/201312/20131222-form // https://sites.google.com/a/jsc-solutions.net/backlog/knowledge-base/2014/201405/20140517 // X:\jsc.svn\examples\javascript\UIAutomationEvents\UIAutomationEvents\Application.cs // X:\jsc.svn\examples\javascript\CSS\Test\CSSHistoric\CSSHistoric\Application.cs // X:\jsc.svn\examples\javascript\Test\TestHistoryForwardEvent\TestHistoryForwardEvent\Application.cs // does the forward button work? var delay = Stopwatch.StartNew(); Console.WriteLine("HistoryExtensions pushState before yield"); // when is the yield called? HistoryExtensions.yield( delegate { //0:3083ms HistoryExtensions pushState before yield //0:3086ms HistoryExtensions pushState.yield { ElapsedMilliseconds = 3, state = } //0:3087ms HistoryExtensions pushState.yield before: { exclusive = 0, length = 1, MethodToken = AgAABgY2dze_awFR4sqxY4A, data_invoke = { function = AgAABgY2dze_awFR4sqxY4A, arguments = { foo = foo } }, data = [object Object] } Console.WriteLine("HistoryExtensions pushState.yield " + new { delay.ElapsedMilliseconds, // whats the current state? Native.window.history.state } ); if (yield.Target != null) { if (yield.Target != Native.self) { throw new InvalidOperationException( "we can only continue with global methods for now... " + new { yield.Target } ); } } var MethodToken = ((__MethodInfo)yield.Method).InternalMethodToken; //var data_invoke = new { function = MethodToken, arguments = new object[] { state } }; var data_invoke = new { MethodToken, arguments = new object[] { state } }; var data = new HistoryDetails { // is this the previous state? state = Native.window.history.state, hint = "ScriptCoreLib.JavaScript.DOM.HistoryExtensions.pushState", exclusive = exclusive, url = url, // arguments: //invoke = new { function = MethodToken, arguments = new object[] { state } } invoke = data_invoke }; //0:22850ms HistoryExtensions pushState before: { exclusive = 0, length = 1 } view-source:38792 //0:22851ms HistoryExtensions pushState after: { length = 2 } // X:\jsc.svn\examples\javascript\Test\TestHistoryForwardEvent\TestHistoryForwardEvent\Application.cs // http://stackoverflow.com/questions/6460377/html5-history-api-what-is-the-max-size-the-state-object-can-be Console.WriteLine("HistoryExtensions pushState.yield before: " + new { MethodToken, exclusive, Native.window.history.length, data_invoke, data }); var current = new { Native.document.location.href }; // fck ie // y("history.state ", x_history_state, (HistoryDetails)Native.window.history.state); Native.window.history.pushState(data, "", url); //0:137143ms HistoryExtensions pushState before yield view-source:38792 //0:137145ms HistoryExtensions pushState.yield view-source:38792 //0:137147ms HistoryExtensions pushState.yield before: { exclusive = 0, length = 1, MethodToken = AgAABgY2dze_awFR4sqxY4A, data_invoke = { function = AgAABgY2dze_awFR4sqxY4A, arguments = { foo = foo } }, data = [object Object] } view-source:38792 //0:137149ms HistoryExtensions pushState after: { length = 2, state = [object Object] } //Console.WriteLine("HistoryExtensions pushState.yield after: " + new //{ // Native.window.history.length, // Native.window.history.state //}); //var data1 = (HistoryDetails)Native.window.history.state; //Console.WriteLine("HistoryExtensions pushState.yield after: " + new //{ // data1.invoke //}); #region __unwind TaskCompletionSource <HistoryScope <T> > __unwind = null; Func <TaskCompletionSource <HistoryScope <T> > > __get_unwind = delegate { // ok, something is listening to inline unwind. // lets wait for the event then and not reload Console.WriteLine("HistoryExtensions pushState __get_unwind [inline]"); if (__unwind == null) { __unwind = new TaskCompletionSource <HistoryScope <T> >(); } return(__unwind); }; #endregion var scope = new HistoryScope <T> { __state = state, __TaskCompletionSource = __get_unwind }; #region exclusive if (exclusive) { // this state is market exlusive. // as such. we shall destroy any other state before we continue. // if we go back in time // we have to reactivate them ofcourse. Console.WriteLine("HistoryExtensions pushState exlusive scope " + new { url }); foreach (var unwind in HistoryScope.inline_unwind.AsEnumerable()) { var reload = unwind(); if (reload) { throw new NotImplementedException("exclusve scope needs to unwind prior states, yet one of them asks for full reload. what to do?"); } } //0:1ms HistoryExtensions pushState exlusive scope { url = http://192.168.1.91:13905/#/foo } view-source:35994 //0:1ms HistoryExtensions pushState before enter scope { url = http://192.168.1.91:13905/#/foo } Console.WriteLine("disable all history aware styles, who is reenabling them?"); IStyleSheet.InternalHistoryAwareSheets.AsEnumerable() // the application .ctor is not rerun? so we cannot even keep the primary style can we? //.Skip(1) .WithEachIndex( (style, i) => { Console.WriteLine("new exclusive state, will disable historic css " + new { i } +style.Owner.getAttribute("historic-url")); if (i == 0) { return; } style.disabled = true; } ); } #endregion HistoryScope.inline_unwind_data.Push(data); HistoryScope.inline_unwind.Push( delegate { if (__unwind == null) { return(true); } // time to do inline unwind. __unwind.SetResult(scope); return(false); } ); // X:\jsc.svn\examples\javascript\CSS\Test\CSSHistoric\CSSHistoric\Application.cs ; var NextStyle = new IStyleSheet(); NextStyle.Owner.setAttribute("historic-url", IStyleSheet.all.Owner.getAttribute("historic-url") + " -> " + url); IStyleSheet.InternalHistoryAwareSheets.Push(NextStyle); // activate the scope Console.WriteLine("HistoryExtensions pushState before enter scope " + new { url }); yield(scope); Console.WriteLine("HistoryExtensions pushState " + new { HistoryScope.inline_unwind.Count }); } ); }
public static void replaceState <T>(this History h, T state, string url, bool exclusive, Action <HistoryScope <T> > yield ) { // tested by // X:\jsc.svn\examples\javascript\async\AsyncHistoricActivities\AsyncHistoricActivities\Application.cs HistoryExtensions.yield( delegate { //Console.WriteLine("enter replaceState"); if (yield.Target != null) { if (yield.Target != Native.self) { throw new InvalidOperationException("we can only continue with global methods for now... " + new { yield.Target }); } } var MethodToken = ((__MethodInfo)yield.Method).InternalMethodToken; var data_state = (HistoryDetails)Native.window.history.state; // HistoryExtensions onpopstate { state = [object Object], e = { state = 7 }, history = { state = 7 }, Count = 2 } // m.state = h.state; //m.hint = 'ScriptCoreLib.JavaScript.DOM.HistoryExtensions.replaceState'; if (data_state != null) { data_state = (HistoryDetails)data_state.state; } var data = new HistoryDetails { // parent state = data_state, hint = "ScriptCoreLib.JavaScript.DOM.HistoryExtensions.replaceState", exclusive = exclusive, url = url, // arguments: //invoke = new { function = MethodToken, arguments = new object[] { state } } invoke = new { MethodToken, arguments = new object[] { state } } }; Console.WriteLine("before history.replaceState"); // IE throws __exc Argument not optional // X:\jsc.svn\examples\javascript\CSS\Test\CSSHistoric\CSSHistoric\Application.cs Native.window.history.replaceState(data, "", url); Console.WriteLine("after history.replaceState"); #region __unwind TaskCompletionSource <HistoryScope <T> > __unwind = null; Func <TaskCompletionSource <HistoryScope <T> > > __get_unwind = delegate { // ok, something is listening to inline unwind. // lets wait for the event then and not reload Console.WriteLine("__get_unwind [inline]"); if (__unwind == null) { __unwind = new TaskCompletionSource <HistoryScope <T> >(); } return(__unwind); }; #endregion var scope = new HistoryScope <T> { __state = state, __TaskCompletionSource = __get_unwind }; if (HistoryScope.inline_unwind.Count > 0) { HistoryScope.inline_unwind_data.Pop(); var unwind = HistoryScope.inline_unwind.Pop(); var reload = unwind(); if (reload) { throw new NotImplementedException("cant reload here can we"); } } #region exclusive if (exclusive) { // this state is market exlusive. // as such. we shall destroy any other state before we continue. // if we go back in time // we have to reactivate them ofcourse. Console.WriteLine("HistoryExtensions pushState exlusive scope " + new { url }); foreach (var unwind in HistoryScope.inline_unwind.AsEnumerable()) { var reload = unwind(); if (reload) { throw new NotImplementedException("exclusve scope needs to unwind prior states, yet one of them asks for full reload. what to do?"); } } Console.WriteLine("disable all history aware styles, who is reenabling them?"); IStyleSheet.InternalHistoryAwareSheets.AsEnumerable() // the application .ctor is not rerun? so we cannot even keep the primary style can we? //.Skip(1) .WithEachIndex( (style, i) => { Console.WriteLine("new exclusive state, will disable historic css " + new { i } +style.Owner.getAttribute("historic-url")); if (i == 0) { return; } style.disabled = true; } ); } #endregion HistoryScope.inline_unwind_data.Push(data); HistoryScope.inline_unwind.Push( delegate { if (__unwind == null) { return(true); } // time to do inline unwind. __unwind.SetResult(scope); return(false); } ); //var css = IStyleSheet.InternalHistoryAwareSheets.Pop(); //if (css != null) // css.disabled = true; var css = IStyleSheet.InternalHistoryAwareSheets.Pop(); if (css != null) { Console.WriteLine("replace: remove css " + css.Owner.getAttribute("historic-url") ); css.disabled = true; css.Owner.Orphanize(); } //IStyleSheet.InternalHistoryAwareSheets.Push(new IStyleSheet()); var NextStyle = new IStyleSheet(); NextStyle.Owner.setAttribute("historic-url", IStyleSheet.all.Owner.getAttribute("historic-url") + " => " + url); IStyleSheet.InternalHistoryAwareSheets.Push(NextStyle); Console.WriteLine("before yield"); yield(scope); Console.WriteLine("replaceState: " + new { HistoryScope.inline_unwind.Count }); } ); }