Source of file NLView.php
Size: 9,986 Bytes - Last Modified: 2021-12-23T10:05:39+00:00
/var/www/docs.ssmods.com/process/src/code/NLView.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 | <?php /** * NLView represents an area on a page or a view which is to provide a component based presentation. It is capable * of rendering itself in a template. All you need to give it is the serialised component hierarchy and the context * for binding. */ class NLView extends Controller { // static $allowed_methods = ( // 'EditForm' // ); /* * @config */ private static $layout_manager_class = null; protected $layout = null; protected $rawComponents; protected $context; protected $layoutManager; static $default_view_contents = '{ "ClassName": "NLLayoutContainer", "children": [ ], "bindings": { } }'; // This should really be in the test suite. static $default_view_contents_alt = '{ "ClassName": "NLLayoutContainer", "children": [ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "This is some <em>HTML</em> text (embedded)." } } }, { "ClassName": "NLLinkComponent", "bindings": { "ExternalURL": { "type": "embedded", "value": "http://disney.com" } }, "children": [ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "an external link using embedded binding" } } } ] }, { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "context", "value": "GetFoo" } } } ], "bindings": { } }'; // This should really be in the test suite. static $default_view_contents_alt2 = '{ "ClassName": "NLLayoutContainer", "children": [ { "ClassName": "NLVerticalBoxLayout", "children": [ { "ClassName": "NLHorizontalBoxLayout", "children": [ { "ClassName": "NLLinkComponent", "bindings": { "ExternalURL": { "type": "embedded", "value": "http://disney.com" } }, "layout": { "classes": [ "col-md-4" ] }, "children": [ { "ClassName": "NLImageComponent", "bindings": { "InternalImage": { "type": "embedded", "value": "Image:1" }, "ResizingOption": { "type": "embedded", "value": "Resized" }, "Width": { "type": "embedded", "value": "60" }, "Height": { "type": "embedded", "value": "40" } } } ] }, { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "This is some embedded text that should appear to the right of the image." } }, "layout": { "classes": [ "col-md-8" ] } } ] }, { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "Here is some text that should be displayed below the image and other text" } } } ], "bindings": { } } ], "bindings": { } }'; static $default_view_contents_old = '{ "ClassName": "NLVerticalBoxLayout", "children": [ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "this is some text that is encoded for json and can contain HTML" } } }, { "ClassName": "NLLinkComponent", "bindings": { "ExternalURL": { "type": "embedded", "value": "http://disney.com" } }, "children": [ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "my favourite website (external)" } } } ] }, { "ClassName": "NLLinkComponent", "bindings": { "InternalPage": { "type": "embedded", "value": "SiteTree:2" } }, "children": [ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "my favourite website (internal)" } } } ] }, { "ClassName": "NLCanvasLayout", "children":[ { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "canvas child 1" } }, "layout": { "top":"10px", "height":"15px", "width":"20px" } }, { "ClassName": "NLTextComponent", "bindings": { "Text": { "type": "embedded", "value": "canvas child 2" } } } ], "layout": { "height":"75px", "width":"150px" } } ], "bindings": { } }'; // Helper function that given a serialised form, returns it cleaned. Specifically, if it is not defined, returns // the default, and also strips '(' and ')' wrapper if present. static function normalise_serialised($serialised) { if (!$serialised) { $serialised = self::$default_view_contents; } while (substr($serialised, 0, 1) == '(') { $serialised = substr($serialised, 1, -1); } return $serialised; } /** Construct an NLView. * @param $parentController * @param $viewName string * @param $serialised string - Serialised definition of the view contents. * @param $context Object - an object that provides context for bindings of view components, which lets * components get data from their hosting environment. */ public function __construct($parentController, $viewName, $serialised, $context, $layoutManager = null) { parent::__construct(); $serialised = self::normalise_serialised($serialised); $this->parentController = $parentController; $this->viewName = $viewName; $this->rawComponents = json_decode($serialised); $this->context = $context; if ($layoutManager) { $this->layoutManager = $layoutManager; } else { $klass = Config::inst()->get('NLView', 'layout_manager_class'); if (!$klass) { throw new Exception("NLView needs a layout manager. Either pass one in, or set it up in config. See module documentation"); } $this->layoutManager = Injector::inst()->create($klass); } } /** * Return the top-level layout component for this view. * This assumes that the construction of the view always has a layout component at the root. */ public function getLayout() { if (!$this->layout) { // get the view definition. We give it the raw component hierarchy and let // the factory component sort out what classes are actually required. $this->layout = NLComponent::factory($this->rawComponents, $this); } return $this->layout; } public function getLayoutManager() { return $this->layoutManager; } /** * Render this view. * @return */ public function forTemplate() { Requirements::css("neolayout/css/nlcore.css"); $layout = $this->getLayout(); $extraClasses = array(); // render return $this->customise( new ArrayData(array( "Layout" => $layout->render($this->context), "ExtraClasses" => implode(" ", $extraClasses), "URL" => $this->parentController->Link($this->viewName) )) )->renderWith("NLView"); } protected function getComponentItems() { $items = new ArrayList(); $subclasses = ClassInfo::subclassesFor("NLComponent"); // Remove abstracts // @todo do this programmatically unset($subclasses["NLComponent"]); unset($subclasses["NLLayoutComponent"]); // @todo let context filter component types if ($this->context && $this->context->hasMethod("filterComponents")) { $subclasses = $this->context->filterComponents($subclasses); } foreach ($subclasses as $class) { $inst = singleton($class); $metadata = $inst->getMetadata(); $items->push(new NLViewAddableItem( isset($metadata["name"]) ? $metadata["name"] : "(unnamed)", isset($metadata["description"]) ? $metadata["description"] : null, isset($metadata["imageURL"]) ? $metadata["imageURL"] : null, $class )); } return $items; } protected function findComponentById($id) { $layout = $this->getLayout(); return $this->findComponentByIdParented($layout, $id); } protected function findComponentByIdParented($parent, $id) { } // // Return a form for a component that can be embedded in the modal editor dialog in the javascript. This is // // requested asynchronously. The component type is identified on the URL; the editor is a for the type of component, // // and is not populated from any specific component.generic form The fields shown on the form // // are created from meta-data, but with no values populated. The values are populated in javascript, as it always // // has the most recent edition of the layout structure, particular where a component is edited the second time without // // saving. // public function EditFormByType() { // // Get the component class name // $fields = new FieldList(); // $actions = new FieldList(); // $form = new Form($this, "EditForm", $fields, $actions); // return $form; // } } class NLViewAddableItem extends ViewableData { /** * @param $name * @param $description * @param $imageURL * @param $type type of thing. e.g. NLLinkComponent, File, Image * @param $objectClass * @param $objectID * @param $ID ID of object if it is an object (not valid for components) */ function __construct($name, $description, $imageURL, $type, $objectClass = null, $objectID = null, $objectBinding = null) { $this->name = $name; $this->description = $description; $this->imageURL = $imageURL; $this->type = $type; $this->objectClass = $objectClass; $this->objectID = $objectID; $this->objectBinding = $objectBinding; } } |