Permalink
Browse files

MINOR Moved Widget, WidgetArea and related files from 'sapphire' to '…

…cms' module
  • Loading branch information...
1 parent 7b038db commit dd6a86c1c15a6706e8569b141b8537c8e5658c67 @chillu chillu committed Mar 22, 2011
View
@@ -0,0 +1,233 @@
+<?php
+/**
+ * Widgets let CMS authors drag and drop small pieces of functionality into
+ * defined areas of their websites.
+ *
+ * ## Forms
+ * You can use forms in widgets by implementing a {@link Widget_Controller}.
+ * See {@link Widget_Controller} for more information.
+ *
+ * @package sapphire
+ * @subpackage widgets
+ */
+class Widget extends DataObject {
+ static $db = array(
+ "Sort" => "Int",
+ "Enabled" => "Boolean"
+ );
+
+ static $defaults = array(
+ 'Enabled' => true
+ );
+
+ static $has_one = array(
+ "Parent" => "WidgetArea",
+ );
+
+ static $has_many = array();
+ static $many_many = array();
+ static $belongs_many_many = array();
+
+ static $default_sort = "\"Sort\"";
+
+ static $title = "Widget Title";
+ static $cmsTitle = "Name of this widget";
+ static $description = "Description of what this widget does.";
+
+ function getCMSFields() {
+ $fields = new FieldSet();
+ $this->extend('updateCMSFields', $fields);
+ return $fields;
+ }
+
+ /**
+ * Note: Overloaded in {@link Widget_Controller}.
+ *
+ * @return string HTML
+ */
+ function WidgetHolder() {
+ return $this->renderWith("WidgetHolder");
+ }
+
+ /**
+ * Renders the widget content in a custom template with the same name as the current class.
+ * This should be the main point of output customization.
+ *
+ * Invoked from within WidgetHolder.ss, which contains
+ * the "framing" around the custom content, like a title.
+ *
+ * Note: Overloaded in {@link Widget_Controller}.
+ *
+ * @return string HTML
+ */
+ function Content() {
+ return $this->renderWith(array_reverse(ClassInfo::ancestry($this->class)));
+ }
+
+ function Title() {
+ return Object::get_static($this->class, 'title');
+ }
+
+ function CMSTitle() {
+ return Object::get_static($this->class, 'cmsTitle');
+ }
+
+ function Description() {
+ return Object::get_static($this->class, 'description');
+ }
+
+ function DescriptionSegment() {
+ return $this->renderWith('WidgetDescription');
+ }
+
+ /**
+ * @see Widget_Controller->editablesegment()
+ */
+ function EditableSegment() {
+ return $this->renderWith('WidgetEditor');
+ }
+
+ function CMSEditor() {
+ $output = '';
+ $fields = $this->getCMSFields();
+ foreach($fields as $field) {
+ $name = $field->Name();
+ $field->setValue($this->getField($name));
+ $renderedField = $field->FieldHolder();
+ $renderedField = ereg_replace("name=\"([A-Za-z0-9\-_]+)\"", "name=\"Widget[" . $this->ID . "][\\1]\"", $renderedField);
+ $renderedField = ereg_replace("id=\"([A-Za-z0-9\-_]+)\"", "id=\"Widget[" . $this->ID . "][\\1]\"", $renderedField);
+ $output .= $renderedField;
+ }
+ return $output;
+ }
+
+ function ClassName() {
+ return $this->class;
+ }
+
+ function Name() {
+ return "Widget[".$this->ID."]";
+ }
+
+ function populateFromPostData($data) {
+ foreach($data as $name => $value) {
+ if($name != "Type") {
+ $this->setField($name, $value);
+ }
+ }
+
+ $this->write();
+
+ // The field must be written to ensure a unique ID.
+ $this->Name = $this->class.$this->ID;
+ $this->write();
+ }
+
+}
+
+/**
+ * Optional controller for every widget which has its own logic,
+ * e.g. in forms. It always handles a single widget, usually passed
+ * in as a database identifier through the controller URL.
+ * Needs to be constructed as a nested controller
+ * within a {@link ContentController}.
+ *
+ * ## Forms
+ * You can add forms like in any other sapphire controller.
+ * If you need access to the widget from within a form,
+ * you can use `$this->controller->getWidget()` inside the form logic.
+ * Note: Widget controllers currently only work on {@link Page} objects,
+ * because the logic is implemented in {@link ContentController->handleWidget()}.
+ * Copy this logic and the URL rules to enable it for other controllers.
+ *
+ * @package sapphire
+ * @subpackage widgets
+ */
+class Widget_Controller extends Controller {
+
+ /**
+ * @var Widget
+ */
+ protected $widget;
+
+ static $allowed_actions = array(
+ 'editablesegment'
+ );
+
+ function __construct($widget = null) {
+ // TODO This shouldn't be optional, is only necessary for editablesegment()
+ if($widget) {
+ $this->widget = $widget;
+ $this->failover = $widget;
+ }
+
+ parent::__construct();
+ }
+
+ public function Link($action = null) {
+ $segment = Controller::join_links('widget', ($this->widget ? $this->widget->ID : null), $action);
+
+ if(Director::get_current_page()) {
+ return Director::get_current_page()->Link($segment);
+ } else {
+ return Controller::curr()->Link($segment);
+ }
+ }
+
+ /**
+ * @return Widget
+ */
+ function getWidget() {
+ return $this->widget;
+ }
+
+ /**
+ * Overloaded from {@link Widget->Content()}
+ * to allow for controller/form linking.
+ *
+ * @return string HTML
+ */
+ function Content() {
+ return $this->renderWith(array_reverse(ClassInfo::ancestry($this->widget->class)));
+ }
+
+ /**
+ * Overloaded from {@link Widget->WidgetHolder()}
+ * to allow for controller/form linking.
+ *
+ * @return string HTML
+ */
+ function WidgetHolder() {
+ return $this->renderWith("WidgetHolder");
+ }
+
+ /**
+ * Uses the `WidgetEditor.ss` template and {@link Widget->editablesegment()}
+ * to render a administrator-view of the widget. It is assumed that this
+ * view contains form elements which are submitted and saved through {@link WidgetAreaEditor}
+ * within the CMS interface.
+ *
+ * @return string HTML
+ */
+ function editablesegment() {
+ $className = $this->urlParams['ID'];
+ if(class_exists($className) && is_subclass_of($className, 'Widget')) {
+ $obj = new $className();
+ return $obj->EditableSegment();
+ } else {
+ user_error("Bad widget class: $className", E_USER_WARNING);
+ return "Bad widget class name given";
+ }
+ }
+}
+
+/**
+ * @package sapphire
+ * @subpackage widgets
+ */
+class Widget_TreeDropdownField extends TreeDropdownField {
+ function FieldHolder() {}
+ function Field() {}
+}
+
+?>
View
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Represents a set of widgets shown on a page.
+ * @package sapphire
+ * @subpackage widgets
+ */
+class WidgetArea extends DataObject {
+
+ static $db = array();
+
+ static $has_one = array();
+
+ static $has_many = array(
+ "Widgets" => "Widget"
+ );
+
+ static $many_many = array();
+
+ static $belongs_many_many = array();
+
+ public $template = __CLASS__;
+
+ /**
+ * Used in template instead of {@link Widgets()}
+ * to wrap each widget in its controller, making
+ * it easier to access and process form logic
+ * and actions stored in {@link Widget_Controller}.
+ *
+ * @return DataObjectSet Collection of {@link Widget_Controller}
+ */
+ function WidgetControllers() {
+ $controllers = new DataObjectSet();
+
+ foreach($this->ItemsToRender() as $widget) {
+ // find controller
+ $controllerClass = '';
+ foreach(array_reverse(ClassInfo::ancestry($widget->class)) as $widgetClass) {
+ $controllerClass = "{$widgetClass}_Controller";
+ if(class_exists($controllerClass)) break;
+ }
+ $controller = new $controllerClass($widget);
+ $controller->init();
+ $controllers->push($controller);
+ }
+
+ return $controllers;
+ }
+
+ function Items() {
+ return $this->getComponents('Widgets');
+ }
+
+ function ItemsToRender() {
+ return $this->getComponents('Widgets', "\"Widget\".\"Enabled\" = 1");
+ }
+
+ function forTemplate() {
+ return $this->renderWith($this->template);
+ }
+
+ function setTemplate($template) {
+ $this->template = $template;
+ }
+
+ function onBeforeDelete() {
+ parent::onBeforeDelete();
+ foreach($this->Widgets() as $widget) {
+ $widget->delete();
+ }
+ }
+}
+
+?>
@@ -0,0 +1,3 @@
+<% control WidgetControllers %>
+ $WidgetHolder
+<% end_control %>
@@ -0,0 +1,4 @@
+<div class="WidgetHolder $ClassName<% if FirstLast %> $FirstLast<% end_if %>">
+ <% if Title %><h3>$Title</h3><% end_if %>
+ $Content
+</div>
Oops, something went wrong.

0 comments on commit dd6a86c

Please sign in to comment.