public function __construct($controller, $name, $fields = null, $actions = null, $validator = null)
 {
     if (!$fields) {
         $helpHtml = _t('MemberImportForm.Help1', '<p>Import users in <em>CSV format</em> (comma-separated values).' . ' <small><a href="#" class="toggle-advanced">Show advanced usage</a></small></p>');
         $helpHtml .= _t('MemberImportForm.Help2', '<div class="advanced">' . '<h4>Advanced usage</h4>' . '<ul>' . '<li>Allowed columns: <em>%s</em></li>' . '<li>Existing users are matched by their unique <em>Code</em> property, and updated with any new values from ' . 'the imported file.</li>' . '<li>Groups can be assigned by the <em>Groups</em> column. Groups are identified by their <em>Code</em> property, ' . 'multiple groups can be separated by comma. Existing group memberships are not cleared.</li>' . '</ul>' . '</div>');
         $importer = new MemberCsvBulkLoader();
         $importSpec = $importer->getImportSpec();
         $helpHtml = sprintf($helpHtml, implode(', ', array_keys($importSpec['fields'])));
         $fields = new FieldList(new LiteralField('Help', $helpHtml), $fileField = new FileField('CsvFile', DBField::create_field('HTMLFragment', _t('SecurityAdmin_MemberImportForm.FileFieldLabel', 'CSV File <small>(Allowed extensions: *.csv)</small>'))));
         $fileField->getValidator()->setAllowedExtensions(array('csv'));
     }
     if (!$actions) {
         $action = new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import from CSV'));
         $action->addExtraClass('btn btn-secondary-outline ss-ui-button');
         $actions = new FieldList($action);
     }
     if (!$validator) {
         $validator = new RequiredFields('CsvFile');
     }
     parent::__construct($controller, $name, $fields, $actions, $validator);
     Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/vendor.js');
     Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js');
     Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css');
     $this->addExtraClass('cms');
     $this->addExtraClass('import-form');
 }
 public function testGetField()
 {
     $formAction = new FormAction('test');
     $this->assertContains('type="submit"', $formAction->getAttributesHTML());
     $formAction->setAttribute('src', 'file.png');
     $this->assertContains('type="image"', $formAction->getAttributesHTML());
 }
 protected function getFormActions()
 {
     $actions = parent::getFormActions();
     // Check if record is versionable
     /** @var Versioned|DataObject $record */
     $record = $this->getRecord();
     if (!$record || !$record->has_extension('SilverStripe\\ORM\\Versioning\\Versioned')) {
         return $actions;
     }
     // Save & Publish action
     if ($record->canPublish()) {
         // "publish", as with "save", it supports an alternate state to show when action is needed.
         $publish = FormAction::create('doPublish', _t('VersionedGridFieldItemRequest.BUTTONPUBLISH', 'Publish'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept');
         // Insert after save
         if ($actions->fieldByName('action_doSave')) {
             $actions->insertAfter('action_doSave', $publish);
         } else {
             $actions->push($publish);
         }
     }
     // Unpublish action
     $isPublished = $record->isPublished();
     if ($isPublished && $record->canUnpublish()) {
         $actions->push(FormAction::create('doUnpublish', _t('VersionedGridFieldItemRequest.BUTTONUNPUBLISH', 'Unpublish'))->setUseButtonTag(true)->setDescription(_t('VersionedGridFieldItemRequest.BUTTONUNPUBLISHDESC', 'Remove this record from the published site'))->addExtraClass('ss-ui-action-destructive'));
     }
     // Archive action
     if ($record->canArchive()) {
         // Replace "delete" action
         $actions->removeByName('action_doDelete');
         // "archive"
         $actions->push(FormAction::create('doArchive', _t('VersionedGridFieldItemRequest.ARCHIVE', 'Archive'))->setDescription(_t('VersionedGridFieldItemRequest.BUTTONARCHIVEDESC', 'Unpublish and send to archive'))->addExtraClass('delete ss-ui-action-destructive'));
     }
     return $actions;
 }
 /**
  * Build the file selection form.
  *
  * @skipUpgrade
  * @return Form
  */
 public function Form()
 {
     // Find out the requested folder ID.
     $folderID = $this->parent->getRequest()->requestVar('ParentID');
     if ($folderID === null && $this->parent->getDisplayFolderName()) {
         $folder = Folder::find_or_make($this->parent->getDisplayFolderName());
         $folderID = $folder ? $folder->ID : 0;
     }
     // Construct the form
     $action = new FormAction('doAttach', _t('UploadField.AttachFile', 'Attach file(s)'));
     $action->addExtraClass('ss-ui-action-constructive icon-accept');
     $form = new Form($this, 'Form', new FieldList($this->getListField($folderID)), new FieldList($action));
     // Add a class so we can reach the form from the frontend.
     $form->addExtraClass('uploadfield-form');
     return $form;
 }
 /**
  * Test that schema is merged correctly
  */
 public function testMergeSchema()
 {
     $publishAction = FormAction::create('publish', 'Publish');
     $publishAction->setIcon('save');
     $publishAction->setSchemaData(['data' => ['buttonStyle' => 'primary']]);
     $schema = $publishAction->getSchemaData();
     $this->assertEquals(['icon' => 'save', 'buttonStyle' => 'primary'], $schema['data']);
 }
 function __construct()
 {
     parent::__construct('addtocampaign', _t('CAMPAIGNS.ADDTOCAMPAIGN', 'Add to Campaign'));
     $this->setUseButtonTag(false);
     $this->addExtraClass('add-to-campaign-action');
     $this->setValidationExempt(true);
     $this->addExtraClass('btn');
     $this->addExtraClass('btn-primary');
 }
 /**
  * @return array
  */
 public function getAttributes()
 {
     // Store state in session, and pass ID to client side.
     $state = array('grid' => $this->getNameFromParent(), 'actionName' => $this->actionName, 'args' => $this->args);
     // Ensure $id doesn't contain only numeric characters
     $id = 'gf_' . substr(md5(serialize($state)), 0, 8);
     Session::set($id, $state);
     $actionData['StateID'] = $id;
     return array_merge(parent::getAttributes(), array('name' => 'action_gridFieldAlterAction' . '?' . http_build_query($actionData), 'data-url' => $this->gridField->Link()));
 }
 public function __construct($controller, $name, $fields = null, $actions = null, $validator = null)
 {
     if (!$fields) {
         $helpHtml = _t('GroupImportForm.Help1', '<p>Import one or more groups in <em>CSV</em> format (comma-separated values).' . ' <small><a href="#" class="toggle-advanced">Show advanced usage</a></small></p>');
         $helpHtml .= _t('GroupImportForm.Help2', '<div class="advanced">' . '<h4>Advanced usage</h4>' . '<ul>' . '<li>Allowed columns: <em>%s</em></li>' . '<li>Existing groups are matched by their unique <em>Code</em> value, and updated with any new values from the ' . 'imported file</li>' . '<li>Group hierarchies can be created by using a <em>ParentCode</em> column.</li>' . '<li>Permission codes can be assigned by the <em>PermissionCode</em> column. Existing permission codes are not ' . 'cleared.</li>' . '</ul>' . '</div>');
         $importer = new GroupCsvBulkLoader();
         $importSpec = $importer->getImportSpec();
         $helpHtml = sprintf($helpHtml, implode(', ', array_keys($importSpec['fields'])));
         $fields = new FieldList(new LiteralField('Help', $helpHtml), $fileField = new FileField('CsvFile', DBField::create_field('HTMLFragment', _t('SecurityAdmin_MemberImportForm.FileFieldLabel', 'CSV File <small>(Allowed extensions: *.csv)</small>'))));
         $fileField->getValidator()->setAllowedExtensions(array('csv'));
     }
     if (!$actions) {
         $action = new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import from CSV'));
         $action->addExtraClass('ss-ui-button');
         $actions = new FieldList($action);
     }
     if (!$validator) {
         $validator = new RequiredFields('CsvFile');
     }
     parent::__construct($controller, $name, $fields, $actions, $validator);
     $this->addExtraClass('cms');
     $this->addExtraClass('import-form');
 }
 public function __construct(Controller $controller, $name)
 {
     // Set default fields
     $fields = new FieldList(HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), HiddenField::create('tempid', null, $controller->getRequest()->requestVar('tempid')), PasswordField::create("Password", _t('Member.PASSWORD', 'Password')), LiteralField::create('forgotPassword', sprintf('<p id="ForgotPassword"><a href="%s" target="_top">%s</a></p>', $this->getExternalLink('lostpassword'), _t('CMSMemberLoginForm.BUTTONFORGOTPASSWORD', "Forgot password?"))));
     if (Security::config()->autologin_enabled) {
         $fields->push(CheckboxField::create("Remember", _t('Member.REMEMBERME', "Remember me next time?")));
     }
     // Determine returnurl to redirect to parent page
     $logoutLink = $this->getExternalLink('logout');
     if ($returnURL = $controller->getRequest()->requestVar('BackURL')) {
         $logoutLink = Controller::join_links($logoutLink, '?BackURL=' . urlencode($returnURL));
     }
     // Make actions
     $actions = new FieldList(FormAction::create('dologin', _t('CMSMemberLoginForm.BUTTONLOGIN', "Log back in")), LiteralField::create('doLogout', sprintf('<p id="doLogout"><a href="%s" target="_top">%s</a></p>', $logoutLink, _t('CMSMemberLoginForm.BUTTONLOGOUT', "Log out"))));
     parent::__construct($controller, $name, $fields, $actions);
 }
 public function getEditForm($id = null, $fields = null)
 {
     $this->setCurrentPageID(Member::currentUserID());
     $form = parent::getEditForm($id, $fields);
     if ($form instanceof HTTPResponse) {
         return $form;
     }
     $form->Fields()->removeByName('LastVisited');
     $form->Fields()->push(new HiddenField('ID', null, Member::currentUserID()));
     $form->Actions()->push(FormAction::create('save', _t('CMSMain.SAVE', 'Save'))->addExtraClass('ss-ui-button ss-ui-action-constructive')->setAttribute('data-icon', 'accept')->setUseButtonTag(true));
     $form->Actions()->removeByName('action_delete');
     if ($member = Member::currentUser()) {
         $form->setValidator($member->getValidator());
     } else {
         $form->setValidator(Member::singleton()->getValidator());
     }
     if ($form->Fields()->hasTabSet()) {
         $form->Fields()->findOrMakeTab('Root')->setTemplate('SilverStripe\\Forms\\CMSTabSet');
     }
     $form->addExtraClass('member-profile-form root-form cms-edit-form center fill-height');
     return $form;
 }
 /**
  * @param File $record
  * @return FormAction
  */
 protected function getInsertAction($record)
 {
     if ($record && $record->isInDB() && $record->canEdit()) {
         return FormAction::create('insert', _t('CMSMain.INSERT', 'Insert file'))->setSchemaData(['data' => ['buttonStyle' => 'primary']]);
     }
     return null;
 }
 /**
  * FieldList::forTemplate() for an action list returns a concatenation of Field values.
  * Internally, this works by having FormAction::FieldHolder return just the field, but it's an important
  * use-case to test.
  */
 public function testForTemplateForActionList()
 {
     $set = new FieldList($a = new FormAction('A'), $b = new FormAction('B'));
     $this->assertEquals($a->Field() . $b->Field(), $set->forTemplate());
 }
 /**
  * Calls {@link SiteTree->getCMSFields()}
  *
  * @param Int $id
  * @param FieldList $fields
  * @return Form
  */
 public function getEditForm($id = null, $fields = null)
 {
     if (!$id) {
         $id = $this->currentPageID();
     }
     if (is_object($id)) {
         $record = $id;
     } else {
         $record = $this->getRecord($id);
         if ($record && !$record->canView()) {
             return Security::permissionFailure($this);
         }
     }
     if ($record) {
         $fields = $fields ? $fields : $record->getCMSFields();
         if ($fields == null) {
             user_error("getCMSFields() returned null  - it should return a FieldList object.\n\t\t\t\t\tPerhaps you forgot to put a return statement at the end of your method?", E_USER_ERROR);
         }
         // Add hidden fields which are required for saving the record
         // and loading the UI state
         if (!$fields->dataFieldByName('ClassName')) {
             $fields->push(new HiddenField('ClassName'));
         }
         $tree_class = $this->stat('tree_class');
         if ($tree_class::has_extension(Hierarchy::class) && !$fields->dataFieldByName('ParentID')) {
             $fields->push(new HiddenField('ParentID'));
         }
         // Added in-line to the form, but plucked into different view by frontend scripts.
         if ($record instanceof CMSPreviewable) {
             /** @skipUpgrade */
             $navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator());
             $navField->setAllowHTML(true);
             $fields->push($navField);
         }
         if ($record->hasMethod('getAllCMSActions')) {
             $actions = $record->getAllCMSActions();
         } else {
             $actions = $record->getCMSActions();
             // add default actions if none are defined
             if (!$actions || !$actions->count()) {
                 if ($record->hasMethod('canEdit') && $record->canEdit()) {
                     $actions->push(FormAction::create('save', _t('CMSMain.SAVE', 'Save'))->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
                 }
                 if ($record->hasMethod('canDelete') && $record->canDelete()) {
                     $actions->push(FormAction::create('delete', _t('ModelAdmin.DELETE', 'Delete'))->addExtraClass('ss-ui-action-destructive'));
                 }
             }
         }
         // Use <button> to allow full jQuery UI styling
         $actionsFlattened = $actions->dataFields();
         if ($actionsFlattened) {
             /** @var FormAction $action */
             foreach ($actionsFlattened as $action) {
                 $action->setUseButtonTag(true);
             }
         }
         $negotiator = $this->getResponseNegotiator();
         $form = Form::create($this, "EditForm", $fields, $actions)->setHTMLID('Form_EditForm');
         $form->addExtraClass('cms-edit-form');
         $form->loadDataFrom($record);
         $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
         $form->setAttribute('data-pjax-fragment', 'CurrentForm');
         $form->setValidationResponseCallback(function () use($negotiator, $form) {
             $request = $this->getRequest();
             if ($request->isAjax() && $negotiator) {
                 $form->setupFormErrors();
                 $result = $form->forTemplate();
                 return $negotiator->respond($request, array('CurrentForm' => function () use($result) {
                     return $result;
                 }));
             }
         });
         // Announce the capability so the frontend can decide whether to allow preview or not.
         if ($record instanceof CMSPreviewable) {
             $form->addExtraClass('cms-previewable');
         }
         $form->addExtraClass('fill-height');
         // Set this if you want to split up tabs into a separate header row
         // if($form->Fields()->hasTabset()) {
         // 	$form->Fields()->findOrMakeTab('Root')->setTemplate('SilverStripe\\Forms\\CMSTabSet');
         // }
         // Add a default or custom validator.
         // @todo Currently the default Validator.js implementation
         //  adds javascript to the document body, meaning it won't
         //  be included properly if the associated fields are loaded
         //  through ajax. This means only serverside validation
         //  will kick in for pages+validation loaded through ajax.
         //  This will be solved by using less obtrusive javascript validation
         //  in the future, see http://open.silverstripe.com/ticket/2915 and
         //  http://open.silverstripe.com/ticket/3386
         if ($record->hasMethod('getCMSValidator')) {
             $validator = $record->getCMSValidator();
             // The clientside (mainly LeftAndMain*.js) rely on ajax responses
             // which can be evaluated as javascript, hence we need
             // to override any global changes to the validation handler.
             if ($validator != NULL) {
                 $form->setValidator($validator);
             }
         } else {
             $form->unsetValidator();
         }
         if ($record->hasMethod('canEdit') && !$record->canEdit()) {
             $readonlyFields = $form->Fields()->makeReadonly();
             $form->setFields($readonlyFields);
         }
     } else {
         $form = $this->EmptyForm();
     }
     return $form;
 }
 /**
  * Passed a FormAction, returns true if that action is exempt from Form validation
  *
  * @param FormAction $action
  * @return bool
  */
 public function actionIsValidationExempt($action)
 {
     if ($action->getValidationExempt()) {
         return true;
     }
     if (in_array($action->actionName(), $this->getValidationExemptActions())) {
         return true;
     }
     return false;
 }
 /**
  * FieldList $actions or string $name (of a method on File to provide a actions) for the EditForm
  * @example 'getCMSActions'
  *
  * @param DataObject $file File context to generate form actions for
  * @return FieldList Field list containing FormAction
  */
 public function getFileEditActions(DataObject $file)
 {
     // Empty actions, generate default
     if (empty($this->fileEditActions)) {
         $actions = new FieldList($saveAction = new FormAction('doEdit', _t('UploadField.DOEDIT', 'Save')));
         $saveAction->addExtraClass('ss-ui-action-constructive icon-accept');
         return $actions;
     }
     // Actions instance
     if ($this->fileEditActions instanceof FieldList) {
         return $this->fileEditActions;
     }
     // Method to call on the given file
     if ($file->hasMethod($this->fileEditActions)) {
         return $file->{$this->fileEditActions}();
     }
     throw new InvalidArgumentException("Invalid value for UploadField::fileEditActions");
 }
 public function Form()
 {
     $form = new Form($this, 'Form', new FieldList(new EmailField('Email'), new TextField('SomeRequiredField'), new CheckboxSetField('Boxes', null, array('1' => 'one', '2' => 'two')), new NumericField('Number')), new FieldList(FormAction::create('doSubmit'), FormAction::create('doSubmitValidationExempt'), FormAction::create('doSubmitActionExempt')->setValidationExempt(true)), new RequiredFields('Email', 'SomeRequiredField'));
     $form->setValidationExemptActions(array('doSubmitValidationExempt'));
     $form->disableSecurityToken();
     // Disable CSRF protection for easier form submission handling
     return $form;
 }
 /**
  * @todo Use GridFieldDetailForm once it can handle structured data and form schemas
  *
  * @param int $id
  * @return Form
  */
 public function getDetailEditForm($id)
 {
     // Get record-specific fields
     $record = null;
     if ($id) {
         $record = ChangeSet::get()->byID($id);
         if (!$record || !$record->canView()) {
             return null;
         }
     }
     if (!$record) {
         $record = ChangeSet::singleton();
     }
     $fields = $record->getCMSFields();
     // Add standard fields
     $fields->push(HiddenField::create('ID'));
     $form = Form::create($this, 'DetailEditForm', $fields, FieldList::create(FormAction::create('save', _t('CMSMain.SAVE', 'Save'))->setIcon('save'), FormAction::create('cancel', _t('LeftAndMain.CANCEL', 'Cancel'))->setUseButtonTag(true)));
     // Load into form
     if ($id && $record) {
         $form->loadDataFrom($record);
     }
     $form->getValidator()->addRequiredField('Name');
     // Configure form to respond to validation errors with form schema
     // if requested via react.
     $form->setValidationResponseCallback(function () use($form, $record) {
         $schemaId = Controller::join_links($this->Link('schema/DetailEditForm'), $record->exists() ? $record->ID : '');
         return $this->getSchemaResponse($form, $schemaId);
     });
     return $form;
 }
 /**
  * @return Form
  */
 public function SearchForm()
 {
     $context = $this->getSearchContext();
     /** @skipUpgrade */
     $form = new Form($this, "SearchForm", $context->getSearchFields(), new FieldList(FormAction::create('search', _t('MemberTableField.APPLY_FILTER', 'Apply Filter'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive'), ResetFormAction::create('clearsearch', _t('ModelAdmin.RESET', 'Reset'))->setUseButtonTag(true)), new RequiredFields());
     $form->setFormMethod('get');
     $form->setFormAction($this->Link($this->sanitiseClassName($this->modelClass)));
     $form->addExtraClass('cms-search-form');
     $form->disableSecurityToken();
     $form->loadDataFrom($this->getRequest()->getVars());
     $this->extend('updateSearchForm', $form);
     return $form;
 }
 /**
  * Get delete action, if this record is deletable
  *
  * @param File $record
  * @return FormAction
  */
 protected function getDeleteAction($record)
 {
     // Delete action
     if ($record && $record->isInDB() && $record->canDelete()) {
         $deleteText = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.DELETE_BUTTON', 'Delete');
         return FormAction::create('delete', $deleteText)->setIcon('trash-bin');
     }
     return null;
 }
 /**
  * Build the set of form field actions for this DataObject
  *
  * @return FieldList
  */
 protected function getFormActions()
 {
     $canEdit = $this->record->canEdit();
     $canDelete = $this->record->canDelete();
     $actions = new FieldList();
     if ($this->record->ID !== 0) {
         if ($canEdit) {
             $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
         }
         if ($canDelete) {
             $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-destructive action-delete'));
         }
     } else {
         // adding new record
         //Change the Save label to 'Create'
         $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Create', 'Create'))->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'add'));
         // Add a Cancel link which is a button-like link and link back to one level up.
         $crumbs = $this->Breadcrumbs();
         if ($crumbs && $crumbs->count() >= 2) {
             $oneLevelUp = $crumbs->offsetGet($crumbs->count() - 2);
             $text = sprintf("<a class=\"%s\" href=\"%s\">%s</a>", "crumb ss-ui-button ss-ui-action-destructive cms-panel-link ui-corner-all", $oneLevelUp->Link, _t('GridFieldDetailForm.CancelBtn', 'Cancel'));
             $actions->push(new LiteralField('cancelbutton', $text));
         }
     }
     $this->extend('updateFormActions', $actions);
     return $actions;
 }
    /**
     * Constructor
     *
     * @skipUpgrade
     * @param Controller $controller The parent controller, necessary to
     *                               create the appropriate form action tag.
     * @param string $name The method on the controller that will return this
     *                     form object.
     * @param FieldList $fields All of the fields in the form - a
     *                                   {@link FieldList} of {@link FormField}
     *                                   objects.
     * @param FieldList|FormAction $actions All of the action buttons in the
     *                                     form - a {@link FieldList} of
     *                                     {@link FormAction} objects
     * @param bool $checkCurrentUser If set to TRUE, it will be checked if a
     *                               the user is currently logged in, and if
     *                               so, only a logout button will be rendered
     */
    public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true)
    {
        // This is now set on the class directly to make it easier to create subclasses
        // $this->authenticator_class = $authenticatorClassName;
        $customCSS = project() . '/css/member_login.css';
        if (Director::fileExists($customCSS)) {
            Requirements::css($customCSS);
        }
        if (isset($_REQUEST['BackURL'])) {
            $backURL = $_REQUEST['BackURL'];
        } else {
            $backURL = Session::get('BackURL');
        }
        if ($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) {
            $fields = FieldList::create(HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this));
            $actions = FieldList::create(FormAction::create("logout", _t('Member.BUTTONLOGINOTHER', "Log in as someone else")));
        } else {
            if (!$fields) {
                $label = Member::singleton()->fieldLabel(Member::config()->unique_identifier_field);
                $fields = FieldList::create(HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), $emailField = TextField::create("Email", $label, null, null, $this), PasswordField::create("Password", _t('Member.PASSWORD', 'Password')));
                if (Security::config()->remember_username) {
                    $emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email'));
                } else {
                    // Some browsers won't respect this attribute unless it's added to the form
                    $this->setAttribute('autocomplete', 'off');
                    $emailField->setAttribute('autocomplete', 'off');
                }
                if (Security::config()->autologin_enabled) {
                    $fields->push(CheckboxField::create("Remember", _t('Member.KEEPMESIGNEDIN', "Keep me signed in"))->setAttribute('title', sprintf(_t('Member.REMEMBERME', "Remember me next time? (for %d days on this device)"), RememberLoginHash::config()->get('token_expiry_days'))));
                }
            }
            if (!$actions) {
                $actions = FieldList::create(FormAction::create('dologin', _t('Member.BUTTONLOGIN', "Log in")), LiteralField::create('forgotPassword', '<p id="ForgotPassword"><a href="' . Security::lost_password_url() . '">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'));
            }
        }
        if (isset($backURL)) {
            $fields->push(HiddenField::create('BackURL', 'BackURL', $backURL));
        }
        // Reduce attack surface by enforcing POST requests
        $this->setFormMethod('POST', true);
        parent::__construct($controller, $name, $fields, $actions);
        $this->setValidator(RequiredFields::create('Email', 'Password'));
        // Focus on the email input when the page is loaded
        $js = <<<JS
\t\t\t(function() {
\t\t\t\tvar el = document.getElementById("MemberLoginForm_LoginForm_Email");
\t\t\t\tif(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus();
\t\t\t})();
JS;
        Requirements::customScript($js, 'MemberLoginFormFieldFocus');
    }