/** * Function for embedding a date control in html. * * @author Peter C. Verhage <*****@*****.**> */ function smarty_function_atkdatefield($params, $smarty) { $name = isset($params['name']) ? $params['name'] : 'date'; $format = isset($params['format']) ? $params['format'] : Tools::atktext('date_format_edit', 'atk', '', '', '', true); $mandatory = isset($params['mandatory']) && $params['mandatory'] || isset($params['obligatory']) && $params['obligatory']; $noweekday = isset($params['noweekday']) && $params['noweekday']; $calendar = isset($params['calendar']) && $params['calendar']; $time = isset($params['time']) ? $params['time'] : ($mandatory ? mktime() : null); $min = isset($params['min']) ? $params['min'] : 0; $max = isset($params['max']) ? $params['max'] : 0; if (is_array($time)) { $date = $time; } else { if ($time == null) { $date = null; } else { if (is_numeric($time)) { $date = getdate($time); $date = array('day' => $date['mday'], 'month' => $date['mon'], 'year' => $date['year']); } else { if (preg_match('/([0-9]{1,2})-([0-9]{1,2})-([0-9]{4})/', $time, $matches)) { $date = array('day' => (int) $matches[1], 'month' => (int) $matches[2], 'year' => $matches[3]); } else { $date = getdate(strtotime($time)); $date = array('day' => $date['mday'], 'month' => $date['mon'], 'year' => $date['year']); } } } } $attr = new DateAttribute($name, $format, '', $min, $max, ($noweekday ? DateAttribute::AF_DATE_EDIT_NO_DAY : 0) | ($mandatory ? Attribute::AF_OBLIGATORY : 0) | ($calendar ? 0 : DateAttribute::AF_DATE_NO_CALENDAR)); $html = $attr->edit(array($name => $date), '', ''); return $html; }
/** * function to get multilanguage strings. * * This is actually a wrapper for ATK's Tools::atktext() method, for * use in templates. * * @author Ivo Jansch <*****@*****.**> * * Example: {atktext id="users.userinfo.description"} * {atktext id="userinfo.description" module="users"} * {atktext id="description" module="users" node="userinfo"} */ function smarty_function_atktext($params, $smarty) { if (!isset($params['id'])) { $params['id'] = $params[0]; } switch (substr_count($params['id'], '.')) { case 1: list($module, $id) = explode('.', $params['id']); $str = Tools::atktext($id, $module, isset($params['node']) ? $params['node'] : ''); break; case 2: list($module, $node, $id) = explode('.', $params['id']); $str = Tools::atktext($id, $module, $node); break; default: $str = Tools::atktext($params['id'], Tools::atkArrayNvl($params, 'module', ''), Tools::atkArrayNvl($params, 'node', ''), Tools::atkArrayNvl($params, 'lng', '')); } if (isset($params['filter'])) { $fn = $params['filter']; $str = $fn($str); } // parse the rest of the params in the string $parser = new StringParser($str); return $parser->parse($params); }
/** * Constructor. * * @param string $name Name of the attribute * @param int $flags Flags for the attribute * @param array $options CKEditor configuration options */ public function __construct($name, $flags = 0, $options = []) { $this->ckOptions['language'] = Language::getLanguage(); $this->ckOptions['wsc_lang'] = $this->ckOptions['scayt_sLang'] = Tools::atktext('locale'); $this->ckOptions = array_merge($this->ckOptions, Config::getGlobal('ck_options'), $options); parent::__construct($name, $flags); }
/** * Translates a menuitem with the menu_ prefix, or if not found without. * * @param string $menuitem Menuitem to translate * @param string $modname Module to which the menuitem belongs * * @return string Translation of the given menuitem */ public function getMenuTranslation($menuitem, $modname = 'atk') { $s = Tools::atktext("menu_{$menuitem}", $modname, '', '', '', true); if (!$s) { $s = Tools::atktext($menuitem, $modname); } return $s; }
/** * Constructor. * * @param string $name Name of the attribute * @param int $flags Flags for this attribute * @param string $currencysymbol The symbol which is printed in front of the value. * @param int $decimals The number of decimals (default 2) * @param string $decimalseparator The separator which is printed for the decimals. * @param string $thousandsseparator The separator which is printed for the thousands. */ public function __construct($name, $flags = 0, $currencysymbol = '', $decimals = 2, $decimalseparator = '', $thousandsseparator = '') { parent::__construct($name, $flags, $decimals); $this->setAttribSize(10); if ($currencysymbol == '') { $currencysymbol = Tools::atktext('currencysymbol', 'atk', '', '', '', true); } $this->m_currencysymbol = $currencysymbol; $this->m_decimalseparator = $decimalseparator != '' ? $decimalseparator : '.'; $this->m_thousandsseparator = $thousandsseparator != '' ? $thousandsseparator : ','; $this->setUseThousandsSeparator(true); }
/** * Handle the error. * * @param string $errorMessage * @param string $debugMessage */ public function handle($errorMessage, $debugMessage) { if ($this->zendPlatformAvailable()) { // log in zend platform $errMsg = implode(' | ', is_array($errorMessage) ? $errorMessage : array()); if ($errMsg == '') { $errMsg = 'Something went terribly wrong, but there is no errormessage set...'; } else { $errMsg = preg_replace('/\\[\\+.*s\\]/', '', $errMsg); } // get rid of timestamps because they will prevent ZP from finding duplicate errors monitor_custom_event(Tools::atktext('app_title'), $errMsg, true); } }
public function search($record, $extended = false, $fieldprefix = '', DataGrid $grid = null) { $this->createDestination(); if ($this->m_destinationFilter != '') { $sp = new StringParser($this->m_destinationFilter); $this->m_destInstance->addFilter($sp->parse($record)); } $recordset = $this->m_destInstance->select()->includes(Tools::atk_array_merge($this->m_destInstance->descriptorFields(), $this->m_destInstance->m_primaryKey))->getAllRows(); $result = '<select class="form-control" name="atksearch[' . $this->fieldName() . ']">'; $result .= '<option value="">' . Tools::atktext('search_all', 'atk'); $result .= $this->createdd($recordset); $result .= '</select>'; return $result; }
/** * Validates email address through regular expression and dns check. * * @param array $record Record that contains value to be validated. * Errors are saved in this record, in the 'atkerror' * field. * @param string $mode Validation mode. Can be either "add" or "update" */ public function validate(&$record, $mode) { $email = $record[$this->fieldName()]; //first check complete string if (!self::validateAddressSyntax($email)) { Tools::triggerError($record, $this, 'error_invalid_email'); } else { if ($this->m_dnsSearch) { //now check if domain exists, searches DNS for MX records list(, $domain) = explode('@', $email, 2); if (!self::validateAddressDomain($domain, false)) { Tools::triggerError($record, $this->fieldName(), 'error_unkown_domain', Tools::atktext('error_unkown_domain') . ' ' . $domain); } } } }
public function __construct($environment, $basedir) { global $g_startTime; $g_startTime = microtime(true); if (static::$s_instance) { throw new \RuntimeException('Only one Atk app can be created'); } static::$s_instance = $this; $this->environment = $environment; //load .env variables only in development environment if (file_exists($basedir . '.env') && in_array(strtolower($environment), ['dev', 'develop', 'development'])) { $dotEnv = new Dotenv($basedir); $dotEnv->load(); } require_once 'adodb-time.php'; Config::init(); if (Config::getGlobal('debug') > 0) { ini_set('display_errors', 1); } if (Config::getGlobal('use_atkerrorhandler', true)) { set_error_handler('Sintattica\\Atk\\Core\\Tools::atkErrorHandler'); error_reporting(E_ALL); set_exception_handler('Sintattica\\Atk\\Core\\Tools::atkExceptionHandler'); register_shutdown_function('Sintattica\\Atk\\Core\\Tools::atkFatalHandler'); } // Filter the atkselector REQUEST variable for blacklisted SQL (like UNIONs) SqlWhereclauseBlacklistChecker::filter_request_where_clause('atkselector'); SqlWhereclauseBlacklistChecker::filter_request_where_clause('atkfilter'); // set locale $locale = Tools::atktext('locale', 'atk', '', '', true); if ($locale) { setlocale(LC_TIME, $locale); } $debug = 'Created a new Atk (' . self::VERSION . ') instance.'; $debug .= ' Environment: ' . $environment . '.'; if (isset($_SERVER['SERVER_NAME']) && isset($_SERVER['SERVER_ADDR'])) { $debug .= ' Server info: ' . $_SERVER['SERVER_NAME'] . ' (' . $_SERVER['SERVER_ADDR'] . ')'; } Tools::atkdebug($debug); //load modules $modules = Config::getGlobal('modules'); if (is_array($modules)) { foreach ($modules as $module) { static::$s_instance->registerModule($module); } } }
/** * The method returns a complete html page containing the feedback info. * * @param string $action The action for which feedback is provided * @param int $actionstatus The status of the action for which feedback is * provided * @param string $message An optional message to display in addition to the * default feedback information message. * * @return string The feedback page as an html String. */ public function feedbackPage($action, $actionstatus, $message = '') { $node = $this->m_node; $ui = $this->getUi(); $params['content'] = '<br>' . Tools::atktext('feedback_' . $action . '_' . Tools::atkActionStatus($actionstatus), $node->m_module, $node->m_type); if ($message) { $params['content'] .= ' <br>' . $message; } $sm = SessionManager::getInstance(); if ($sm->atkLevel() > 0) { $params['formstart'] = '<form method="get">' . $sm->formState(SessionManager::SESSION_BACK); $params['buttons'][] = '<input type="submit" class="btn btn-default btn_cancel" value="<< ' . Tools::atktext('back') . '">'; $params['formend'] = '</form>'; } $output = $ui->renderAction($action, $params); return $ui->renderBox(array('title' => $node->actionTitle($action), 'content' => $output)); }
/** * Authenticate a user. * * @param string $user The login of the user to authenticate. * @param string $passwd The password of the user. Note: if the canMd5 * function of an implementation returns true, * $passwd will be passed as an md5 string. * * @return int SecurityManager::AUTH_SUCCESS - Authentication succesful * SecurityManager::AUTH_MISMATCH - Authentication failed, wrong * user/password combination * SecurityManager::AUTH_LOCKED - Account is locked, can not login * with current username. * SecurityManager::AUTH_ERROR - Authentication failed due to some * error which cannot be solved by * just trying again. If you return * this value, you *must* also * fill the m_fatalError variable. */ public function validateUser($user, $passwd) { if ($user == '') { return SecurityManager::AUTH_UNVERIFIED; } // can't verify if we have no userid // if it's a virtual mail server add @<domain> to the username if (Config::getGlobal('auth_mail_login_type') == 'vmailmgr') { $user = $user . '@' . Config::getGlobal('auth_mail_suffix'); } if (Config::getGlobal('auth_mail_server') == '') { $this->m_fatalError = Tools::atktext('auth_no_server'); return SecurityManager::AUTH_ERROR; } $mailauth = @imap_open('{' . Config::getGlobal('auth_mail_server') . ':' . Config::getGlobal('auth_mail_port') . '}', $user, $passwd); // TODO/FIXME: return SecurityManager::AUTH_ERROR when connection fails.. if ($mailauth == 0) { return SecurityManager::AUTH_MISMATCH; } else { imap_close($mailauth); return SecurityManager::AUTH_SUCCESS; } }
/** * Returns a piece of html code that can be used in a form to search for values. * * @param array $record Array with values * @param bool $extended if set to false, a simple search input is * returned for use in the searchbar of the * recordlist. If set to true, a more extended * search may be returned for the 'extended' * search page. The Attribute does not * make a difference for $extended is true, but * derived attributes may reimplement this. * @param string $fieldprefix The fieldprefix of this attribute's HTML element. * @param DataGrid $grid * * @return string piece of html code with a checkbox */ public function search($record, $extended = false, $fieldprefix = '', DataGrid $grid = null) { $id = $this->getHtmlId($fieldprefix); $name = $this->getSearchFieldName($fieldprefix); $result = '<select id="' . $id . '" name="' . $name . '" class="form-control select-standard">'; $result .= '<option value="">' . Tools::atktext('search_all', 'atk') . '</option>'; $result .= '<option value="0" '; if (is_array($record) && $record[$this->fieldName()] === '0') { $result .= 'selected'; } $result .= '>' . Tools::atktext('no', 'atk') . '</option>'; $result .= '<option value="1" '; if (is_array($record) && $record[$this->fieldName()] === '1') { $result .= 'selected'; } $result .= '>' . Tools::atktext('yes', 'atk') . '</option>'; $result .= '</select>'; return $result; }
/** * Attempts to get a translated label which can be used when composing an "add" link. * * @return string Localised "add" label */ public function getAddLabel() { $key = 'link_' . $this->fieldName() . '_add'; $label = Tools::atktext($key, $this->m_ownerInstance->m_module, $this->m_ownerInstance->m_type, '', '', true); if ($label == '') { $label = Tools::atktext($key, $this->m_destInstance->m_module, '', '', '', true); if ($label == '') { $key = 'link_' . Tools::getNodeType($this->m_destination) . '_add'; $label = Tools::atktext($key, $this->m_destInstance->m_module, '', '', '', true); if ($label == '') { $label = Tools::atktext('link_add', 'atk'); } } } return $label; }
/** * Function returns a generic html form for editing a record. * * @param string $mode The edit mode ("add" or "edit"). * @param array $record The record to edit. * @param array $forceList A key-value array used to preset certain * fields to a certain value. * @param array $suppressList An array of fields that will be hidden. * @param string $fieldprefix If set, each form element is prefixed with * the specified prefix (used in embedded * forms) * @param string $template The template to use for the edit form * @param bool $ignoreTab Ignore the tabs an attribute should be shown on. * * @return string the edit form as a string */ public function editForm($mode = 'add', $record = null, $forceList = '', $suppressList = '', $fieldprefix = '', $template = '', $ignoreTab = false) { $node = $this->m_node; /* get data, transform into form, return */ $data = $node->editArray($mode, $record, $forceList, $suppressList, $fieldprefix, $ignoreTab); // Format some things for use in tpl. /* check for errors and display them */ $tab = $node->getActiveTab(); $error_title = ''; $pk_err_attrib = []; $tabs = $node->getTabs($node->m_action); // Handle errors $errors = []; if (count($data['error']) > 0) { $error_title = '<b>' . Tools::atktext('error_formdataerror') . '</b>'; foreach ($data['error'] as $error) { if ($error['err'] == 'error_primarykey_exists') { $pk_err_attrib[] = $error['attrib_name']; } else { if (count($tabs) > 1 && $error['tab']) { $tabLink = $this->getTabLink($node, $error); $error_tab = ' (' . Tools::atktext('error_tab') . ' ' . $tabLink . ' )'; } else { $tabLink = null; $error_tab = ''; } if (is_array($error['label'])) { $label = implode(', ', $error['label']); } else { if (!empty($error['label'])) { $label = $error['label']; } else { if (!is_array($error['attrib_name'])) { $label = $node->text($error['attrib_name']); } else { $label = []; foreach ($error['attrib_name'] as $attrib) { $label[] = $node->text($attrib); } $label = implode(', ', $label); } } } /* Error messages should be rendered in templates using message, label and the link to the tab. */ $err = array('message' => $error['msg'], 'tablink' => $tabLink, 'label' => $label); /* * @deprecated: For backwards compatibility, we still support the msg variable as well. * Although the message, tablink variables should be used instead of msg and tab. */ $err = array_merge($err, array('msg' => $error['msg'] . $error_tab)); $errors[] = $err; } } if (count($pk_err_attrib) > 0) { // Make primary key error message $pk_err_msg = ''; for ($i = 0; $i < count($pk_err_attrib); ++$i) { $pk_err_msg .= Tools::atktext($pk_err_attrib[$i], $node->m_module, $node->m_type); if ($i + 1 < count($pk_err_attrib)) { $pk_err_msg .= ', '; } } $errors[] = array('label' => Tools::atktext('error_primarykey_exists'), 'message' => $pk_err_msg); } } /* display the edit fields */ $fields = []; $errorFields = []; $attributes = []; for ($i = 0, $_i = count($data['fields']); $i < $_i; ++$i) { $field =& $data['fields'][$i]; $tplfield = $this->createTplField($data['fields'], $i, $mode, $tab); $fields[] = $tplfield; // make field available in numeric array $params[isset($field['name']) ? $field['name'] : null] = $tplfield; // make field available in associative array $attributes[isset($field['name']) ? $field['name'] : null] = $tplfield; // make field available in associative array if (!empty($field['error'])) { $errorFields[] = $field['id']; } } $ui = $this->getUi(); $page = $this->getPage(); $page->register_script(Config::getGlobal('assets_url') . 'javascript/formsubmit.js'); // register fields that contain errornous values $page->register_scriptcode('var atkErrorFields = ' . Json::encode($errorFields) . ';'); if (Config::getGlobal('lose_changes_warning', true)) { // If we are in the save or update action the user has added a nested record, has done // a selection using the select handler or generated an error, in either way we assume // the form has been changed, so we always warn the user when leaving the page. $isChanged = 'false'; if (isset($record['atkerror']) && count($record['atkerror']) > 0 || isset($this->m_node->m_postvars['__atkunloadhelper']) && $this->m_node->m_postvars['__atkunloadhelper']) { $isChanged = 'true'; } $unloadText = addslashes($this->m_node->text('lose_changes_warning')); $page->register_script(Config::getGlobal('assets_url') . 'javascript/class.atkunloadhelper.js'); $page->register_loadscript("new ATK.UnloadHelper('entryform', '{$unloadText}', {$isChanged});"); } $result = ''; foreach ($data['hide'] as $hidden) { $result .= $hidden; } $params['activeTab'] = $tab; $params['fields'] = $fields; // add all fields as a numeric array. $params['attributes'] = $attributes; // add all fields as an associative array $params['errortitle'] = $error_title; $params['errors'] = $errors; // Add the list of errors. Tools::atkdebug("Render editform - {$template}"); if ($template) { $result .= $ui->render($template, $params); } else { $tabTpl = $this->_getTabTpl($node, $tabs, $mode, $record); $params['fieldspart'] = $this->_renderTabs($fields, $tabTpl); $result .= $ui->render('editform_common.tpl', $params); } return $result; }
/** * Adds the attribute's view / hide HTML code to the view array. * * This method is called by the node if it wants the data needed to create * a view form. * * This is a framework method, it should never be called directly. * * @param string $mode the mode ("view") * @param array $arr pointer to the view array * @param array $defaults pointer to the default values array */ public function addToViewArray($mode, &$arr, &$defaults) { if ($this->hasFlag(self::AF_HIDE_VIEW)) { return; } /* we first check if there is no display override method, if there * is this method has the same behaviour as the Attribute's method */ if (method_exists($this->m_ownerInstance, $this->m_name . '_display') || $this->display($defaults, 'view') !== null) { $this->addToViewArray($mode, $arr, $defaults); } else { if (!$this->createDestination()) { return; } $record = $defaults[$this->fieldName()]; $a = $this->m_destInstance->viewArray($mode, $record, false); /* editable fields, if self::AF_NOLABEL is specified or if there is just 1 field with the * same name as the relation we don't display a label * TODO FIXME */ if (!is_array($arr['fields'])) { $arr['fields'] = []; } if (!$this->hasFlag(self::AF_ONETOONE_INTEGRATE) && !$this->hasFlag(self::AF_NOLABEL) && !(count($a['fields']) == 1 && $a['fields'][0]['name'] == $this->m_name)) { /* separator and name */ if ($arr['fields'][count($arr['fields']) - 1]['html'] !== '-') { $arr['fields'][] = array('html' => '-', 'tabs' => $this->m_tabs, 'sections' => $this->getSections()); } $arr['fields'][] = array('line' => '<b>' . Tools::atktext($this->m_name, $this->m_ownerInstance->m_module, $this->m_ownerInstance->m_type) . '</b>', 'tabs' => $this->m_tabs, 'sections' => $this->getSections()); } if (is_array($a['fields'])) { if (!$this->hasFlag(self::AF_ONETOONE_INTEGRATE) || $this->hasFlag(self::AF_ONETOONE_RESPECT_TABS)) { foreach (array_keys($a['fields']) as $key) { $a['fields'][$key]['tabs'] = $this->m_tabs; $a['fields'][$key]['sections'] = $this->getSections(); } } $arr['fields'] = array_merge($arr['fields'], $a['fields']); } if (!$this->hasFlag(self::AF_ONETOONE_INTEGRATE) && !$this->hasFlag(self::AF_NOLABEL) && !(count($a['fields']) == 1 && $a['fields'][0]['name'] == $this->m_name)) { /* separator */ $arr['fields'][] = array('html' => '-', 'tabs' => $this->m_tabs, 'sections' => $this->getSections()); } } }
/** * We don't display the password. * * @param array $record the record with display data * @param string $mode * * @return string with value to display */ public function display($record, $mode) { return Tools::atktext('password_hidden', 'atk'); }
public function edit($record, $fieldprefix, $mode) { $this->createDestination(); $this->createLink(); $this->_renderChangeHandler($fieldprefix); $selectedPk = []; // first the selected records.. for ($i = 0; $i < count($record[$this->m_name]); ++$i) { if (is_array($record[$this->fieldName()][$i][$this->getRemoteKey()])) { $newselected = $this->m_destInstance->primaryKey($record[$this->m_name][$i][$this->getRemoteKey()]); } else { $newselected = $this->m_destInstance->primaryKey(array($this->m_destInstance->primaryKeyField() => $record[$this->m_name][$i][$this->getRemoteKey()])); } $selectedPk[] = $newselected; } $recordset = $this->_getSelectableRecords($record, $mode); $left = []; $right = []; $width = 100; for ($i = 0; $i < count($recordset); ++$i) { if (in_array($this->m_destInstance->primaryKey($recordset[$i]), $selectedPk) || in_array($recordset[$i][$this->m_destInstance->primaryKeyField()], $this->initialValue()) && $mode == 'add') { $right[] = $recordset[$i]; } else { $left[] = $recordset[$i]; } // fancy autowidth detection $width = max(Tools::atk_strlen($this->m_destInstance->descriptor($recordset[$i])) * 10, $width); } if ($this->m_maxlistwidth) { $width = min($this->m_maxlistwidth, $width); } $result = '<table border="0" class="' . $this->get_class_name() . '"><tr><td>' . Tools::atktext('available', 'atk') . ':<br/>'; $fieldname = $fieldprefix . $this->fieldName(); $leftname = $fieldname . '_sel'; $rightname = $fieldname . '[][' . $this->getRemoteKey() . ']'; $filterbox_left = false; $filterbox_right = false; $rightname_clean = ''; if ($this->m_filterBox) { // fix for selecting with jQuery // css ids shouldn't contain characters like [ and ] : http://www.w3.org/TR/html5/dom.html#the-id-attribute $rightname_clean = str_replace('[', '\\\\[', $rightname); $rightname_clean = str_replace(']', '\\\\]', $rightname_clean); $filterbox_left = $fieldname . 'left_filter_box'; $filterbox_right = $fieldname . 'right_filter_box'; } $result .= $this->_renderSelect($leftname, $left, $width, $rightname, $fieldname, $filterbox_left); $result .= '</td><td class="shuttle-controls">'; if ($this->m_filterBox) { // move buttons down a little if filter boxes are being displayed $result .= '<br><br><br>'; } $result .= '<div class="shuttle-controls-single">'; $result .= '<button class="btn btn-default" onClick="shuttle_move(\'' . $leftname . '\', \'' . $rightname . '\', \'' . $fieldname . '\');return false;"><i class="glyphicon glyphicon-triangle-right"></i></button>'; $result .= '<button class="btn btn-default" type="button" value="<" onClick="shuttle_move(\'' . $rightname . '\', \'' . $leftname . '\', \'' . $fieldname . '\');return false;"><i class="glyphicon glyphicon-triangle-left"></i></button>'; $result .= '</div>'; $result .= '<div class="shuttle-controls-multiple">'; $result .= '<button class="btn btn-default" type="button" value=">>" onClick="shuttle_moveall(\'' . $leftname . '\', \'' . $rightname . '\', \'' . $fieldname . '\');return false;"><i class="glyphicon glyphicon-forward"></i></button>'; $result .= '<button class="btn btn-default" type="button" value="<<" onClick="shuttle_moveall(\'' . $rightname . '\', \'' . $leftname . '\', \'' . $fieldname . '\');return false;"><i class="glyphicon glyphicon-backward"></i></button>'; $result .= '</div>'; $result .= '</td><td>' . Tools::atktext('selected', 'atk') . ':<br/>'; $result .= $this->_renderSelect($rightname, $right, $width, $leftname, $fieldname, $filterbox_right); // on submit, we must select all items in the right selector, as unselected items // will not be posted. $page = $this->m_ownerInstance->getPage(); $page->register_script(Config::getGlobal('assets_url') . 'javascript/class.atkshuttlerelation.js'); if ($this->m_filterBox && $rightname_clean && $filterbox_right && $filterbox_left && $rightname && $leftname) { // do the filtering $page->register_scriptcode("\n jQuery(function(\$){\n \$('#{$filterbox_left}').on('input', function() {\n var val = this.value.toLowerCase();\n \$('#{$leftname} > option').hide()\n .filter(function() {\n return this.text.toLowerCase().indexOf( val ) > -1;\n })\n .show();\n });\n\n \$('#{$filterbox_right}').on('input', function() {\n var val = this.value.toLowerCase();\n \$('#{$rightname_clean} > option').hide()\n .filter(function() {\n return this.text.toLowerCase().indexOf( val ) > -1;\n })\n .show();\n });\n });\n "); } $page->register_submitscript("shuttle_selectAll('" . $rightname . "');"); $result .= '</table>'; return $result; }
/** * Handle the error. * * @param string $errorMessage * @param string $debugMessage */ public function handle($errorMessage, $debugMessage) { $sessionManager = SessionManager::getInstance(); $sessionData =& SessionManager::getSession(); $txt_app_title = Tools::atktext('app_title'); if ($this->params['mailto'] != '') { // only if enabled.. $atk = Atk::getInstance(); $subject = '[' . $_SERVER['SERVER_NAME'] . "] {$txt_app_title} error"; $defaultfrom = sprintf('%s <%s@%s>', $txt_app_title, Config::getGlobal('identifier', 'atk'), $_SERVER['SERVER_NAME']); $from = Config::getGlobal('mail_sender', $defaultfrom); $body = "Hello,\n\nAn error seems to have occurred in the atk application named '{$txt_app_title}'.\n"; $body .= "\nThe errormessage was:\n\n" . implode("\n", is_array($errorMessage) ? $errorMessage : array()) . "\n"; $body .= "\nA detailed report follows:\n"; $body .= "\nPHP Version: " . phpversion() . "\n\n"; $body .= "\nDEBUGMESSAGES\n" . str_repeat('-', 70) . "\n"; $lines = []; for ($i = 0, $_ = count($debugMessage); $i < $_; ++$i) { $lines[] = $this->_wordwrap(Tools::atk_html_entity_decode(preg_replace('(\\[<a.*</a>\\])', '', $debugMessage[$i]))); } $body .= implode("\n", $lines); if (is_array($_GET)) { $body .= "\n\n_GET\n" . str_repeat('-', 70) . "\n"; foreach ($_GET as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 20 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } if (function_exists('getallheaders')) { $request = getallheaders(); if (count($request) > 0) { $body .= "\n\nREQUEST INFORMATION\n" . str_repeat('-', 70) . "\n"; foreach ($request as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } } if (is_array($_POST)) { $body .= "\n\n_POST\n" . str_repeat('-', 70) . "\n"; foreach ($_POST as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 20 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } if (is_array($_COOKIE)) { $body .= "\n\n_COOKIE\n" . str_repeat('-', 70) . "\n"; foreach ($_COOKIE as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 20 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } $body .= "\n\nATK CONFIGURATION\n" . str_repeat('-', 70) . "\n"; foreach ($GLOBALS as $key => $value) { if (substr($key, 0, 7) == 'config_') { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } $body .= "\n\nMODULE CONFIGURATION\n" . str_repeat('-', 70) . "\n"; foreach ($atk->g_modules as $modname => $modpath) { $modexists = file_exists($modpath) ? ' (path exists)' : ' (PATH DOES NOT EXIST!)'; $body .= $this->_wordwrap($modname . ':' . str_repeat(' ', max(1, 20 - strlen($modname))) . var_export($modpath, 1) . $modexists) . "\n"; } $body .= "\n\nCurrent User:\n" . str_repeat('-', 70) . "\n"; $user = SecurityManager::atkGetUser(); if (is_array($user) && count($user)) { foreach ($user as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } else { $body .= "Not known\n"; } if (is_object($sessionManager)) { $body .= "\n\nATK SESSION\n" . str_repeat('-', 70); $body .= "\nNamespace: " . $sessionManager->getNameSpace() . "\n"; if (isset($sessionData[$sessionManager->getNameSpace()]['stack'])) { $stack = $sessionData[$sessionManager->getNameSpace()]['stack']; for ($i = 0; $i < count($stack); ++$i) { $body .= "\nStack level {$i}:\n"; $item = isset($stack[$i]) ? $stack[$i] : null; if (is_array($item)) { foreach ($item as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } } } if (isset($sessionData[$sessionManager->getNameSpace()]['globals'])) { $ns_globals = $sessionData[$sessionManager->getNameSpace()]['globals']; if (count($ns_globals) > 0) { $body .= "\nNamespace globals:\n"; foreach ($ns_globals as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } } if (isset($sessionData['globals'])) { $globals = $sessionData['globals']; if (count($globals) > 0) { $body .= "\nGlobals:\n"; foreach ($globals as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 30 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } } } } $body .= "\n\nSERVER INFORMATION\n" . str_repeat('-', 70) . "\n"; foreach ($_SERVER as $key => $value) { $body .= $this->_wordwrap($key . str_repeat(' ', max(1, 20 - strlen($key))) . ' = ' . var_export($value, 1)) . "\n"; } //TODO: replace with some mailer object mail($this->params['mailto'], $subject, $body, "From: {$from}"); } }
/** * Determine error message. * * @param int $pos The position of the element that is not properly * formatted. * @param string $specifier The format that the value should've adhered to. * * @return string A translated error string. */ public function _formatErrorString($pos, $specifier) { return sprintf(Tools::atktext('error_format_mismatch', 'atk', $this->m_owner), $pos, $specifier); }
/** * This method returns an html page containing a recordlist to select * records from. The recordlist can be searched, sorted etc. like an * admin screen. * * @return string The html select page. */ public function multiSelectPage() { // add the postvars to the form global $g_stickyurl; $sm = SessionManager::getInstance(); $g_stickyurl[] = 'atktarget'; $g_stickyurl[] = 'atktargetvar'; $g_stickyurl[] = 'atktargetvartpl'; $GLOBALS['atktarget'] = $this->getNode()->m_postvars['atktarget']; $GLOBALS['atktargetvar'] = $this->getNode()->m_postvars['atktargetvar']; $GLOBALS['atktargetvartpl'] = $this->getNode()->m_postvars['atktargetvartpl']; $params['header'] = Tools::atktext('title_multiselect', $this->getNode()->m_module, $this->getNode()->m_type); $actions['actions'] = []; $actions['mra'][] = 'multiselect'; $grid = DataGrid::create($this->getNode(), 'multiselect'); /* * At first the changes below looked like the solution for the error * on the contact multiselect page. Except this is not the case, because * the MRA actions will not be shown, which is a must. */ if (is_array($actions['actions'])) { $grid->setDefaultActions($actions['actions']); } else { $grid->setDefaultActions($actions); } $grid->removeFlag(DataGrid::EXTENDED_SEARCH); $grid->addFlag(DataGrid::MULTI_RECORD_ACTIONS); $params['list'] = $grid->render(); if ($sm->atkLevel() > 0) { $backlinkurl = $sm->sessionUrl(Config::getGlobal('dispatcher') . '?atklevel=' . $sm->newLevel(SessionManager::SESSION_BACK)); $params['footer'] = '<br><div style="text-align: center"><input type="button" class="btn btn-default" onclick="window.location=\'' . $backlinkurl . '\';" value="' . Tools::atktext('cancel') . '"></div>'; } $output = $this->getUi()->renderList('multiselect', $params); return $this->getUi()->renderBox(array('title' => $this->getNode()->actionTitle('multiselect'), 'content' => $output)); }
/** * Get all attributes to select for the export. * * @return string HTML code with checkboxes for each attribute to select */ public function getAttributeSelect() { $atts = $this->getUsableAttributes(); $content = '<div class="container-fluid ExportHandler">'; foreach ($atts as $tab => $group) { $content .= '<div class="row attributes-group">'; if ($tab != 'default') { $content .= '<div class="col-sm-12 attributes-group-title">'; $content .= Tools::atktext(["tab_{$tab}", $tab], $this->m_node->m_module, $this->m_node->m_type); $content .= '</div>'; } foreach ($group as $item) { $checked = $item['checked'] ? 'CHECKED' : ''; $content .= '<div class="col-xs-12 col-sm-4 col-md-3 col-lg-2 attributes-checkbox-container">'; $content .= '<label><input type="checkbox" name="export_' . $item['name'] . '" class="atkcheckbox" value="export_' . $item['name'] . '" ' . $checked . '> ' . $item['text'] . '</label>'; $content .= '</div>'; } $content .= '</div>'; } $content .= '</div>'; return $content; }
/** * Returns an array with all the saved criteria * information. This information will be parsed * to the different. * * @param string $current * * @return array */ public function getSavedCriteria($current) { // check if table is present if (!$this->tableExist()) { return []; } return array('load_criteria' => $this->getLoadCriteria($current), 'forget_criteria' => $this->getForgetCriteria($current), 'toggle_save_criteria' => $this->getToggleSaveCriteria(), 'save_criteria' => $this->getSaveCriteria($current), 'label_load_criteria' => htmlentities(Tools::atktext('load_criteria', 'atk')), 'label_forget_criteria' => htmlentities(Tools::atktext('forget_criteria', 'atk')), 'label_save_criteria' => '<label for="toggle_save_criteria">' . htmlentities(Tools::atktext('save_criteria', 'atk')) . '</label>', 'text_save_criteria' => htmlentities(Tools::atktext('save_criteria', 'atk'))); }
/** * Gets the node and the descriptor for the current item * and returns a trace of that. * * So for instance, if we were adding a grade to a student, * it would show: * Student [ Teknoman ] - Grade [ A+ ] * * @return string The descriptortrace */ public function descriptorTrace() { $sessionData =& self::getSession(); $stack = $sessionData[$this->m_namespace]['stack'][$this->atkStackID()]; $res = []; $node = null; $module = null; $nodename = null; $stackcount = count($stack); $atk = Atk::getInstance(); for ($i = 0; $i < $stackcount; ++$i) { if (isset($stack[$i]['descriptor']) || $i == $stackcount - 1) { if ($stack[$i]['atknodeuri'] != '') { $node = $atk->atkGetNode($stack[$i]['atknodeuri']); $module = Tools::getNodeModule($stack[$i]['atknodeuri']); $nodename = Tools::getNodeType($stack[$i]['atknodeuri']); } if (is_object($node)) { $ui = Ui::getInstance(); $txt = $ui->title($module, $nodename); } else { $txt = Tools::atktext($nodename, $module); } $res[] = $txt . (isset($stack[$i]['descriptor']) ? " [ {$stack[$i]['descriptor']} ] " : ''); } } return $res; }
/** * Are we allowed to delete a record? * * @return mixed bool if allowed or string with not allowed message */ public function deleteAllowed() { if ($this->hasFlag(self::AF_RESTRICTED_DELETE)) { // Get the destination node $classname = $this->m_destination; $cache_id = $this->m_owner . '.' . $this->m_name; $atk = Atk::getInstance(); $rel = $atk->atkGetNode($classname, $cache_id); // Get the current atkselector $where = $this->translateSelector($this->m_ownerInstance->m_postvars['atkselector']); if ($where) { $childrecords = $rel->select($where)->getAllRows(); if (!empty($childrecords)) { return Tools::atktext('restricted_delete_error'); } } else { return false; } } return true; }
/** * Get the add link to add to the admin header. * * @return string HTML code with link to the add action of the node (if allowed) */ public function getAddLink() { $atk = Atk::getInstance(); $node = $atk->atkGetNode($this->invoke('getAddNodeType')); if (!$node->hasFlag(Node::NF_NO_ADD) && $node->allowed('add')) { $label = $node->text('link_' . $node->m_type . '_add', null, '', '', true); if (empty($label)) { // generic text $label = Tools::atktext('add', 'atk'); } if ($node->hasFlag(Node::NF_ADD_LINK)) { $addurl = $this->invoke('getAddUrl', $node); return Tools::href($addurl, $label, SessionManager::SESSION_NESTED); } } return ''; }
/** * Returns a piece of html code that can be used in a form to edit this * attribute's value. (hours, minutes and seconds will be a dropdownbox). * * @param array $record The record that holds the value for this attribute. * @param string $fieldprefix The fieldprefix to put in front of the name * of any html form element for this attribute. * @param string $mode The mode we're in ('add' or 'edit') * * @return string Piece a of HTML Code */ public function edit($record, $fieldprefix, $mode) { $id = $this->getHtmlId($fieldprefix); $fieldvalue = Tools::atkArrayNvl($record, $this->fieldName(), ''); if (!$this->hasFlag(self::AF_DURATION_STRING)) { $curminutes = null; $result = '<div class="form-inline">'; if ($this->m_maxtime_min >= 60) { $curhours = $this->_getHourPart($fieldvalue); $curminutes = $this->_getMinutePart($fieldvalue); $result .= '<select id="' . $id . '_hours" name="' . $this->getHtmlName($fieldprefix) . '[hours]" class="form-control select-standard">'; for ($h = 0; $h <= $this->m_maxtime_min / 60;) { $result .= '<option value="' . $h . '" '; if ($curhours == $h) { $result .= 'selected'; } $result .= '>' . $h . ' ' . Tools::atktext('hours', 'atk'); if ($this->m_resolution_min <= 60) { ++$h; } else { $h = floor($h + $this->m_resolution_min / 60); } } $result .= '</select>'; } if ($this->m_maxtime_min >= 1 && $this->m_resolution_min < 60) { $result .= ' <select id="' . $id . '_minutes" name="' . $this->getHtmlName($fieldprefix) . '[minutes]" class="form-control select-standard">'; for ($m = 0; $m < 60 || $this->m_maxtime_min < 60 && $m < $this->m_maxtime_min;) { $result .= '<option value="' . $m . '" '; if ($curminutes == $m) { $result .= 'selected'; } $result .= '>' . $m . ' ' . Tools::atktext('minutes', 'atk'); if ($this->m_resolution_min <= 1) { ++$m; } else { $m = $m + $this->m_resolution_min; } } $result .= '</select>'; } $result .= '</div>'; } else { $curval = $fieldvalue > 0 ? $this->_minutes2string($fieldvalue) : ''; $result = '<input type="text" name="' . $this->getHtmlName($fieldprefix) . '" value="' . $curval . '"' . ($this->m_size > 0 ? ' size="' . $this->m_size . '"' : '') . '>'; } return $result; }
/** * Get the access denied page. * * @return string the HTML code of the access denied page */ public function _getAccessDeniedPage() { $ui = $this->m_node->getUi(); $content = '<br><br>' . Tools::atktext('error_node_action_access_denied', '', $this->m_node->getType()) . '<br><br><br>'; $blocks = [$ui->renderBox(['title' => Tools::atktext('access_denied'), 'content' => $content])]; return $ui->render('actionpage.tpl', ['blocks' => $blocks, 'title' => Tools::atktext('access_denied')]); }
/** * Validates absolute, relative and anchor URL through regular expression. * * @param array $record Record that contains value to be validated. * Errors are saved in this record, in the 'atkerror' * field. * @param string $mode Validation mode. Can be either "add" or "update" * @param bool $show_error fire a triggerError when validation fails */ public function validateUrl(&$record, $mode, $show_error = false) { $result = false; $absolute_result = true; $anchor_result = true; $absolute_anchor_result = true; $relative_result = true; $base_url_regex = "(ft|htt)ps?:\\/\\/[a-zA-Z0-9\\.\\-\\_]+\\.[a-zA-Z]{2,4}"; $relative_url_regex = "[a-zA-Z0-9\\.\\-\\_\\/?&=%]"; $relative_url_regex_with_anchor = "[a-zA-Z0-9\\.\\-\\_\\/?&=%#]"; /* * Validate URL, check if format is absolute (external URL's) and has no anchor * * Example: http://www2-dev.test_url.com * or: ftp://www2-dev.test_url.com/index.php?/feeds/index.rss2 */ if (($this->m_accepts_url_flag & self::ABSOLUTE) == self::ABSOLUTE) { $absolute_result = preg_match('/^' . $base_url_regex . $relative_url_regex . '*$/Ui', $record[$this->fieldName()]) ? true : false; $result = $result || $absolute_result; } /* * Validate URL, check if format is a valid anchor * * Example: #internal_bookmark */ if (($this->m_accepts_url_flag & self::ANCHOR) == self::ANCHOR) { $anchor_result = preg_match('/^#' . $relative_url_regex . '*$/Ui', $record[$this->fieldName()]) ? true : false; $result = $result || $anchor_result; } /* * Validate URL, check if format is absolute (external URL's) and has (optional) anchor * * Example: http://www2-dev.test_url.com * or: ftp://www2-dev.test_url.com/index.php?/feeds/index.rss2 * or: https://www2-dev.test_url.com/index.php?/history.html#bookmark */ if (($this->m_accepts_url_flag & self::ABSOLUTE) == self::ABSOLUTE && ($this->m_accepts_url_flag & self::ANCHOR) == self::ANCHOR) { $absolute_anchor_result = preg_match('/^' . $base_url_regex . $relative_url_regex_with_anchor . '*$/Ui', $record[$this->fieldName()]) ? true : false; $result = $result || $absolute_anchor_result; } /* * Validate URL, check if format is relative * * Example: /mysite/guestbook/index.html */ if (($this->m_accepts_url_flag & self::RELATIVE) == self::RELATIVE) { $relative_result = preg_match('/^' . $relative_url_regex_with_anchor . '+$/Ui', $record[$this->fieldName()]) ? true : false; $result = $result || $relative_result; } /* * If an error occured, show applicable message(s) */ if (!$result && $show_error) { // if result of all validations is false, display error-messages if ($absolute_result === false) { Tools::triggerError($record, $this->fieldName(), 'invalid_absolute_no_anchor_url', Tools::atktext('invalid_absolute_no_anchor_url')); } if ($anchor_result === false) { Tools::triggerError($record, $this->fieldName(), 'invalid_url_anchor', Tools::atktext('invalid_url_anchor')); } if ($absolute_anchor_result === false) { Tools::triggerError($record, $this->fieldName(), 'invalid_absolute_url', Tools::atktext('invalid_absolute_url')); } if ($relative_result === false) { Tools::triggerError($record, $this->fieldName(), 'invalid_relative_url', Tools::atktext('invalid_relative_url')); } } if (!$result) { parent::validate($record, $mode); } }
/** * Checks with each of the attributes of the node whose record is about to be deleted * if they allow the deletion. * * @return bool wether or not the attributes have allowed deletion */ public function checkAttributes() { foreach ($this->m_node->getAttributes() as $attrib) { // If allowed !=== true, then it returned an error message if ($attrib->deleteAllowed() !== true) { $db = $this->m_node->getDb(); $db->rollback(); $location = $this->m_node->feedbackUrl('delete', self::ACTION_FAILED, null, sprintf(Tools::atktext('attrib_delete_not_allowed'), Tools::atktext($attrib->m_name, $this->m_node->m_module, $this->m_node->m_type))); $this->m_node->redirect($location); return false; } } return true; }
public function search($record, $extended = false, $fieldprefix = '', DataGrid $grid = null) { $useautocompletion = Config::getGlobal('manytoone_search_autocomplete', true) && $this->hasFlag(self::AF_RELATION_AUTOCOMPLETE); $id = $this->getHtmlId($fieldprefix); $name = $this->getSearchFieldName($fieldprefix); $htmlAttributes = []; if (!$this->hasFlag(self::AF_LARGE) && !$useautocompletion) { //Normal dropdown search if (!$this->createDestination()) { return ''; } $recordset = $this->_getSelectableRecords($record, 'search'); if (isset($record[$this->fieldName()][$this->fieldName()])) { $record[$this->fieldName()] = $record[$this->fieldName()][$this->fieldName()]; } $selValues = isset($record[$this->fieldName()]) ? $record[$this->fieldName()] : null; if (!is_array($selValues)) { $selValues = [$selValues]; } if (in_array('', $selValues)) { $selValues = ['']; } $options = []; $options[''] = Tools::atktext('search_all'); $options['__NONE__'] = $this->getNoneLabel('search'); $pkfield = $this->m_destInstance->primaryKeyField(); foreach ($recordset as $option) { $pk = $option[$pkfield]; $options[$pk] = $this->m_destInstance->descriptor($option); } if (!is_null($grid) && !$extended && $this->m_autoSearch) { $onchange = $grid->getUpdateCall(array('atkstartat' => 0), [], 'ATK.DataGrid.extractSearchOverrides'); $this->getOwnerInstance()->getPage()->register_loadscript('jQuery("#' . $id . '").on("change", function(el){' . $onchange . '});'); } $selectOptions = []; $selectOptions['enable-select2'] = true; $selectOptions['allow-clear'] = true; $selectOptions['dropdown-auto-width'] = true; $selectOptions['placeholder'] = Tools::atktext('search_all'); $selectOptions = array_merge($selectOptions, $this->m_select2Options['search']); // width always auto $selectOptions['width'] = 'auto'; return $this->drawSelect($id, $name, $options, $selValues, $selectOptions, $htmlAttributes); } else { //Autocomplete search if (isset($record[$this->fieldName()][$this->fieldName()])) { $record[$this->fieldName()] = $record[$this->fieldName()][$this->fieldName()]; } $current = isset($record[$this->fieldName()]) ? $record[$this->fieldName()] : null; if ($useautocompletion) { $noneLabel = $this->getNoneLabel('search'); $options = []; $options[''] = $noneLabel; $selValues = isset($record[$this->fieldName()]) ? $record[$this->fieldName()] : null; if (!is_array($selValues)) { $selValues = [$selValues]; } foreach ($selValues as $selValue) { $options[$selValue] = $selValue; } $selectOptions = []; $selectOptions['enable-select2'] = true; $selectOptions['enable-manytoonereleation-autocomplete'] = true; $selectOptions['tags'] = true; $selectOptions['ajax--url'] = Tools::partial_url($this->m_ownerInstance->atkNodeUri(), $this->m_ownerInstance->m_action, 'attribute.' . $this->fieldName() . '.autocomplete_search'); $selectOptions['minimum-input-length'] = $this->m_autocomplete_minchars; $selectOptions['allow-clear'] = true; $selectOptions['dropdown-auto-width'] = true; $selectOptions['placeholder'] = $noneLabel; $selectOptions = array_merge($selectOptions, $this->m_select2Options['search']); //width always auto $selectOptions['width'] = 'auto'; return $this->drawSelect($id, $name, $options, $selValues, $selectOptions, $htmlAttributes); } else { //normal input field $result = '<input type="text" id="' . $id . '" name="' . $name . '" ' . $this->getCSSClassAttribute('form-control') . ' value="' . $current . '"' . ($this->m_searchsize > 0 ? ' size="' . $this->m_searchsize . '"' : '') . ($this->m_maxsize > 0 ? ' maxlength="' . $this->m_maxsize . '"' : '') . '>'; } return $result; } }