/** * Custom processing for the options string in getConfigInputfields * * Detects and confirms option deletions. * * @param Inputfield $inputfield For the _options inputfield * @throws WireException * */ protected function process(Inputfield $inputfield) { $value = $this->wire('input')->post('_options'); if ($this->wire('process') != 'ProcessField' || !$this->wire('user')->isSuperuser()) { return; } $ns = "{$this}{$this->field}"; // namespace for session if (!is_null($value)) { // _options has been posted if ($this->manager->useLanguages() && $inputfield->useLanguages) { // multi-language $valuesPerLanguage = array(); $changed = false; foreach ($this->wire('languages') as $language) { $key = $language->isDefault() ? "_options" : "_options__{$language}"; $valuesPerLanguage[$language->id] = $this->wire('input')->post($key); $key = $language->isDefault() ? "value" : "value{$language}"; if ($inputfield->{$key} != $valuesPerLanguage[$language->id]) { $changed = true; } } if ($changed) { $this->manager->setOptionsStringLanguages($this->field, $valuesPerLanguage, false); } } else { // non multi-language if ($value != $inputfield->attr('value')) { $this->manager->setOptionsString($this->field, $value, false); } } $removedOptionIDs = $this->manager->getRemovedOptionIDs($this->field); // identified for removal if (count($removedOptionIDs)) { // stuff in session for next request $this->wire('session')->set($ns, 'removedOptionIDs', $removedOptionIDs); } $deleteOptionIDs = $this->wire('input')->post('_delete_options'); $deleteConfirm = (int) $this->wire('input')->post('_delete_confirm'); if ($deleteOptionIDs && $deleteConfirm) { // confirmed deleted if (!ctype_digit(str_replace(',', '', $deleteOptionIDs))) { throw new WireException("Invalid deleteOptionIDs"); } $deleteOptionIDs = explode(',', $deleteOptionIDs); foreach ($deleteOptionIDs as $key => $value) { $deleteOptionIDs[$key] = (int) $value; } $this->manager->deleteOptionsByID($this->field, $deleteOptionIDs); } } else { // options not posted, check if there are any pending session activities $removedOptionIDs = $this->wire('session')->get($ns, 'removedOptionIDs'); if (count($removedOptionIDs)) { $f = $this->wire('modules')->get('InputfieldHidden'); $f->attr('name', '_delete_options'); $f->attr('value', implode(',', $removedOptionIDs)); $this->inputfields->prepend($f); // setup for confirmation $f = $this->wire('modules')->get('InputfieldCheckbox'); $f->attr('name', '_delete_confirm'); $f->label = $this->_('Please confirm that you want to delete options'); $f->label2 = $this->_n('Delete this option', 'Delete these options', count($removedOptionIDs)); $this->warning($f->label); $removeOptions = $this->manager->getOptionsByID($this->field, $removedOptionIDs); $delimiter = $this->_('DELETE:') . ' '; $f->description .= $delimiter . $removeOptions->implode("\n{$delimiter}", 'title'); // collapse other inputfields since we prefer them to focus on this one only for now foreach ($this->inputfields as $i) { $i->collapsed = Inputfield::collapsedYes; } // add our confirmation field $this->inputfields->prepend($f); // was stuffed in session from previous request, unset it now since this is a one time thing $this->wire('session')->remove($ns, 'removedOptionIDs'); } } }
/** * Returns whether or not the given Inputfield should be processed by processInput() * * When an $inputfield has a 'showIf' property, then this returns false, but it queues * the field in the delayedChildren array for later processing. The root container should * temporarily remove the 'showIf' property of inputfields they want processed. * * @param Inputfield $inputfield * @return bool * */ public function isProcessable(Inputfield $inputfield) { if (!$inputfield->editable()) { return false; } // visibility settings that aren't saveable static $skipTypes = array(Inputfield::collapsedHidden, Inputfield::collapsedLocked, Inputfield::collapsedNoLocked, Inputfield::collapsedYesLocked); $collapsed = (int) $inputfield->getSetting('collapsed'); if (in_array($collapsed, $skipTypes)) { return false; } if (in_array($collapsed, array(Inputfield::collapsedYesAjax, Inputfield::collapsedBlankAjax))) { $processAjax = $this->wire('input')->post('processInputfieldAjax'); if (is_array($processAjax) && in_array($inputfield->attr('id'), $processAjax)) { // field can be processed (convention used by InputfieldWrapper) } else { if ($collapsed == Inputfield::collapsedBlankAjax && !$inputfield->isEmpty()) { // field can be processed because it is only collapsed if blank } else { if (isset($_SERVER['HTTP_X_FIELDNAME']) && $_SERVER['HTTP_X_FIELDNAME'] == $inputfield->attr('name')) { // field can be processed (convention used by ajax uploaded file and other ajax types) } else { // field was not rendered via ajax and thus can't be processed return false; } } } } // if dependencies aren't in use, we can skip the rest if ($this->useDependencies === false) { return true; } if (strlen($inputfield->getSetting('showIf')) || $inputfield->getSetting('required') && strlen($inputfield->getSetting('requiredIf'))) { $name = $inputfield->attr('name'); if (!$name) { $name = $inputfield->attr('id'); if (!$name) { $name = $this->wire('sanitizer')->fieldName($inputfield->label); } $inputfield->attr('name', $name); } $this->delayedChildren[$name] = $inputfield; return false; } return true; }
/** * Returns whether or not the given Inputfield should be processed by processInput() * * When an $inputfield has a 'showIf' property, then this returns false, but it queues * the field in the delayedChildren array for later processing. The root container should * temporarily remove the 'showIf' property of inputfields they want processed. * * @param Inputfield $inputfield * @return bool * */ protected function isProcessable(Inputfield $inputfield) { // skip over collapsedHidden or collapsedLocked inputfields, beacuse they are not saveable if ($inputfield->collapsed === Inputfield::collapsedHidden) { return false; } if ($inputfield->collapsed === Inputfield::collapsedLocked) { return false; } // if dependencies aren't in use, we can skip the rest //if(!$this->useDependencies) return true; if (strlen($inputfield->getSetting('showIf')) || $inputfield->getSetting('required') && strlen($inputfield->getSetting('requiredIf'))) { $name = $inputfield->attr('name'); $this->delayedChildren[$name] = $inputfield; return false; } return true; }
/** * Returns whether or not the given Inputfield should be processed by processInput() * * When an $inputfield has a 'showIf' property, then this returns false, but it queues * the field in the delayedChildren array for later processing. The root container should * temporarily remove the 'showIf' property of inputfields they want processed. * * @param Inputfield $inputfield * @return bool * */ protected function isProcessable(Inputfield $inputfield) { // visibility settings that aren't saveable static $skipTypes = array(Inputfield::collapsedHidden, Inputfield::collapsedLocked, Inputfield::collapsedNoLocked, Inputfield::collapsedYesLocked); if (in_array((int) $inputfield->getSetting('collapsed'), $skipTypes)) { return false; } // if dependencies aren't in use, we can skip the rest if ($this->useDependencies === false) { return true; } if (strlen($inputfield->getSetting('showIf')) || $inputfield->getSetting('required') && strlen($inputfield->getSetting('requiredIf'))) { $name = $inputfield->attr('name'); if (!$name) { $name = $inputfield->attr('id'); if (!$name) { $name = $this->wire('sanitizer')->fieldName($inputfield->label); } $inputfield->attr('name', $name); } $this->delayedChildren[$name] = $inputfield; return false; } return true; }
/** * Returns whether or not the given Inputfield should be processed by processInput() * * When an $inputfield has a 'showIf' property, then this returns false, but it queues * the field in the delayedChildren array for later processing. The root container should * temporarily remove the 'showIf' property of inputfields they want processed. * * @param Inputfield $inputfield * @return bool * */ protected function isProcessable(Inputfield $inputfield) { // skip over collapsedHidden or collapsedLocked inputfields, beacuse they are not saveable if ($inputfield->collapsed === Inputfield::collapsedHidden) { return false; } if ($inputfield->collapsed === Inputfield::collapsedNoLocked) { return false; } if ($inputfield->collapsed === Inputfield::collapsedYesLocked) { return false; } // if dependencies aren't in use, we can skip the rest if ($this->useDependencies === false) { return true; } if (strlen($inputfield->getSetting('showIf')) || $inputfield->getSetting('required') && strlen($inputfield->getSetting('requiredIf'))) { $name = $inputfield->attr('name'); if (!$name) { $name = $inputfield->attr('id'); if (!$name) { $name = $this->wire('sanitizer')->fieldName($inputfield->label); } $inputfield->attr('name', $name); } $this->delayedChildren[$name] = $inputfield; return false; } return true; }