Building the Bing apps for Windows 8OverviewFor Windows 8, the Bing team built News, Weather, Finance, Sports, Travel and Maps apps. This technical overview provides insight on the architecture of these apps, key Windows 8 features and the contracts they use, common controls they employ, and world readiness more generally. Several members of the Bing team formed an apps team approximately one year ago to deliver a set of apps powered by Bing for Windows 8. The focus of these apps is to keep users informed by delivering fast and fluid experiences, with content from multiple sources. All the apps are optimized for touch and tablet devices, but also work great with a keyboard and mouse. We have spent the last several months making these apps world-ready. When developing the apps, we had two objectives: to build a set of great apps to make Windows 8 even more compelling and to serve as a model for app developers. With this post, we provide you with a technical overview of the apps and offer insight/resources you can use to develop your own apps. Through the process, we learned a lot – even a few things we’d do differently next time. Keep reading for the full story. Weather app: Find the weather conditions for your places of interest. Architecture overviewPlatform servicesAll our apps are written in HTML/Java Script, except the Maps app, which is built in XAML/C#. All the apps share a common client platform that provides several essential services, such as instrumentation, caching, query services, settings, roaming, profile management, market customizations, and speech fundamentals. We deliberately chose to have client side caching, to invest in prefetching and for the client to set the time to live of various pieces of data for a couple reasons. Our apps are designed for all PC devices, many of which we expect to be tablet devices. Windows 8 tablets can be used to consume content as well as create content by consumers and businesses alike. In many situations, we know users go through various states of connectivity (fully connected on fast networks, weak connectivity over WiFi or cellular, flaky networks, and even no connectivity). Our goal was to build a rich client app that’s different from a webpage. We used IE concepts of caching all network data to the file system and re-using cached data while waiting for fresh data to arrive. We also designed experiences for when cached data wasn’t available and network requests failed. For these scenarios, we, provide graceful error messages, retry mechanisms and listen for network connectivity changes from the OS to automatically trigger a retry. Query servicesOur apps use several services that are built on the Bing stack and/or in Windows Azure. The Bing services and data are served via dedicated application servers built on the Bing platform. For example, the Finance app heavily uses data and services from Azure, whereas data and services for the Maps app are provided via the Maps control, which is built by the Bing Maps team. Our apps also have other articles, images and videos that are hosted in our Content Management System. If you want to create apps that take advantage of the Bing web index or industry leading publisher data, check out the Windows Azure Marketplace, where you can access the Bing Search API and info from leading publishers like STATS Sports or agencies like the United Nations. CachingSupporting hundreds of millions of users interacting with rich apps that are powered by lots of data and content requires a lot of server computing. To scale the hardware needs along with the number of users, we have invested heavily in caching at different tiers. Our content management system rendering server, services in Azure, as well as the local client platform itself cache data to reduce the server load. If you’re anticipating several thousand users, consider local caching as a means to limit server computing and to improve the user experience – you can find out more about app caching (AppCache) on the Dev Center. Some of the ways our apps make use of caching on the client involve:
Custom controlsDesign is a fundamental differentiator for our apps and plays a key role in building visually organized and intuitive to use apps. To achieve a consistent look and feel and a visually immersive experience across our apps, we built custom controls on top of the compelling UI controls that Windows provides. If you want a consistent look and feel across your apps or want to deliver against a signature user interface, we encourage you to take advantage of the flexibility of Windows and build your own UX framework or custom controls on top of Windows 8. There are ample resources available on MSDN to help you create your own UX framework and custom controls. FailsafeIf your app relies upon data from a 3rd party, plan on full outages as well as partial outages from your data providers from time to time. We strive to make our apps avoid single points of failure and we build in several failsafe mechanisms. We invested in various failsafe practices on both the server and client side primarily for the benefit of our users. Across all our apps, we have data and services from many parts of Microsoft as well as industry partners. All these external sources have varying degrees of uptime SLAs and TTM (time to mitigate) service level outages. Any given panorama on any application could rely on data and services from multiple sources. To provide a good end user experience, we use failsafe techniques both on the server and client side, including caching, backup providers, graceful degradation of features or falling back on acceptably stale data in some cases (for example, destination information). Think about these failsafe measures and take steps to create adaptive UI and error messaging when design and develop your app, not during or after a data failure. Client framework – language choicesOne question developers frequently ask is why we implement using client-side HTML, rather than server-based HTML5. The short answer is that apps on Windows 8 are not websites. Creating a great Windows Store app requires a deep level of integration with the platform that we simply cannot achieve with standard web code. If we had delivered features purely via the same HTML5 normally viewed in the browser, the pages would not have had access to the features of Windows 8 that really make the user experience great. Building an app gave us several advantages, including:
By: Ray Yagubyan
$1,649.00
Pros
Cons
Manufacturer’s DescriptionRadically thin, supremely strong, scratch resistant and easy to clean: White Gorilla Glass 2 makes the beauty of the 13.3″ Aspire S7 Series gleam at an ultra-thin 11.9 mm. The 11.6″ model, with its sleek aluminum unibody, is just 12.2 mm slim. Either Ultrabook gives you the freedom to go anywhere, carefree and looking fabulous. Performance
Acer isn’t kidding when they describe the $1699, S7-391 ultraportable as cutting edge. This Windows 8 laptop is so thin (11.9 mm) and stiff, it could double as a weapon in the wrong hands. Did I say wrong hands? Assuming you can afford it, there are no wrong hands for this laptop. It’s forward thinking in its design, eye-catchingly attractive, travels light, and is a heck of a performer. The S7 is a touchscreen laptop, which partly explains the extreme rigidity–you’re can’t get away with users poking at a display that’s not sturdily constructed or flexes too much. The white Gorilla Glass 2 outer panels and an anodized aluminum keyboard deck that are in play also give the S7 a modern look that’s vaguely Mac-like. The keyboard is short-throw yet types nicely, and the one-piece touchpad is very responsive, perhaps overly so for my ham-handed use. The touchpad’s placement is spot on and it’s also press-to-click so you can turn off tapping if you’d like.
Features and performanceComponent-wise, our S7-391-9413 (a Canadian SKU identical to the US S7-391-9886) test unit boasted a state-of-the-art selection: a Core i7-3517U CPU, 4GB (the max) of DDR3 memory, and twin integrated 128GB SSDs striped in RAID 0 for 256GB of total disk capacity. These lifted the laptop to an impressive 72 score on our new WorldBench 8 test suite. That compares well with the Lenovo IdeaPad Yoga, which posted a WorldBench 8 score of 60, although the Yoga PCWorld reviewed used a mobile Core i5 CPU and costs $600 less. The S7-391 utilizes Intel’s integrated HD 4000 graphics which in most cases delivers playable games rates up to 1366 by 768 resolution; some games will require stepping down further in resolution. DiRT Showdown posted 35 frames per second at 1366 by 768 low detail levels, and eked out 11.4fps in the demanding Civilization V late game test at low detail and 1366 by 768. Our unit booted in a mere 11 seconds–not the fastest we’ve seen, but still quick. Less expensive S7 models with slower CPUs and smaller hard drives are available from $1199. Unfortunately there’s no 8GB memory option which would be nice for power users running virtual machines and the like.
Display and connectivityThe S7-391′s display packs a 1920 by 1080 grid of pixels into a mere 13.3 diagonal inches. That makes for a super-fine and basically unnoticeable dot pitch, but also means many users will need to adjust the text and icon settings to 125% of normal in order to read them. That action means the same amount of usable screen real estate as with a lower resolution display, but much smoother text and wonderful video. The display pivots on its hinges 180 degrees so the entire laptop will lay flat against a table. However, with so much keyboard deck between you and the display, this seems useful only when you’re standing over the unit. Rotating a full 360 degrees might work better. The port selection on the S7-391 is as good as you’ll find on an ultraportable. There are two USB 3.0 ports, a micro-HDMI port, a headset/headphone jack, as well as an SD/MMC memory card slot. Unlike some vendors, Acer realizes that you’ll probably need or want to use Ethernet on occasion and thoughtfully includes a USB to Ethernet adapter. There’s an HDMI to VGA adapter as well, but you’ll have to grab your own micro-HDMI to HDMI cable if you’ve the need. Connectivity is top-notch with 802.11 a/b/g/n Wi-Fi, Bluetooth 4.0, and the aforementioned tk Ethernet USB adapter.
Ultra-thin at a costThe S7-391 travels at a mere 3.5 pounds with AC adapter, and an ounce or two heavier with the two USB adapters. The laptop itself is a mere 2.8 pounds. Battery life might be a concern for some at only 3 hours and 54 minutes, but for a laptop this thin and light with high-performance components, you’re not going to do much better. All in all, the S7-391 is a nice laptop to use and show off. It would be nice to have an 8GB option and better battery life, but neither is essential for the vast majority of users. The design and overall usability are top notch. And it’s an eye-catching system, sure to draw attention whenever you pull it out.
Thanks Ray Yagubyan
10 C++ 11 Features Every C++ Developer Should UseThis article discusses a series of features new to C++11 that all developers should learn and use. There are lots of new additions to the language and the standard library, and this article barely scratches the surface. However, I believe some of these new features should become routine for all C++ developers. You could probably find many similar articles evangelizing different C++11 features. This is my attempt to assemble a list of C++ features that should be a norm nowadays. Table of contents:
autoBefore C++11 the auto keyword was used for storage duration
specification. In the new standard its purpose was changed towards type
inference. Collapse | Copy Code auto i = 42; // i is an int auto l = 42LL; // l is an long long auto p = new foo(); // p is a foo* Using Collapse | Copy Code std::map<std::string, std::vector<int>> map; for(auto it = begin(map); it != end(map); ++it) { } You should note that auto cannot be used as the return type of a function. However, you can use auto in place of the return type of function, but in this case the function must have a trailing return type. In this case auto does not tell the compiler it has to infer the type, it only instructs it to look for the return type at the end of the function. In the example below the return type of function compose is the return type of operator+ that sums values of types T1 and T2. Collapse | Copy Code template <typename T1, typename T2> auto compose(T1 t1, T2 t2) -> decltype(t1 + t2) { return t1+t2; } auto v = compose(2, 3.14); // v's type is double nullptrZero used to be the value of null pointers, and that has drawbacks
due to the implicit conversion to integral types. The keyword Collapse | Copy Code void foo(int* p) {} void bar(std::shared_ptr<int> p) {} int* p1 = NULL; int* p2 = nullptr; if(p1 == p2) { } foo(nullptr); bar(nullptr); bool f = nullptr; int i = nullptr; // error: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type For backward compatibility 0 is still a valid null pointer value. Range-based for loopsC++11 augmented the for statement to support the “foreach” paradigm
of iterating over collections. In the new form, it is possible to
iterate over C-like arrays, initializer lists and anything for which the
non-member This for each for is useful when you just want to get and do something with the elements of a collection/array and don’t care about indexes, iterators or number of elements. Collapse | Copy Code std::map<std::string, std::vector<int>> map; std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); map["one"] = v; for(const auto& kvp : map) { std::cout << kvp.first << std::endl; for(auto v : kvp.second) { std::cout << v << std::endl; } } int arr[] = {1,2,3,4,5}; for(int& e : arr) { e = e*e; } Override and finalI always founded the virtual methods badly designed in C++ because there wasn’t (and still isn’t) a mandatory mechanism to mark virtual methods as overridden in derived classes. The virtual keyword is optional and that makes reading code a bit harder, because you may have to look through the top of the hierarchy to check if the method is virtual. I have always used, and encouraged people to use the virtual keyword on derived classes also, to make the code easier to read. However, there are subtle errors that can still arise. Take for instance the following example: Collapse | Copy Code class B { public: virtual void f(short) {std::cout << "B::f" << std::endl;} }; class D : public B { public: virtual void f(int) {std::cout << "D::f" << std::endl;} };
Here is another subtle error: the parameters are the same, but the method in the base class is marked const, while me method in the derived is not. Collapse | Copy Code class B { public: virtual void f(int) const {std::cout << "B::f " << std::endl;} }; class D : public B { public: virtual void f(int) {std::cout << "D::f" << std::endl;} }; Again, these two are overloads and not overrides, so if you call Fortunately there is now a way to describe your intentions. Two new special identifiers (not keywords) have been added: Collapse | Copy Code class B { public: virtual void f(short) {std::cout << "B::f" << std::endl;} }; class D : public B { public: virtual void f(int) override {std::cout << "D::f" << std::endl;} }; This now triggers a compiler error (the same error you’d get for the second example too, if using the
On the other hand if you intend to make a method impossible to override any more (down the hierarchy) mark it as Collapse | Copy Code class B { public: virtual void f(int) {std::cout << "B::f" << std::endl;} }; class D : public B { public: virtual void f(int) override final {std::cout << "D::f" << std::endl;} }; class F : public D { public: virtual void f(int) override {std::cout << "F::f" << std::endl;} };
Strongly-typed enums“Traditional” enums in C++ have some drawbacks: they export their enumerators in the surrounding scope (which can lead to name collisions, if two different enums in the same have scope define enumerators with the same name), they are implicitly converted to integral types and cannot have a user-specified underlying type. These issues have been fixed in C++ 11 with the introduction of a new
category of enums, called strongly-typed enums. They are specified with
the Collapse | Copy Code enum class Options {None, One, All}; Options o = Options::All; Smart pointersThere have been tons of articles written on this subject, therefore I just want to mention the smart pointers with reference counting and auto releasing of owned memory that are available:
On the other hand the auto_ptr is obsolete and should no longer be used. When you should unique_ptr and when you should use shared_ptr depends on the ownership requirements and I recommend reading this discussion. The first example below shows Collapse | Copy Code void foo(int* p) { std::cout << *p << std::endl; } std::unique_ptr<int> p1(new int(42)); std::unique_ptr<int> p2 = std::move(p1); // transfer ownership if(p1) foo(p1.get()); (*p2)++; if(p2) foo(p2.get()); The second example shows Collapse | Copy Code void foo(int* p) { } void bar(std::shared_ptr<int> p) { ++(*p); } std::shared_ptr<int> p1(new int(42)); std::shared_ptr<int> p2 = p1; bar(p1); foo(p2.get()); The first declaration is equivalent to this one Collapse | Copy Code auto p3 = std::make_shared<int>(42); make_shared<T> is a non-member function and has the advantage of allocating memory for the shared object and the smart pointer with a single allocation, as opposed to the explicit construction of a shared_ptr via the contructor, that requires at least two allocations. In addition to possible overhead, there can be situations where memory leaks can occur because of that. In the next example memory leaks could occur if seed() throws an error. Collapse | Copy Code void foo(std::shared_ptr<int> p, int init) { *p = init; } foo(std::shared_ptr<int>(new int(42)), seed()); No such problem exists if using make_shared. The third sample shows usage of Collapse | Copy Code auto p = std::make_shared<int>(42); std::weak_ptr<int> wp = p; { auto sp = wp.lock(); std::cout << *sp << std::endl; } p.reset(); if(wp.expired()) std::cout << "expired" << std::endl; If you try to lock on an expired LambdasAnonymous functions, called lambda, have been added to C++ and
quickly rose to prominence. It is a powerful feature borrowed from
functional programming, that in turned enabled other features or powered
libraries. You can use lambdas wherever a function object or a functor
or a Collapse | Copy Code std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); std::for_each(std::begin(v), std::end(v), [](int n) {std::cout << n << std::endl;}); auto is_odd = [](int n) {return n%2==1;}; auto pos = std::find_if(std::begin(v), std::end(v), is_odd); if(pos != std::end(v)) std::cout << *pos << std::endl; A bit trickier are recursive lambdas. Imagine a lambda that represents a Fibonacci function. If you attempt to write it using auto you get compilation error: Collapse | Copy Code auto fib = [&fib](int n) {return n < 2 ? 1 : fib(n-1) + fib(n-2);}; Collapse | Copy Code error C3533: 'auto &': a parameter cannot have a type that contains 'auto' error C3531: 'fib': a symbol whose type contains 'auto' must have an initializer error C3536: 'fib': cannot be used before it is initialized error C2064: term does not evaluate to a function taking 1 arguments The problem is auto means the type of the object is inferred from its
initializer, yet the initializer contains a reference to it, therefore
needs to know its type. This is a cyclic problem. The key is to break
this dependency cycle and explicitly specify the function’s type using Collapse | Copy Code std::function<int(int)> lfib = [&lfib](int n) {return n < 2 ? 1 : lfib(n-1) + lfib(n-2);}; non-member begin() and end()You probably noticed I have used in the samples above non-member Let’s take for instance the previous example where I was printing a vector and then looking for its first odd element. If the std::vector was instead a C-like array, the code might have looked like this: Collapse | Copy Code int arr[] = {1,2,3}; std::for_each(&arr[0], &arr[0]+sizeof(arr)/sizeof(arr[0]), [](int n) {std::cout << n << std::endl;}); auto is_odd = [](int n) {return n%2==1;}; auto begin = &arr[0]; auto end = &arr[0]+sizeof(arr)/sizeof(arr[0]); auto pos = std::find_if(begin, end, is_odd); if(pos != end) std::cout << *pos << std::endl; With non-member Collapse | Copy Code int arr[] = {1,2,3}; std::for_each(std::begin(arr), std::end(arr), [](int n) {std::cout << n << std::endl;}); auto is_odd = [](int n) {return n%2==1;}; auto pos = std::find_if(std::begin(arr), std::end(arr), is_odd); if(pos != std::end(arr)) std::cout << *pos << std::endl; This is basically identical code to the Collapse | Copy Code template <typename Iterator> void bar(Iterator begin, Iterator end) { std::for_each(begin, end, [](int n) {std::cout << n << std::endl;}); auto is_odd = [](int n) {return n%2==1;}; auto pos = std::find_if(begin, end, is_odd); if(pos != end) std::cout << *pos << std::endl; } template <typename C> void foo(C c) { bar(std::begin(c), std::end(c)); } template <typename T, size_t N> void foo(T(&arr)[N]) { bar(std::begin(arr), std::end(arr)); } int arr[] = {1,2,3}; foo(arr); std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); foo(v); static_assert and type traits
Collapse | Copy Code template <typename T, size_t Size> class Vector { static_assert(Size < 3, "Size is too small"); T _points[Size]; }; int main() { Vector<int, 16> a1; Vector<double, 2> a2; return 0; } Collapse | Copy Code error C2338: Size is too small see reference to class template instantiation 'Vector<T,Size>' being compiled with [ T=double, Size=2 ] static_assert becomes more useful when used together with type traits. These are a series of classes that provide information about types at compile time. They are available in the <type_traits> header. There are several categories of classes in this header: helper classes, for creating compile-time constants, type traits classes, to get type information at compile time, and type transformation classes, for getting new types by applying transformation on existing types. In the following example function add is supposed to work only with integral types. Collapse | Copy Code template <typename T1, typename T2> auto add(T1 t1, T2 t2) -> decltype(t1 + t2) { return t1 + t2; } However, there are no compiler errors if one writes Collapse | Copy Code std::cout << add(1, 3.14) << std::endl; std::cout << add("one", 2) << std::endl; The program actually prints 4.14 and “e”. But if we add some compile-time asserts, both these lines would generate compiler errors. Collapse | Copy Code template <typename T1, typename T2> auto add(T1 t1, T2 t2) -> decltype(t1 + t2) { static_assert(std::is_integral<T1>::value, "Type T1 must be integral"); static_assert(std::is_integral<T2>::value, "Type T2 must be integral"); return t1 + t2; } Collapse | Copy Code error C2338: Type T2 must be integral see reference to function template instantiation 'T2 add<int,double>(T1,T2)' being compiled with [ T2=double, T1=int ] error C2338: Type T1 must be integral see reference to function template instantiation 'T1 add<const char*,int>(T1,T2)' being compiled with [ T1=const char *, T2=int ] Move semanticsThis is yet another important and well covered topic from C++11, that one could write a series of articles, not just a paragraph. Therefore I will not get into too many details, but encourage you to find additional readings, if you’re not already familiar with the topic. C++11 has introduced the concept of rvalue references (specified with &&) to differentiate a reference to an lvalue or an rvalue. An lvalue is an object that has a name, while an rvalue is an object that does not have a name (a temporary object). The move semantics allow modifying rvalues (previously considered immutable and indistinguishable from const T& types). A C++ class/struct used to have some implicit member functions: default constructor (only if another constructor is not explicitly defined) and copy constructor, a destructor and a copy assignment operator. The copy constructor and the copy assignment operator perform a bit-wise (or shallow) copy, i.e. copying the variables bitwise. That means if you have a class that contains pointers to some objects, they just copy the value of the pointers and not the objects they point to. This might be OK in some cases, but for many cases you actually want a deep-copy, meaning that you want to copy the objects pointers refer to, and not the values of the pointers. In this case you have to explicitly write copy constructor and copy assignment operator to perform a deep-copy. What if the object you initialize or copy from is an rvalue (a temporary). You still have to copy its value, but soon after the rvalue goes away. That means an overhead of operations, including allocations and memory copying that after all, should not be necessary. Enter the move constructor and move assignment operator. These two special functions take a T&& argument, which is an rvalue. Knowing that fact, they can modify the object, such as “stealing” the objects their pointers refer to. For instance, a container implementation (such as a vector or a queue) may have a pointer to an array of elements. When an object is instantiating from a temporary, instead of allocating another array, copying the values from the temporary, and then deleting the memory from the temporary when that is destroyed, we just copy the value of the pointer that refers to the allocated array, thus saving an allocation, copying a sequence of elements, and a later de-allocation. The following example shows a dummy buffer implementation. The buffer
is identified by a name (just for the sake of showing a point revealed
below), has a pointer (wrapper in an Collapse | Copy Code template <typename T> class Buffer { std::string _name; size_t _size; std::unique_ptr<T[]> _buffer; public: // default constructor Buffer(): _size(16), _buffer(new T[16]) {} // constructor Buffer(const std::string& name, size_t size): _name(name), _size(size), _buffer(new T[size]) {} // copy constructor Buffer(const Buffer& copy): _name(copy._name), _size(copy._size), _buffer(new T[copy._size]) { T* source = copy._buffer.get(); T* dest = _buffer.get(); std::copy(source, source + copy._size, dest); } // copy assignment operator Buffer& operator=(const Buffer& copy) { if(this != ©) { _name = copy._name; if(_size != copy._size) { _buffer = nullptr; _size = copy._size; _buffer = _size > 0 > new T[_size] : nullptr; } T* source = copy._buffer.get(); T* dest = _buffer.get(); std::copy(source, source + copy._size, dest); } return *this; } // move constructor Buffer(Buffer&& temp): _name(std::move(temp._name)), _size(temp._size), _buffer(std::move(temp._buffer)) { temp._buffer = nullptr; temp._size = 0; } // move assignment operator Buffer& operator=(Buffer&& temp) { assert(this != &temp); // assert if this is not a temporary _buffer = nullptr; _size = temp._size; _buffer = std::move(temp._buffer); _name = std::move(temp._name); temp._buffer = nullptr; temp._size = 0; return *this; } }; template <typename T> Buffer<T> getBuffer(const std::string& name) { Buffer<T> b(name, 128); return b; } int main() { Buffer<int> b1; Buffer<int> b2("buf2", 64); Buffer<int> b3 = b2; Buffer<int> b4 = getBuffer<int>("buf4"); b1 = getBuffer<int>("buf5"); return 0; } The default copy constructor and copy assignment operator should look
familiar. What’s new to C++11 is the move constructor and move
assignment operator, implemented in the spirit of the aforementioned
move semantics. If you run this code you’ll see that when b4 is
constructed, the move constructor is called. Also, when b1 is assigned a
value, the move assignment operator is called. The reason is the value
returned by You probably noticed the use of std::move in the move constructor, when initializing the name variable and the pointer to the buffer. The name is actually a string, and UPDATE: Though the purpose of this example was to show how move constructor and move assignment operator should be implemented, the exact details of an implementation may vary. An alternative implementation was provided by Member 7805758 in the comments. To be easier to see it I will show it here: Collapse | Copy Code template <typename T> class Buffer { std::string _name; size_t _size; std::unique_ptr<T[]> _buffer; public: // constructor Buffer(const std::string& name = "", size_t size = 16): _name(name), _size(size), _buffer(size? new T[size] : nullptr) {} // copy constructor Buffer(const Buffer& copy): _name(copy._name), _size(copy._size), _buffer(copy._size? new T[copy._size] : nullptr) { T* source = copy._buffer.get(); T* dest = _buffer.get(); std::copy(source, source + copy._size, dest); } // copy assignment operator Buffer& operator=(Buffer copy) { swap(*this, copy); return *this; } // move constructor Buffer(Buffer&& temp):Buffer() { swap(*this, temp); } friend void swap(Buffer& first, Buffer& second) noexcept { using std::swap; swap(first._name , second._name); swap(first._size , second._size); swap(first._buffer, second._buffer); } }; ConclusionsThere are many more things to say about C++11; this was just one of many possible beginnings. This article presented a series of core language and standard library features that every C++ developer should use. However, I recommend you additional readings, at least for some of these features.
Anatomy of HTML5/Javascript Single Page Application
IntroductionWhat is Single Page Application (SPA)?Ordinary HTML applications/web-sites fetch each page from the server every time the user wants to go to a new page. SPA applications, however, bring all the pages of the application on the client’s browser at the beginning and use JavaScript in order to switch between the pages making parts of HTML visible and invisible depending on which page is chosen. This makes the HTML application as responsive as a native or Silverlight application, since the navigation between the pages does not require a round trip to the server. This advantage comes at the expense of a higher application loading time. There are some ways to speed up the loading of an SPA application, making the SPA loading experience for the user the same as when loading a usual HTML application, but this topic is beyond this article. If you think of it, an SPA application is very similar to a Silverlight application, in that most Silverlight applications load all the pages at the beginning and later allow the users to navigate between the pages without calling the server. So understanding of the SPA concepts should come very naturally to Silverlight developers. Navigation StateIn its generic form, the browser navigation maps a unique URL to the specific navigation state of the browser application. The “navigation state of the application” determines which pages or regions within the application are shown or hidden or how they are shown. The browser interprets the URL and sets the application to the corresponding state. This is required for e.g. enabling the user to navigate the browser application by pressing the browser “back” and “forward” navigation buttons (the browser stores the URLs and when the user presses one of the browser navigation buttons the URL changes and the application state changes correspondingly). Also, this is useful when some external page refers to some specific page (or state) within the application which is not the application’s default page. The reverse is also true: once the state of the application changes, e.g. because the user presses a tab or a hyperlink to move to a different page, the browser URL should also change to the one corresponding to the new state. For the ordinary (non-SPA) HTML applications the navigation comes naturally (the page loads from the server based on the corresponding URL). The SPA applications, however, need to use some JavaScript magic in order to achieve the one-to-one mapping between the URLs and the navigation states of the application. Here we present a new functionality that makes the SPA navigation easier to achieve than by using other already existing frameworks. The same navigation concepts can apply to any native single window/multipage applications especially to those built for smart phones and tablets and time permitting, I am going to write more articles about it. Composition of an SPA ApplicationIn my experience, building SPA application results in large HTML files since the application consists of multiple pages and all of them are loaded together. Large HTML files can be difficult to understand and modify. I created functionality allowing to split SPAs into multiple files and load and assemble them all on the client. This functionality is also discussed here. BPF FrameworkBeing a great fan of WPF and Silverlight, I ambitiously called the new framework BPF standing for Browser Presentation Foundation. Its ultimate purpose is to provide the capabilities one can find in WPF and Silverlight and more. Currently it provides some generic purpose utility functionality, navigation and composition capabilities which will be described below. Composition part of the framework depends on JQuery, the rest of the framework is self-sufficient, and can be used without JQuery installed. There are two SPAs that have been built with an earlier version of BPF library: my own business website - awebpros.com and paperplusne.com. Note that paperplusne.com website does not have correct pricing data yet for all its items (for items without pricing data I put $1000 as their price). You can still order some plastic-ware through it and someone will contact you back about the prices. SPA Server CommunicationsJust like a Silverlight or a desktop application, the SPA application can minimize the amount of information it loads from the server by getting only the required data from the server (usually in JSON form) and not the generated HTML code as ordinary HTML applications do. I provide some examples of an SPA communicating with the server within this article. Organization of this ArticleWe present the simplest possible samples of the ordinary and SPA HTML/JavaScript sites. We talk about the differences between them. We discuss the navigation and present the navigation capabilities of the BPF framework. We discuss the composition using BPF framework. We talk about SPA communications with the server using ASP.NET MVC and provide corresponding examples. Important Note: This article concentrates on the business logic and not on the UI design. We present the SPAs built in the simplest possible way without any concern about how ugly they look. PrerequisitesYou need to have some knowledge of HTML and JavaScript in order to read and understand this article. I refer to HTML5, JavaScript, Knockout, JQuery, Guide for Recovering Silverlight/WPF/C# Addicts. Part 1 – JavaScript and DOM as a good HTML/JavaScript primer. Throughout this article, I use some very basic JQuery functionality to detect when the HTML document is loaded and also to provide a multiplatform way of binding to the DOM events, so some understanding of JQuery functionality is needed. A couple of paragraphs from JQuery and DOM Event should cover this information. When discussing composition we also use JQuery selectors. You can follow the JQuery Selectors link to learn about them. I am using JQuery-UI Part that covers communications with the server might require some basic understanding of ASP MVC, even though we try to explain everything within the article itself. Part of a Larger SeriesThis article can be considered part 3 of “HTML5, JavaScript, Knockout, JQuery, Guide for Recovering Silverlight/WPF/C# Addicts” series which also contain HTML5, JavaScript, Knockout, JQuery, Guide for Recovering Silverlight/WPF/C# Addicts. Part 1 – JavaScript and DOM and HTML5, JavaScript, Knockout, JQuery, Guide for Recovering Silverlight/WPF/C# Addicts. Part 2 – Solar System Animation built with SVG, Knockout and MVVM Pattern. SPA BasicsPresenting Two Page SPA and Two Page Ordinary HTML Application SamplesHere we present two very simple two-page HTML applications: one ordinary and the other SPA. The code for the ordinary HTML application is located under TwoPageOrdinaryHTMLApp solution, while the code for the SPA is located under TwoPageSPA solution. Both applications provide exactly the same user experience. There are two hyperlinks at the top of the HTML window corresponding to two pages. Clicking on top hyperlink shows first page’s text, while clicking on the other one shows the other page’s text: The ordinary HTML application has two HTML pages Page1.htm and Page2.htm. Both have hyper links at the top of the page (one to itself and one to the other page) and the page text. For page1.htm page text is “This is page 1″ and it is colored red. For page2.htm the text is “This is page 2″ and it is colored blue. Here is the page1.htm code: Collapse | Copy Code <body> <!-- hyper links for choosing the page --> <ul> <li><a href="Page1.htm">choose page1</a></li> <li><a href="Page2.htm">choose page2</a></li> </ul> <!-- page 1 message colored in red --> <p style="font-size:40px;color:red">This is page 1</p> </body> To start the TwoPageOrdinaryHTMLApp, right click on Page1.htm file within the Visual Studio’s solution explorer and choose “View in Browser” option if you want to view it in the default browser or “Browse with” option if you want to choose the browser. You can switch between the pages by clicking the hyperlinks at the top. The SPA solution uses JQuery (if you open Scripts folder you will see a bunch of JQuery files). You can install JQuery as a NuGet package as described in JQuery. There is only one HTML file within TwoPageSPA project: Index.html. You can start the application by right clicking on this file within solution explorer and choosing “Run in Browser”. Index.html has HTML part containing the hyperlinks and text for both page. It also has a JavaScript code for switching between the pages. Here is the HTML code within Index.html file: Collapse | Copy Code <body> <ul> <!-- href='#' is needed only to help the links look like links --> <li><a id="page1Link" href="#">choose page1</a></li> <li><a id="page2Link" href="#">choose page2</a></li> </ul> <!-- page 2 message colored in blue --> <!-- in the beginning page2 is not visible (display set to 'none') --> <p id="page2" style="font-size:40px;color:blue;display:none">This is page 2</p> <!-- page 1 message colored in red --> <p id="page1" style="font-size:40px;color:red" >This is page 1</p> </body> As you can see, the page links do not contain valid references – their Both pages’ text is placed below the links. Page 2 text is not visible in the beginning (its Page switching is done by JavaScript code placed below the HTML code: Collapse | Copy Code // use $(document).ready function to // make sure that the code executes only after the document's // DOM has been loaded into the browser. $(document).ready(function () { // when page1Link link is clicked, page1 shows, // page2 hides $(page1Link).bind("click", function () { $(page1).show(); $(page2).hide(); }); // when page2Link link is clicked, page2 shows, // page1 hides $(page2Link).bind("click", function () { $(page1).hide(); $(page2).show(); }); }); We use JQuery’s bind function to attach event handlers to One can see, however, there is a difference in behaviors of the two applications. When you change pages in the ordinary HTML application, the browser URL also changes (e.g. from http://localhost:23033/Page1.htm to http://localhost:23033/Page2.htm). After switching the pages, you can use “back” button on your browser to go to the previous page. Also if you want the users to access Page2.htm without accessing Page1 (which is a default page for the application) you can simply give a hyperlink http://localhost:23033/Page2.htm pointing straight to Page2. If you try to switch pages in the SPA, however, you will notice that the URL does not change, back button is not working and there is no way to give the users a straight link to page2. This problem will be addressed shortly in a section of the article dedicated to SPA navigation. Using JQuery UI Tabs for SPA PagesIt looks nicer to have tabs instead of hyperlinks when you want to switch between the pages. JQuery UI tabs can be used for this purpose. JQuery UI is a GUI package built on top of JQuery. You can install it via NuGet in the same fashion as JQuery. The code sample using JQuery UI tabs is located under
TwoPagesSPAWithTabs solution. It consists of Index.htm file as well as
the files from JQuery and JQuery UI packages. Index.htm file contains
reference to a JQuery UI style sheet: Here is the HTML code within Index.htm file: Collapse | Copy Code <body> <ul id="pageTabs"> <!-- hrefs of the links point to the ids of the pages' contents --> <li><a href="#page1">choose page1</a></li> <li><a href="#page2">choose page2</a></li> </ul> <!-- page 1 message colored in red --> <p id="page1" style="font-size:40px;color:red" >This is page 1</p> <!-- page 2 message colored in blue --> <p id="page2" style="font-size:40px;color:blue">This is page 2</p> </body> Note that the The JavaScript code is also very simple: Collapse | Copy Code $(document).ready(function () { $("body").tabs(); // turns the hyperlinks into tabs }); Here is how the application looks: Just like in previous SPA sample, the URL is not connected to the tabs – changing tabs won’t change the URL and changing URL won’t change the tabs. BPF Framework and NavigationHere we present navigation functionality of the BPF framework. Many SPAs use Sammy.js framework for the navigation. Sammy.js allows to map different URL hashes into various JavaScript functions. When SPA has a lot of different navigation states with some possible hierarchy, such mapping might be different to implement. BPF library, however, implements the mapping between the navigation states and the URL hashes naturally and with very little extra code. There is a limitation to the current version of BPF framework, in that it relies on Code for BPF framework is located under BPF folder. It is also available from github.com/npolyak/bpf. The only file you need in order to access all of its functionality is bpf.min.js; so far (in the beginning of December 2012, it is pretty small – about 12Kb). This file was obtained by bundling and minification of other JavaScript files which can also be found in BPF folder and to which I will be referring from time to time. Two Page SPA with NavigationWe’ll start by using BPF functionality to modify the simple two page
SPA with tabs presented above in such a way that it can be navigated.
The sample is located under TwoPageSPAWithNavigation solution. The only
difference between this project and TwoPageSPAWithTabs lies in
JavaScript code at the bottom of Index.html file. In TwoPageSPAWithTabs
project JavaScript code consisted of one line Collapse | Copy Code // get the tabs DOM elements var tabs = $("body").tabs(); // turns the hyperlinks into tabs // JQTabsNavAdaptor is a special constructro that adapts // the JQuery tabs to become usable by the navigation framework var tabsAdaptor = new bpf.nav.JQTabsNavAdaptor(tabs); // create the navigation framework node var tabNode = new bpf.nav.Node(tabsAdaptor); // connect the navigation framework node to the browser's url hash bpf.nav.connectToUrlHash(tabNode); // set the url to correspond to the return bpf.nav.setKeySegmentToHash(tabNode); Do not try to understand it all, since detailed navigation functionality design will be discussed shortly. In short, we use Running the sample shows SPA very similar to TwoPageSPAWithTabs, but the tabs have unique URL mapped to them and when you change the tabs, the URL also changes. Correspondingly “Back” and “Forward” browser buttons now work and switch between the tabs. Also typing “http://localhost:48476/Index.html#page2.” for a URL in a browser, will get you straight to the second tab. A More Complex Example With JQuery TabsHierarchicalSPAWithNavigation sample presents a more interesting of tab hierarchy. The top level tabs contain sub-tabs. Each tab/sub-tab combination maps to its own URL. Try starting the application and playing with the tabs. Here is how the application looks: Pay attention that we show SubPage2 within Page2. This combination corresponds to the URL hash: “#page2.page2SubTab2.”. If we change the tabs, the hash will change accordingly. You can see that the hash always start with ‘#’ and ends with ‘.’
character. The links corresponding to different levels of the
navigation state hierarchy are separated by the period (‘.’) character.
Such links in this sample, match the Here is the code for creating connecting the navigation (again do not try very hard to understand it as we’ll discuss it in the next subsection): Collapse | Copy Code // get the tabs DOM elements var tabs = $("body").tabs(); // turns top level hyperlinks into tabs var page1SubTabs = $("#page1SubTabs").tabs(); // turns page 1 hyperlinks into tabs var page2SubTabs = $("#page2SubTabs").tabs(); // turns page 2 hyperlink into tabs // creates the top level node (JQTabsNavAdaptor is used). var topLevelNode = bpf.nav.getJQTabsNode(tabs); // creates a child node and adds it to top level node // as child of "page1". bpf.nav.addJQTabsChild(topLevelNode, "page1", page1SubTabs); // creates a child node and adds it to top level node // as child of "page2". bpf.nav.addJQTabsChild(topLevelNode, "page2", page2SubTabs); // connect the navigation framework to the browser's url hash bpf.nav.connectToUrlHash(topLevelNode); // set the url to correspond to the current selection pattern return bpf.nav.setKeySegmentToHash(topLevelNode); Detailed Design of the Navigation FunctionalityNavigation functionality is located under “namespace” The purpose of Navigation functionality is to allow the developers to define a number of navigation states within an SPA and map each of the states into a unique browser URL so that when the state changes the URL changes also and vice versa – the URL change triggers the navigation state change. The navigation state is assumed to be hierarchical – there can be a number of states at the top level (e.g. page 1 and page 2 from the previous sample). Each one can have sub-states (sub-pages). Each of the sub-states can have its own sub-states etc. The total navigation state of the application is determined by the unique selection of states at each level (or level states). Each level state maps to a link bound by period (‘.’) characters within the URL hash. It is attached to a link corresponding to the parent level state. The image below depicts a sample of the state hierarchy with the tree links corresponding to the level states and the hash strings shown next to the corresponding end nodes: e.g. Page1/SubPage2 selection will result in hash=”#Page1.SubPage2.”: Each part of the URL’s hash bound by periods we call hash segment. For example hash “#Page1.SubPage2″ has two segments: “Page1″ and “SubPage2″. Each segment maps into the level state selected at that level. At each level no more than one level state can be selected (sometimes, it is convenient to assume that no level state is selected at some level). Navigation states consist of level states. Each navigation node can have several level child states that belong to it. One or none of these level child states may be selected as the current level state. Each of the level states has a string associated with it. This string uniquely identifies that state among the children states of the same node. This string becomes a segment bound by two period characters within the URL’s hash when the level state is selected. The total hash is uniquely determined by the sequence of such segments corresponding to the level states starting from the higher level states and going down to the more refined levels. The main functionality for capturing information about the tree of level states is
Each Collapse | Copy Code public interface ISelectable { // event that fires when a selection changes at the selectable // object's level. // This event is implemented as bpf.nav.SimpleEvent in JavaScript event Action onSelectionChagned; // returns the currently selected key (hashSegment) // if no key is selected, it returns null string getSelectedKey(); // does the selection specified by the key (or hashSegment) void select(string key); // unselects the currently selected key (if any and if the object allows it). void unselect(); } Most entities within JavaScript do not support the above interface so
we have to use an adaptor to adapt the objects we are dealing with to Adaptor contains the object that controls the selection (in this case it is JQuery UI tabs object) and implements Another adaptor built into BPF – a check box adaptor comes with
These two methods provide a way to update the selection within some
selectable objects (e.g. JQuery UI tabs) once the URL’s hash changes
and vice versa – to change the URL once a selection changes within
the View Model Selection ExampleThis section requires some knowledge of Knockoutjs library. You can learn about Knockoutjs by using this link or many other resources including Solar System Animation built with SVG, Knockout and MVVM Pattern. This section’s sample is located under ParamNavigationTest solution.
We have a View Model created by the functionality within the file
StudentViewModel.js file under Scripts/ViewModels directory. It defines
a collection of The View is located within HTML/Index.html file. It provides hyperlinks to the Our task is to provide a unique URL hash for each student – course selection. We can, of course, use the BPF library has a class We use
Here is how we connect the navigation states to the View Model within Index.html file: Collapse | Copy Code // we create the adaptor for the selected student observable var studentLevelObservableAdaptor = new bpf.nav.KoObservableNavAdaptor ( studentVM.selectedStudent, // key to student function function (key) { var foundStudent = _.chain(studentVM.students).filter(function (student) { return student.name === key; }).first().value(); return foundStudent; }, // student to key function function (student) { return student.name; } ); var topLevelNode = new bpf.nav.FactoryNode( studentLevelObservableAdaptor, null, // child node producing function function (key, data) { var childObj = data.getChildObjectByKey(key); if (!childObj) return; // create adapted child object var adaptedChildObj = new bpf.nav.KoObservableNavAdaptor ( childObj.selectedCourse, function (courseKey) { return _.chain(childObj.courses). filter(function (universityCourse) { return universityCourse.courseName === courseKey; }).first().value(); }, function (course) { return course.courseName; } ); // create the node return new bpf.nav.Node( adaptedChildObj ); } ); bpf.nav.connectToUrlHash(topLevelNode); bpf.nav.setKeySegmentToHash(topLevelNode); Cartesian Product NavigationSuppose that your browser is divided into two halves. Each of the halves has tabs. You can select one tab in each of the halves. You also want to assign a URL for every possible tab combination. The resulting space of navigation states will be a Cartesian products of the states within each of the halves of the browser. We can further complicate the task by dividing the browser into more than two parts. Also we can assume that such Cartesian product can occur not only at the top state, but at any state level. SimpleProductNavigationTest solution contains precisely the scenario we described in the beginning of this section. The browser page is divided into two parts. Each part has tabs. We record every combination of tab selections in both parts of the page: Note that total URL hash for on the figure above is “#(topics/TopicA)(othertopics/SomeOtherTopicA).”. The parts of the hash corresponding to the components of the Cartesian product are placed within a parenthesis. The part of the hash within a parenthesis starts with a key that uniquely identifies that part within the Cartesian product. The key is separated from the rest of the string within the parenthesis by a forward slash. We use Collapse | Copy Code // create topics JQuery UI tabs var topics = $("#MyTopics").tabs(); // create otherTopics tabs var otherTopics = $("#SomeOtherTopics").tabs(); // top level node is a product node for // the Cartesian product of the states var topLevelNode = new bpf.nav.ProductNode(); // add "topics" node to be a child of topLevelNode under key "topics" bpf.nav.addJQTabsChild(topLevelNode, "topics", topics); // add "otherTopics" node to be a child of topLevelNode under key "othertopics" bpf.nav.addJQTabsChild(topLevelNode, "othertopics", otherTopics); // create the one to one relationship between the states and the URL bpf.nav.connectToUrlHash(topLevelNode); // change the original URL to be based on the navigation states bpf.nav.setKeySegmentToHash(topLevelNode);
A considerably more complex example can be found in ComplexProductNavigationTest solution. It involves a long sequence of tabs within tabs with Cartesian products occurring at two levels – the top one and under TopicA tab. Here is how the SPA looks: The total hash part of the URL for the figure above is “#(topics/TopicA.(a1subs1/A1Subtopic1.A1Sub1Sub2)(a1subs2/A2Subtopic2))(othertopics/SomeOtherTopicA).”. You can play with the application to see that the browser navigation buttons are working indeed. Here is the HTML code of the application: Collapse | Copy Code <table> <tr> <td style="vertical-align: top"> <div id="MyTopics"> <ul> <li><a href="#TopicA">TopicA</a></li> <li><a href="#TopicB">TopicB</a></li> </ul> <div id="TopicA"> My topic A <table> <tr> <td style="vertical-align: top;"> <div id="A1Subtopics"> <ul> <li><a href="#A1Subtopic1">A1Sub1</a></li> <li><a href="#A1Subtopic2">A1Sub2</a></li> </ul> <div id="A1Subtopic1"> A1 Sub Topic1 <div id="A1Sub1Sub"> <ul> <li><a href="#A1Sub1Sub1">A1S1S1</a></li> <li><a href="#A1Sub1Sub2">A1S1S2</a></li> </ul> <div id="A1Sub1Sub1">A1 Sub1 Sub1</div> <div id="A1Sub1Sub2">A1 Sub1 Sub2</div> </div> </div> <div id="A1Subtopic2">A1 Sub Topic2</div> </div> </td> <td style="vertical-align: top;"> <div id="A2Subtopics"> <ul> <li><a href="#A2Subtopic1">A2Sub1</a></li> <li><a href="#A2Subtopic2">A2Sub2</a></li> </ul> <div id="A2Subtopic1">A2 Sub Topic1</div> <div id="A2Subtopic2">A2 Sub Topic2</div> </div> </td> </tr> </table> </div> <div id="TopicB"> The Topic B </div> </div> </td> <td style="vertical-align: top"> <div id="SomeOtherTopics"> <ul> <li><a href="#SomeOtherTopicA">AnotherA</a></li> <li><a href="#SomeOtherTopicB">AnotherB</a></li> </ul> <div id="SomeOtherTopicA">Some Other A </div> <div id="SomeOtherTopicB" style="background-color: pink">Some Other B</div> </div> </td> </tr> </table> And here is the JavaScript code within Collapse | Copy Code // create topics JQuery UI tabs var topics = $("#MyTopics").tabs(); // create otherTopics tabs var otherTopics = $("#SomeOtherTopics").tabs(); var A1Subtopics = $("#A1Subtopics").tabs(); var A2Subtopics = $("#A2Subtopics").tabs(); var A1Sub1Sub = $("#A1Sub1Sub").tabs(); // top level node is a product node for // the Cartesian product of the states var topLevelNode = new bpf.nav.ProductNode(); // add "topics" node to be a child of topLevelNode under key "topics" var topicsNode = bpf.nav.addJQTabsChild(topLevelNode, "topics", topics); // add "otherTopics" node to be a child of topLevelNode under key "othertopics" bpf.nav.addJQTabsChild(topLevelNode, "othertopics", otherTopics); var aSubtopicsProductNode = new bpf.nav.ProductNode(); topicsNode.addChildNode("TopicA", aSubtopicsProductNode); var A1SubNode = bpf.nav.addJQTabsChild(aSubtopicsProductNode, "a1subs1", A1Subtopics); bpf.nav.addJQTabsChild(aSubtopicsProductNode, "a1subs2", A2Subtopics); bpf.nav.addJQTabsChild(A1SubNode, "A1Subtopic1", A1Sub1Sub); // create the one to one relationship between the states and the URL bpf.nav.connectToUrlHash(topLevelNode); // change the original URL to be based on the navigation states bpf.nav.setKeySegmentToHash(topLevelNode); Using BPF Framework for SPA CompositionAs I mentioned in Introduction, SPA might result in large HTML files due to the fact that all its pages are loaded together and switching the pages simply means that parts of HTML change their visibility. BPF framework provides a way to break HTML functionality into smaller files (called BPF plugins or simply plugins) and assemble all of them together on the client side. It also allows the plugins to refer to some other plugins creating a plugin hierarchy. Moreover, you can place JavaScript code dealing with the functionality provided by the plugin into the same HTML file and later call this functionality either during the composition or at a later stage. This was my attempt to imitate the WPF/Silverlight code-behind concept within HTML/JavaScript universe. All of the BPF composition related functionality is located within Composite.js file and it relies heavily on JQuery. Simple Plugin SampleLet us take a look at the sample under SimpleCompositionSample project. HTML directory of this project contains two html files Index.html – the main file and APlugin.html – a file containing the plugin code. To start the application, right click on Index.html file within Solution Explorer and choose “View in Browser” option. Here is the HTML code within Index.html file: Collapse | Copy Code <div style="font-size:30px;color:red">This is the main Module</div> <img id="busyIndicator" src="../Images/busy_indicator.gif" style="vertical-align:central;margin-left:50%" /> <!-- plugin will get into this div below --> <div id="APluginContainer1"></div> <!-- call plugin's function to change its color to 'blue' for the plugin above --> <button id="changePluginColorButton1">Change 1st Plugin Text to Blue</button> <!-- plugin will get into this div below --> <div id="APluginContainer2" style="margin-top:40px"></div> <!-- call plugin's function to change its color to 'blue' for the plugin above --> <button id="changePluginColorButton2">Change 2nd Plugin Text to Blue</button> The only text visible within main HTML file is “This is the main Module”. There are two <div> tags for inserting plugin content: “APluginContainer1″ and “APluginContainer2″. Each one of them has a button under it that calls the plugin’s code-behind to change the color of the text of the corresponding plugin instance to blue. You may notice that the same plugin is being inserted into two places within the main module. Here is the JavaScript code of Index.html: Collapse | Copy Code // this event will fire after all the plugins and their // descendant plugins are loaded var compositionReady = new bpf.utils.EventBarrier(); // the composition ready event fires after everything all the plugins // and their descendants have been loaded into the main module. compositionReady.addSimpleEventHandler(function (success) { $("#busyIndicator").hide(); $("#changePluginColorButton1").click(function () { // after changePluginColorButton1 is clicked, the // the function changeColorBackToBlue defined within the plugin // will be called and will only affect APluginContainer1 bpf.control("#APluginContainer1").call("changeColorToBlue"); }); // after changePluginColorButton2 is clicked, the // the function changeColorBackToBlue defined within the plugin // will be called and will only affect APluginContainer2 $("#changePluginColorButton2").click(function () { bpf.control("#APluginContainer2").call("changeColorToBlue"); }) }); // gets the plugin from file APlugin.html and inserts it into the // element pointed to by the selector "#APluginContainer1" bpf.cmpst.getPlugin("APlugin.html", null, "#APluginContainer1", compositionReady); // gets the plugin from file APlugin.html and inserts it into the // element pointed to by the selector "#APluginContainer2" bpf.cmpst.getPlugin("APlugin.html", null, "#APluginContainer2", compositionReady); The two Collapse | Copy Code bpf.control("#APluginContainer1").call("changeColorToBlue"); The function Now, let us take a look at the plugin code: Collapse | Copy Code <div id="aPlugin" style="font-size:25px"> This is a plugin </div> <!--script tag should be marked by data-type="script-interface" in order for it to be recognized as containing the plugin's 'code-behind' --> <script type="text/javascript" data-type="script-interface"> (function () { // this function returns the plugin's 'code-behind' - // a JSON object consisting the functions. Two function names are // reserved "preRender" and "postRender" - the first executes // before the plugin is inserted into the parent module's DOM // the second executes after the plugin is inserted into the parent's // module dome. // other functions can be called at any later stage - at the developer's will // 'this' object for every function except for preRender contains the parameters // of the element into which this plugin attached. The most important parameter is // currentDOM - the DOM of the parent element. // All the JQuery selectors acting within the plugin should start with // this.currentDOM.find(... to make sure that we are only modifying our instance // of the plugin and not some other instances. // The other important field within "this" object is "codeBehind". It gives // access to the code-behind function returned below. // Note that all the function names should be in quotes in order for eval method // to work at the moment when the plugin is inserted into the plugin cache. return { "postRender": function (compositionReadyEventBarrier) { // change color to blue this.currentDOM.find("#aPlugin").css("color", "green"); }, "changeColorToBlue": function () { // change the color to blue this.currentDOM.find("#aPlugin").css("color", "blue"); } }; })(); </script> The HTML of the plugin simply shows text “This is a plugin”. The <script> tag marked with The code-behind <script> tag contains an anonymous function
that returns a JSON object defining various methods. There are two
predefined code-behind methods that are called (if they exist) when the
plugin is loaded into the main module: All the code-behind methods except for Important Note: if you want to find a DOM element belonging to a plugin within the code-behind you should do it via a call to The Code-behind’s method Here is how we call the Collapse | Copy Code bpf.control("#APluginContainer1").call("changeColorToBlue"); When you run the application you will get the text for both instances of the plugin colored in green. When you click the button under the corresponding plugin instance that plugin instance will turn blue, while the other stays the same color. Here is the image of the application after the top plugin instance’s button was clicked: The text of the top plugin instance changed to blue, while the text of the bottom plugin instance stayed green. Chain of the Plugins Composition SampleChainOfPluginsCompositionSample solution contains a sample where the main module loads a plugin, which, in turn load another plugin we call it sub-plugin. All the HTML files of the sample are located under HTML folder. Index.html is the file containing the main module. You can start the application by right clicking on it and choosing “View in Browser” option. Here is the image of the application once it starts: The buttons change the color of the text of the plugin and sub-plugin correspondingly. The code of Index.html file does not contain anything new in comparison to the previous sample. Most “interesting” code is located within APlugin.html file: Collapse | Copy Code <div id="aPlugin" style="font-size:25px"> This is a plugin <div id="subPluginContainer"></div> <Button id="changePluginColorButton">Change Plugin Color to Blue</Button> <Button id="changeSubPluginColorButton">Change SUB Plugin Color to Black</Button> </div> <script src="../Scripts/jquery-1.8.3.js"></script> <script src="../Scripts/BPF/bpf.js"></script> <script type="text/javascript" data-type="script-interface"> (function () { return { "postRender": function (compositionReadyEventBarrier) { var self = this; // change color to green self.currentDOM.find("#aPlugin").css("color", "green"); // create a child event barrier - it will fire // once the sub-plugin and all of its // descendants are loaded. // And the parent event barrier won't fire until it fires. var subCompositionReady = compositionReadyEventBarrier.createChildEventBarrier(); subCompositionReady.addSimpleEventHandler(function () { // changes the color of the plugin itself to blue. $("#changePluginColorButton").click(function () { self.currentDOM.find("#aPlugin").css("color", "blue"); }); // on changeSubPluginColorButton click call the sub-plugin's // method changeColorToBlack $("#changeSubPluginColorButton").click(function () { bpf.control("#subPluginContainer", self).call("changeColorToBlack"); }); }); // get sub-plugin note that you need to pass 'this' object // as the second argument to getPlugin function bpf.cmpst.getPlugin("ASubPlugin.html", self, "#subPluginContainer", subCompositionReady); } }; })(); </script> Note that when we call Composition and Navigation SampleCompositionAndNavigationSample solution shows how to combine BPF
composition and navigation. We create two tabs at the main module
level. We also have tabs within a plugin. The plugin is added to the
content of one of the tabs within the main module. We use the Collapse | Copy Code <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link href="../Content/themes/base/jquery-ui.css" rel="stylesheet" /> <title></title> </head> <body> <!-- links to be converted to tabs --> <ul id="pageTabs"> <li><a href="#page1">Page1</a></li> <li><a href="#page2">Page2</a></li> </ul> <!-- page 1 message colored in red --> <div id="page1" style="color:red" > This is page 1 <div id="pluginContainer"></div> </div> <!-- page 2 message colored in blue --> <div id="page2" style="color:blue">This is page 2</div> </body> </html> <script src="../Scripts/jquery-1.8.3.min.js"></script> <script src="../Scripts/jquery-ui-1.9.2.min.js"></script> <script src="../Scripts/BPF/bpf.js"></script> <script> $(document).ready(function () { // create the tabs, store a reference to the tabs. var topLevelTabs = $("body").tabs(); // create the top level bpf.nav.Node object around the tabs. var topLevelNode = bpf.nav.getJQTabsNode(topLevelTabs); var compositionReady = new bpf.utils.EventBarrier(); compositionReady.addSimpleEventHandler(function () { // this function is called after all the plugins are loaded (rendered) // we call "connectToParentNode" function on the plugin // passing the topLevelNode to it, in order to connect // the plugin's tabs to the bpf navigation framework. bpf.control("#pluginContainer").call("connectToParentNode", topLevelNode); // connect the navigation framework with the URL's hash bpf.nav.connectToUrlHash(topLevelNode); // update the current URL bpf.nav.setKeySegmentToHash(topLevelNode); }); // get the plugin bpf.cmpst.getPlugin("APlugin.html", null, "#pluginContainer", compositionReady); }); </script> To connect the plugin’s navigation node to that of the main module, we call function Collapse | Copy Code bpf.control("#pluginContainer").call("connectToParentNode", topLevelNode); Here is the plugin’s code (from APlugin.html file): Collapse | Copy Code <div id="subTabPlugin"> <ul id="subTabs"> <li><a href="#subPage1">SUB Page1</a></li> <li><a href="#subPage2">SUB Page2</a></li> </ul> <!-- page 1 message colored in red --> <div id="subPage1" style="color:green" >This is SUB page 1</div> <!-- page 2 message colored in blue --> <div id="subPage2" style="color:purple">This is SUB page 2</div> </div> <script src="../Scripts/jquery-1.8.3.min.js"></script> <script src="../Scripts/jquery-ui-1.9.2.min.js"></script> <script src="../Scripts/BPF/bpf.js"></script> <script type="text/javascript" data-type="script-interface"> (function () { var pluginTabs; return { "postRender": function (compositionReadyEventBarrier) { // create tabs within the plugin and store the // tab object to be used later pluginTabs = this.currentDOM.find("#subTabPlugin").tabs(); }, "connectToParentNode": function (parentNode) { // create the navigation node at the plugin level and // connect it with the parent navigation node. bpf.nav.addJQTabsChild(parentNode, "page1", pluginTabs); } }; })(); </script> The method Connecting to the parent’s navigation node is taken care of by the method Parameterized PluginsParameterizedPluginSample shows how to create instances of the same plugin that differ in their looks. Just like in SimpleCompositionSample, two instances of the same plugin are inserted into the main module contained within Index.html file: Collapse | Copy Code // gets the plugin from file APlugin.html and inserts it into the // element pointed to by the selector "#APluginContainer1" bpf.cmpst.getPlugin( "APlugin.html", null, "#APluginContainer1", compositionReady, { fontSize: "50px", color: "blue" } ); // gets the plugin from file APlugin.html and inserts it into the // element pointed to by the selector "#APluginContainer2" bpf.cmpst.getPlugin( "APlugin.html", null, "#APluginContainer2", compositionReady, { // pass the object containing postRenderArguments fontSize: "20px", color: "green" } ); The last argument to Collapse | Copy Code { "postRender": function (compositionReadyEventBarrier) { var fontSize = this.postRenderArguments.fontSize; // get font size from the arguments var color = this.postRenderArguments.color; // get color from the arguments this.currentDOM.find("#aPlugin").css("font-size", fontSize); this.currentDOM.find("#aPlugin").css("color", color); } } As a result we have the same plugin text displayed with different font-size and color: The top plugin instance has font size of 50px and blue color, while the bottom one - 20px and green color. Generic Silverlight Plugin SampleHere I describe a generic BPF plugin for Silverlight applications. Silverlight apps are usually packaged as one file with .xap extension. In order to embed a Silverlight app into a page, you have to have the page reference Silverlight.js file (which comes from Microsoft). You also have to write the following HTML code within your HTML application: Collapse | Copy Code This is a large chunk of HTML code and my idea was to create a BPF parameterized plugin for re-using it in multiple places within HTML applications. One of the parameters of the BPF plugin will be, of course, the Silverlight app’s URL. Other parameters might be needed for positioning the application, e.g. width, height, margins. You would probably want to know why Silverlight plugin is different
from any other BPF plugin. Why can’t we simply create a parameterized
plugin using the information from the previous subsection? My answer
is “redirect your question to Microsoft”. The <object> tag behaves
in a very strange way in conjunction with JQuery on IE8 and IE9 –
trying to use JQuery to parse the DOM of the object tag totally
mangles it. Besides, from my experience, the Silverlight app URL has to
be set before the HTML code is inserted into the main module – IE won’t
change the Silverlight application when the Silverlight URL changes if
the code has already been inserted. In fact it is because of these
issues that I added The code for this sample is located under SilverlighPluginSample solution. Here is what you get if you run the application – (hey, after a week of toiling on this article I can allow myself a bit of self promotion – AWebPros.com is my company): To get around the issues with Silverlight plugin that I describe
above, we change the plugin code substituting <object> tag for
<myobject>. Also in order to place the URL parameter in the
correct place, we use “___XAPFilePlaceHolder___” string as a
placeholder. The substitution of these strings by the correct ones
takes place within Here is the code within SilverlightContainerPlugin.html file: Collapse | Copy Code <div> <myobject type="application/x-silverlight-2" style="display: block; text-align: center; width: 100%; height: 100%"> <param name="source" value="___XAPFilePlaceHolder___" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="5.0.61118.0" /> <param name="autoUpgrade" value="true" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration: none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </myobject> </div> <script src="../Scripts/jquery-1.8.2.js"></script> <script type="text/javascript" data-type="script-interface"> (function () { return { "preRender": function (preRenderArgs) { // get original html of the plugin var originalHtml = this.getDownloadedHtml() // replace "myobject" string with "object" and // ___XAPFilePlaceHolder___ with the Silverlight app url parameter. var modifiedHtml = originalHtml.replace(/myobject/gi, "object").replace("___XAPFilePlaceHolder___", preRenderArgs.slAppUrl); // replace the HTML code of the plugin this.setDownloadedHtml(modifiedHtml); }, "postRender": function () { var args = this.postRenderArguments; var slContainerDiv = this.currentDOM.find(".slContainerDiv"); // position the plugin if (args) { slContainerDiv.css("margin-top", args.marginTop); slContainerDiv.css("margin-bottom", args.marginBottom); slContainerDiv.css("width", args.width); slContainerDiv.css("height", args.height); } }, } })(); </script> Here is how the plugin is inserted within the main module: Collapse | Copy Code bpf.cmpst.getPlugin( "SilverlightContainerPlugin.html", this, "#AWebProsLogo", compositionReady, { // post-render args marginTop: "auto", marginBottom: "auto", width: "150px", height: "150px" }, { // pre-render args slAppUrl: "../ClientBin/AnimatedBanner.xap" } ); This plugin is not part of BPF library (which consists only of JavaScript files) but it can be very useful and as such it is published on github.com/npolyak/bpf/tree/master/BPF/UsefulBPFPlugins SPA Server Communications Using ASP.NET MVCHere we show how SPA can communicate with the ASP.NET MVC server. Unlike the previous two sections, this section does not contain anything new – it is simply a tutorial providing a number of different examples of SPA communicating with the server. Simple GET Request Sample Returning String from the ServerAs was mentioned in Introduction, once the SPA is running, it should only load string or JSON data for the application and not the HTML code. A very simple example of an SPA sending and getting some string data from an ASP server can be found under SPAServerStringCommunications solution. To start the solution, right mouse button click on Index.html file and choose “View in Browser”. Here is how the application looks after it is started: After you enter your name into the editable area and click “Get Server String” button the browser will send your name to the server and receive a string “Hello <yourname>” from the server and display above the button in red: SPAServerStringCommunications project was created as ASP.NET MVC 4 empty project. After the project was created, I removed Model and Views folders and added a “Hello” controller to the Controllers folder. I also removed all the scripts from the Scripts folder and installed JQuery as a NuGet package.
Collapse | Copy Code public ActionResult GetHelloMessage(string name) { // AllowGet flag states that the method can be accessed // by GET HTTP request. return Json("Hello " + name, JsonRequestBehavior.AllowGet); } In this case The relative URL to The project’s HTML/JavaScript client is located within Index.html file. Here is the HTML part of the client code: Collapse | Copy Code <body> <div>Enter name</div> <!-- name input --> <input id="nameInput" type="text" name="value" style="width:200px" /> <!-- div to display the text returning from the server --> <div id="serverText" style="min-height:50px;color:red;margin-top:10px"></div> <!-- button to trigger communication with the server --> <button id="getHelloStringButton">Get Server String</button> </body> And here is the JavaScript: Collapse | Copy Code $(document).ready(function () { $("#getHelloStringButton").click(function () { // on button click // get name value var name = nameInput.value; // send query string to the server. // /hello/gethellomessag is the relative url // second argument is the query string // 3rd argument is the function called on successful reply from the server $.get("/hello/gethellomessage", "name=" + name, function (returnedMessage) { // write the text coming fromt he server into // serverText element. $("#serverText").text(returnedMessage); }); }); }); JavaScript code uses JQuery’s In general, when a GET query has multiple arguments, the query should be built as GETting a Complex Object from the ServerIn the previous sample, we sent a string to the server to get a string back. SPAComplexObjectGetter project returns a JSON object with some structure to it in response to a GET HTTP request. To run the project, open it in Visual Studio right mouse click on Index.html file in Solution Explorer and choose “View in Browser”. Here is what you will see after clicking button “Get Cinema Info”: Unlike the previous sample, SPAComplexObjectGetter project has a non-empty Models folder with two classes in it: “Controllers” folder contains DataController.cs file with only one method: Collapse | Copy Code public ActionResult GetCinema() { // create a cinema object populated with data Cinema cinema = new Cinema(); // send it in JSON form back to the client return Json(cinema, JsonRequestBehavior.AllowGet); } The relative URL to call method Now let us look at the client code within Index.html file. HTML code is very simple consisting of a Collapse | Copy Code <body> <div id="cinemaInfo" style="margin-bottom:20px"></div> <Button id="getCinemaInfoButton">Get Cinema Info</Button> </body> JavaScript code is more complex, but just like the code of the previous sample, it uses JQuery function Collapse | Copy Code $(document).ready(function () { $("#getCinemaInfoButton").click(function () { // on button click // send query string to the server. // /hello/gethellomessag is the relative url // second argument an empty string since our query does not have parameters // 3rd argument is the function called on successful reply from the server $.get("/data/getcinema", "", function (cinema) { // clear the info displayed from // the previous click (if any). $("#cinemaInfo").contents().remove(); // add cinema information to "cinemaInfo" div element $("#cinemaInfo").append("Name: " + cinema.Name); $("#cinemaInfo").append("<div></div>"); $("#cinemaInfo").append("Description: " + cinema.Description); $("#cinemaInfo").append("<div style='margin-top:5px'></div>"); $("#cinemaInfo").append("Movies:"); $("#cinemaInfo").append("<div></div>"); // add information about individual movies for (var idx = 0; idx < cinema.Movies.length; idx++) { var movie = cinema.Movies[idx]; $("#cinemaInfo").append ( " " + "Title: " + movie.Title + ", " + "year: " + movie.Year ); $("#cinemaInfo").append("<div></div>"); } }); }); }); The query part of the function The object returned from the server is represented by variable You can view the JSON object returned from the server by opening a
browser e.g. Chrome and typing the URL to the controller function POSTing Complex Data Object to the ServerGET requests presented in the two previous samples build the query as part of the URL and as such GET requests are perfect when an object you want to send a set of names and values to the server. When a complex JSON object needs to be transferred from the client to the server, POST request should be utilized. In this sub-section we will consider the same This sub-section’s sample is located under SPA_POSTingObjectToServer solution. The server has the same model classes: To cover the case of the server failure, I also made the server
request fail every other time. To mark the failure, the server changes
the Collapse | Copy Code static bool evenRequest = true; // url=/data/changecinemadata public ActionResult ChangeCinemaData(Cinema cinema) { evenRequest = !evenRequest; // report error on every even request if (evenRequest) { Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; return Json("serverError"); } // add movie "Anne of Planet Mars" // to Cinema data coming from the client // and return the modified Cinema data // back to the client cinema.Movies.Add ( new Movie { Title = "Anne of Planet Mars", Year = 3000 } ); return Json(cinema); } Note, that the server will interpret the data coming from the client as an object of type The client code is located in Index.html file. HTML consist of two Collapse | Copy Code <body> <!-- Here we place the original cinema data--> <div id="originalCinemaInfo" style="margin-bottom:20px"></div> <!-- clicking this button sends the cinema object to the server and places the result returning from the server under serverCinemaInfo tag --> <Button id="changeCinemaInfoFromServerButton">Change Cinema Info via Server</Button> <div style="color:blue;margin-top:20px">Reply from the Server:</div> <!-- here we create a visual representation for Cinema object coming from the server --> <div id="serverCinemaInfo" style="margin-bottom:20px;color:Red"> </div> </body> Here is the JavaScript code: Collapse | Copy Code $(document).ready(function () { // we create a Cinema object on the client var cinema = { Name: "Mohawk Mall Cinema", Description: "An OK Cinema", Movies: [ { Title: "Anne of Green Gables", Year: 1985 }, { Title: "Anne of Avonlea", Year: 1987 } ] }; // display the visual representation of the original // cinema object displayCinemaInfo($("#originalCinemaInfo"), cinema); var cinemaJsonString = JSON.stringify(cinema); $("#changeCinemaInfoButton").click(function () { $.ajax({ type: "POST", dataType: "json", contentType: "application/json; charset=utf-8;", url: "/data/changecinemadata", data: cinemaJsonString, success: function (changedCinemaFromServer) { // display the visual representation of the server modified // cinema object displayCinemaInfo($("#serverCinemaInfo"), changedCinemaFromServer); }, error: function (resultFromServer) { // clear the previous contet of serverCinemaInfo element $("#serverCinemaInfo").contents().remove(); // display the error message $("#serverCinemaInfo").append("Server Error"); } }); }); }); We use generic The data we send within the message body is our Here is how the SPA looks after successful reply from the server: and here is how it looks in case of failure:
SummaryThis article talks about the Single Page Applications (SPAs). We define the SPA and present numerous SPA samples. All the information and functionality within the article is something I wished I knew and had several months ago when I just started building the SPAs. This article introduces a new JavaScript library called BPF (Browser Presentation Foundation). This library is used for two purposes:
Eventually, I hope that the BPF library will include a lot of other functionality. Thank you |