Advertisement
jbpellerin

darklight1

Mar 1st, 2012
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 5.72 KB | None | 0 0
  1. module darklight.jbmain;
  2. import std.stdio;
  3. import std.algorithm : splitter;
  4. import std.process : environment;
  5.  
  6. //darklight base module and some utilities
  7. import darklight.controls;
  8. import darklight.sql;
  9. import darklight.document;
  10. import darklight.parse;
  11. //These two could be public imports in darklight.controls I think, gave you the option to leave them out though
  12. import darklight.stackpanel;
  13. import darklight.tab;
  14.  
  15. //Creates this module's control factory - this allows for dependency injections
  16. //(Grid containing LeftPanel for example, even though that would otherwise be a circular reference)
  17. mixin FactoryGen!("darklight.jbmain",
  18. "jbm:darklight.jbmain;",        //defines the alias jbm for darklight.jbmain
  19. "LeftPanel:jbm.LeftPanel;
  20. ContentPanel:jbm.ContentPanel;",    //aliases this module's Controls for easier usage
  21. darklight.controls);            //imports the aliases defined in darklight.controls
  22.  
  23. //nothing is stopping these ViewModels from being classes, in fact it's probably better if they are
  24. struct ContentTab
  25. {
  26.     string title;
  27.     string content;
  28. }
  29. struct MainVM
  30. {
  31.     ContentTab[] tabs;
  32. }
  33.  
  34. //xaml to be sent to the factory
  35. //Doesn't need it's own Control class since it's top-level, but could have one if you wanted
  36.     //1fr in the ColumnDefinition is the equivalent to 1* in xaml, this is css3 grid syntax
  37.     //css3 grids are emulated in js for this since the only browser to support them only runs on windows 8
  38. enum string _mainPanel =
  39. "<Grid width={{`100%`}} height={{`100%`}}>
  40.     <GridDefinition>
  41.         <RowDefinition height={{`100%`}}/>
  42.         <ColumnDefinition width={{`400px`}}/>
  43.         <ColumnDefinition width={{`1fr`}}/>
  44.         <ColumnDefinition width={{`500px`}}/>
  45.     </GridDefinition>
  46.     <LeftPanel xname={{`Lefty`}}
  47.         grid.column={{1}}/>
  48.     <ContentPanel grid.column={{2}}/>
  49.     <StackPanel xname={{`RightStack`}}
  50.         grid.column={{3}}>
  51.         <TextBlock xname={{`CompanyHeader`}}
  52.             text={{`Darklight corporation (not a real corporation)`}}/>
  53.     </StackPanel>
  54. </Grid>";
  55.  
  56. //This is the left panel on the site, contains a form, with a textbox and button, and a textblock
  57. //The targetElement/replace functionality of the form is contrived, to show ajax passing can be done but what it does with it sucks
  58. class LeftPanel : StackPanel
  59. {
  60.     enum string _xmlstring =
  61. "<StackPanel>
  62.     <Form xname={{`form1`}}
  63.           url={{`jbmain.dl`}}
  64.           targetElement={{`placeholder1`}}>
  65.         <TextBox xname={{`inputText1`}} text={{`default string`}}/>
  66.         <Button text={{`Button!!`}}/>
  67.     </Form>
  68.     <TextBlock xname={{`placeholder1`}}/>
  69. </StackPanel>";
  70.        
  71.     string content()
  72.     {
  73.         //The html generated will have a string concatenated to it, it's non-breaking in this example but be careful to still return valid xhtml
  74.         return super.content() ~ "I snuck in a string!";
  75.     }  
  76.  
  77.     //To make this be a Control with it's own xaml - This performs code generation that extracts bindings and sub-elements
  78.     mixin Control.extractgen!(_xmlstring);
  79. }
  80.  
  81. class ContentPanel : TabMenu
  82. {
  83.     //The first exciting piece of xaml, it has bindings!
  84.     //viewModel is the VM that can be bound
  85.     //in the TextBlock case, this.text=viewModel.title will get added during compile-time to the code that generates the content, so that at run-time the text will be set according to the viewModel
  86.     //binding=viewModel.tabs is a ListPanel feature, ListPanel repeats the inner xaml content for all elements in a provided range (not range as in 1-10, range as in array datatype)
  87.         //the controls inside the ListPanel from that point on will now have their viewModels each representing one of the tabs. So the ViewModel for the ListPanel is not the same as the one for the TabPage
  88.         //binding is a variable that can be assigned to, that will set the viewModel of controls nested in a given control
  89.         //In this case there is additional behaviour in that inner controls only get an element of binding instead of the whole array, but that is a feature of the ListPanel.
  90.     //the overflow Control just defines expander behaviour, int this case a scroll-bar would appear if the content got too large
  91.         //The TextBlock inside the Overflow has the same ViewModel depth as the other one. That is, their viewModels are the same ContentTab.
  92.     enum string _xmlstring =
  93. "<TabMenu xname={{`ContentTabs`}}>
  94.     <ListPanel binding={{viewModel.tabs}}>
  95.         <TabPage>
  96.             <TextBlock text={{viewModel.title}}/>
  97.             <Overflow behaviour={{Behaviour.automatic}}>
  98.                 <TextBlock text={{viewModel.content}}/>
  99.             </Overflow>
  100.         </TabPage>
  101.     </ListPanel>
  102. </TabMenu>";
  103.    
  104.     mixin Control.extractgen!(_xmlstring);
  105. }
  106.  
  107. void main(string[] args)
  108. {
  109.     //stupid handler for ajax calls
  110.     //eventually I'll flesh this out into full rpc's using mixin templates to make code generation automatic
  111.     if (environment.get("REQUEST_METHOD", "GET") == "POST")
  112.     {
  113.         handleAjax();
  114.         return;
  115.     }
  116.    
  117.     MainVM mvm;
  118.    
  119.     auto db = db_open("db1.s3db"); //to ppoulate the vm's tabs
  120.     record[] records = db_execute(db, "SELECT * FROM table1");
  121.    
  122.     db_close(db);
  123.     foreach(rec; records)
  124.     {
  125.         ContentTab tab;
  126.         tab.title=rec.data["id"];
  127.         tab.content=rec.data["name"];
  128.         mvm.tabs ~= tab;
  129.     }
  130.  
  131.     auto control = darklight_jbmainFactory.BuildControl!(_mainPanel)(mvm, mvm);
  132.     Document doc = new Document("My first webpage", "cgi-bin/", control);
  133.     doc.filenames = "ut/site1";
  134.    
  135.     writeln(doc.content);
  136.     doc.prepare();
  137. }
  138.  
  139. void handleAjax()
  140. {
  141.     //This method just returns the environment variables from the POST call, removing the first one which is a darklight message
  142.     writeln("Content-type: text/plain;\n\n");
  143.    
  144.     string reqs = environment.get("QUERY_STRING","");
  145.     auto reqargs = splitter(reqs, "&");
  146.     reqargs.popFront();
  147.     string[string] vals;
  148.    
  149.     foreach(req; reqargs)
  150.     {
  151.         auto split = splitter(req, "=");
  152.         vals[split.front] = split.back;
  153.     }
  154.    
  155.     writeln("request received : ", vals);
  156.     return;
  157. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement