diff --git a/wire/core/AdminTheme.php b/wire/core/AdminTheme.php index d1f4ec69..6e971841 100644 --- a/wire/core/AdminTheme.php +++ b/wire/core/AdminTheme.php @@ -249,31 +249,37 @@ abstract class AdminTheme extends WireData implements Module { // we already have this field installed, no need to continue if($field) { $this->message($toUseNote); - return; + } else { + // this will be the 2nd admin theme installed, so add a field that lets them select admin theme + $field = $this->wire(new Field()); + $field->name = 'admin_theme'; + $field->type = $this->wire('modules')->get('FieldtypeModule'); + $field->set('moduleTypes', array('AdminTheme')); + $field->set('labelField', 'title'); + $field->set('inputfieldClass', 'InputfieldRadios'); + $field->label = 'Admin Theme'; + $field->flags = Field::flagSystem; + try { + $field->save(); + } catch(\Exception $e) { + $this->error("Error creating 'admin_theme' field: " . $e->getMessage()); + } } - // this will be the 2nd admin theme installed, so add a field that lets them select admin theme - $field = $this->wire(new Field()); - $field->name = 'admin_theme'; - $field->type = $this->wire('modules')->get('FieldtypeModule'); - $field->set('moduleTypes', array('AdminTheme')); - $field->set('labelField', 'title'); - $field->set('inputfieldClass', 'InputfieldRadios'); - $field->label = 'Admin Theme'; - $field->flags = Field::flagSystem; - $field->save(); - - $fieldgroup = $this->wire('fieldgroups')->get('user'); - $fieldgroup->add($field); - $fieldgroup->save(); - - // make this field one that the user is allowed to configure in their profile - $data = $this->wire('modules')->getModuleConfigData('ProcessProfile'); - $data['profileFields'][] = 'admin_theme'; - $this->wire('modules')->saveModuleConfigData('ProcessProfile', $data); - - $this->message($this->_('Installed field "admin_theme" and added to user profile settings.')); - $this->message($toUseNote); + if($field && $field->id) { + /** @var Fieldgroup $fieldgroup */ + $fieldgroup = $this->wire('fieldgroups')->get('user'); + if(!$fieldgroup->hasField($field)) { + $fieldgroup->add($field); + $fieldgroup->save(); + $this->message($this->_('Installed field "admin_theme" and added to user profile settings.')); + $this->message($toUseNote); + } + // make this field one that the user is allowed to configure in their profile + $data = $this->wire('modules')->getModuleConfigData('ProcessProfile'); + $data['profileFields'][] = 'admin_theme'; + $this->wire('modules')->saveModuleConfigData('ProcessProfile', $data); + } } /** diff --git a/wire/core/InputfieldWrapper.php b/wire/core/InputfieldWrapper.php index c235bcab..cb23b08f 100644 --- a/wire/core/InputfieldWrapper.php +++ b/wire/core/InputfieldWrapper.php @@ -101,6 +101,14 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre */ protected $requiredLabel = ''; + /** + * Whether or not column width is handled internally + * + * @var bool + * + */ + protected $useColumnWidth = true; + /** * Construct the Inputfield, setting defaults for all properties * @@ -119,6 +127,8 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre if(is_array($settings)) foreach($settings as $key => $value) { if($key == 'requiredLabel') { $this->requiredLabel = $value; + } else if($key == 'useColumnWidth') { + $this->useColumnWidth = $value; } else { $this->set($key, $value); } @@ -368,7 +378,7 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre $_classes = array_merge(self::$defaultClasses, self::$classes); $markup = array(); $classes = array(); - $useColumnWidth = true; + $useColumnWidth = $this->useColumnWidth; $renderAjaxInputfield = $this->wire('config')->ajax ? $this->wire('input')->get('renderInputfieldAjax') : null; if(isset($_classes['form']) && strpos($_classes['form'], 'InputfieldFormNoWidths') !== false) { @@ -534,20 +544,25 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre } else if(strpos($label, '{class}') !== false) { $label = str_replace('{class}', '', $label); } + } else { + // no header + // $inputfield->addClass('InputfieldNoHeader', 'wrapClass'); } - if($useColumnWidth) { - $columnWidth = (int) $inputfield->getSetting('columnWidth'); - $columnWidthAdjusted = $columnWidth + ($columnWidthTotal ? -1 * $columnWidthSpacing : 0); - if($columnWidth >= 9 && $columnWidth <= 100) { - $ffAttrs['class'] .= ' ' . $classes['item_column_width']; - if(!$columnWidthTotal) $ffAttrs['class'] .= ' ' . $classes['item_column_width_first']; + $columnWidth = (int) $inputfield->getSetting('columnWidth'); + $columnWidthAdjusted = $columnWidth + ($columnWidthTotal ? -1 * $columnWidthSpacing : 0); + if($columnWidth >= 9 && $columnWidth <= 100) { + $ffAttrs['class'] .= ' ' . $classes['item_column_width']; + if(!$columnWidthTotal) $ffAttrs['class'] .= ' ' . $classes['item_column_width_first']; + if($useColumnWidth) { $ffAttrs['style'] = "width: $columnWidthAdjusted%;"; - $columnWidthTotal += $columnWidth; - //if($columnWidthTotal >= 100 && !$requiredIf) $columnWidthTotal = 0; // requiredIf meant to be a showIf? - if($columnWidthTotal >= 100) $columnWidthTotal = 0; } else { - $columnWidthTotal = 0; + $ffAttrs['data-colwidth'] = "$columnWidthAdjusted%"; } + $columnWidthTotal += $columnWidth; + //if($columnWidthTotal >= 100 && !$requiredIf) $columnWidthTotal = 0; // requiredIf meant to be a showIf? + if($columnWidthTotal >= 100) $columnWidthTotal = 0; + } else { + $columnWidthTotal = 0; } if(!isset($ffAttrs['id'])) $ffAttrs['id'] = 'wrap_' . $inputfield->attr('id'); $ffAttrs['class'] = str_replace('Inputfield_ ', '', $ffAttrs['class']); diff --git a/wire/core/ProcessController.php b/wire/core/ProcessController.php index 6a81b2bb..a374118b 100644 --- a/wire/core/ProcessController.php +++ b/wire/core/ProcessController.php @@ -157,8 +157,8 @@ class ProcessController extends Wire { // set a proces fuel, primarily so that certain Processes can determine if they are the root Process // example: PageList when in PageEdit - $this->wire('process', $this->process); - + $this->wire('process', $this->process); + return $this->process; } diff --git a/wire/core/ProcessWire.php b/wire/core/ProcessWire.php index ab23c6ec..f79abce1 100644 --- a/wire/core/ProcessWire.php +++ b/wire/core/ProcessWire.php @@ -45,7 +45,7 @@ class ProcessWire extends Wire { * Reversion revision number * */ - const versionRevision = 52; + const versionRevision = 53; /** * Version suffix string (when applicable) @@ -754,6 +754,7 @@ class ProcessWire extends Wire { $httpHost = ''; $scheme = ''; $siteDir = isset($options['siteDir']) ? $options['siteDir'] : 'site'; + $cfg = array('dbName' => ''); if($rootURL && strpos($rootURL, '://')) { // rootURL is specifying scheme and hostname @@ -771,9 +772,7 @@ class ProcessWire extends Wire { $rootPath = rtrim($rootPath, '/'); $_rootURL = $rootURL; if(is_null($rootURL)) $rootURL = '/'; - - $config = new Config(); - $config->dbName = ''; + $sitePath = $rootPath . "/$siteDir/"; // check what rootPath is referring to if(strpos($rootPath, "/$siteDir")) { @@ -804,11 +803,11 @@ class ProcessWire extends Wire { unset($sf, $f, $x); // when internal is true, we are not being called by an external script - $config->internal = $realIndexFile == $realScriptFile; + $cfg['internal'] = $realIndexFile == $realScriptFile; } else { // when included from another app or command line script - $config->internal = false; + $cfg['internal'] = false; $host = ''; } @@ -841,36 +840,43 @@ class ProcessWire extends Wire { $adminTplDir = 'templates-admin'; // create new Config instance - $config->urls = new Paths($rootURL); - $config->urls->wire = "$wireDir/"; - $config->urls->site = "$siteDir/"; - $config->urls->modules = "$wireDir/modules/"; - $config->urls->siteModules = "$siteDir/modules/"; - $config->urls->core = "$coreDir/"; - $config->urls->assets = "$assetsDir/"; - $config->urls->cache = "$assetsDir/cache/"; - $config->urls->logs = "$assetsDir/logs/"; - $config->urls->files = "$assetsDir/files/"; - $config->urls->tmp = "$assetsDir/tmp/"; - $config->urls->templates = "$siteDir/templates/"; - $config->urls->fieldTemplates = "$siteDir/templates/fields/"; - $config->urls->adminTemplates = is_dir("$siteDir/$adminTplDir") ? "$siteDir/$adminTplDir/" : "$wireDir/$adminTplDir/"; - $config->paths = clone $config->urls; - $config->paths->root = $rootPath . '/'; - $config->paths->sessions = $config->paths->assets . "sessions/"; + $cfg['urls'] = new Paths($rootURL); + $cfg['urls']->data(array( + 'wire' => "$wireDir/", + 'site' => "$siteDir/", + 'modules' => "$wireDir/modules/", + 'siteModules' => "$siteDir/modules/", + 'core' => "$coreDir/", + 'assets' => "$assetsDir/", + 'cache' => "$assetsDir/cache/", + 'logs' => "$assetsDir/logs/", + 'files' => "$assetsDir/files/", + 'tmp' => "$assetsDir/tmp/", + 'templates' => "$siteDir/templates/", + 'fieldTemplates' => "$siteDir/templates/fields/", + 'adminTemplates' => "$wireDir/$adminTplDir/", + ), true); + + $cfg['paths'] = clone $cfg['urls']; + $cfg['paths']->set('root', $rootPath . '/'); + $cfg['paths']->data('sessions', $cfg['paths']->assets . "sessions/"); // Styles and scripts are CSS and JS files, as used by the admin application. // But reserved here if needed by other apps and templates. - $config->styles = new FilenameArray(); - $config->scripts = new FilenameArray(); + $cfg['styles'] = new FilenameArray(); + $cfg['scripts'] = new FilenameArray(); + + $config = new Config(); + $config->setTrackChanges(false); + $config->data($cfg, true); // Include system config defaults /** @noinspection PhpIncludeInspection */ require("$rootPath/$wireDir/config.php"); // Include site-specific config settings - $configFile = $config->paths->site . "config.php"; - $configFileDev = $config->paths->site . "config-dev.php"; + $configFile = $sitePath . "config.php"; + $configFileDev = $sitePath . "config-dev.php"; if(is_file($configFileDev)) { /** @noinspection PhpIncludeInspection */ @require($configFileDev); @@ -883,8 +889,9 @@ class ProcessWire extends Wire { $config->httpHost = $httpHost; if(!in_array($httpHost, $config->httpHosts)) $config->httpHosts[] = $httpHost; } + if($scheme) $config->https = ($scheme === 'https'); - + return $config; } diff --git a/wire/core/Wire.php b/wire/core/Wire.php index 1f0ecb6c..b0cf7652 100644 --- a/wire/core/Wire.php +++ b/wire/core/Wire.php @@ -364,16 +364,53 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable { * * #pw-internal * - * @param $method - * @param $arguments + * @param string $method + * @param array $arguments * @return mixed * */ public function _callMethod($method, $arguments) { - if(empty($arguments)) { - return $this->$method(); + $qty = $arguments ? count($arguments) : 0; + $result = null; + switch($qty) { + case 0: + $result = $this->$method(); + break; + case 1: + $result = $this->$method($arguments[0]); + break; + case 2: + $result = $this->$method($arguments[0], $arguments[1]); + break; + case 3: + $result = $this->$method($arguments[0], $arguments[1], $arguments[2]); + break; + default: + $result = call_user_func_array(array($this, $method), $arguments); + } + return $result; + } + + /** + * Call a hook method (optimization when it's known for certain the method exists) + * + * #pw-internal + * + * @param string $method Method name, without leading "___" + * @param array $arguments + * @return mixed + * + */ + public function _callHookMethod($method, array $arguments = array()) { + if(method_exists($this, $method)) { + return $this->_callMethod($method, $arguments); + } + $hooks = $this->wire('hooks'); + if($hooks->isMethodHooked($this, $method)) { + $result = $hooks->runHooks($this, $method, $arguments); + return $result['return']; } else { - return call_user_func_array(array($this, $method), $arguments); + return $this->_callMethod("___$method", $arguments); } } diff --git a/wire/core/WireData.php b/wire/core/WireData.php index d754bb50..20246c7a 100644 --- a/wire/core/WireData.php +++ b/wire/core/WireData.php @@ -202,16 +202,24 @@ class WireData extends Wire implements \IteratorAggregate, \ArrayAccess { * $value = $item->data('some_property'); * ~~~~~ * - * @param string $key Property you want to get or set. - * @param mixed $value Optionally specify a value if you want to set rather than get. - * @return mixed|null|$this Returns one of the following: + * @param string|array $key Property you want to get or set, or associative array of properties you want to set. + * @param mixed $value Optionally specify a value if you want to set rather than get. + * Or Specify boolean TRUE if setting an array via $key and you want to overwrite any existing values (rather than merge). + * @return array|WireData|null Returns one of the following: * - `mixed` - Actual value if getting a previously set value. * - `null` - If you are attempting to get a value that has not been set. * - `$this` - If you are setting a value. */ public function data($key = null, $value = null) { if(is_null($key)) return $this->data; - if(is_null($value)) { + if(is_array($key)) { + if($value === true) { + $this->data = $key; + } else { + $this->data = array_merge($this->data, $key); + } + return $this; + } else if(is_null($value)) { return isset($this->data[$key]) ? $this->data[$key] : null; } else { $this->data[$key] = $value; diff --git a/wire/core/admin.php b/wire/core/admin.php index 58661f7f..538a4cd9 100644 --- a/wire/core/admin.php +++ b/wire/core/admin.php @@ -111,6 +111,7 @@ if($page->process && $page->process != 'ProcessPageView') { } if($input->get('modal')) $session->addHookBefore('redirect', null, '_hookSessionRedirectModal'); $content = $controller->execute(); + $process = $controller->wire('process'); } catch(Wire404Exception $e) { $wire->error($e->getMessage()); @@ -168,6 +169,7 @@ if($controller && $controller->isAjax()) { if(!strlen($content)) $content = '

' . __('The process returned no content.') . '

'; $adminThemeFile = $config->paths->adminTemplates . 'default.php'; if(strpos($adminThemeFile, $config->paths->site) === 0) { + // @todo determine if compilation needed $adminThemeFile = $wire->files->compile($adminThemeFile); } /** @noinspection PhpIncludeInspection */ diff --git a/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.css b/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.css index b30f69ae..cf977bf5 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.css +++ b/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.css @@ -1,49 +1,41 @@ -.InputfieldCommentsAdmin .CommentsAdminItemHead { - margin-bottom: 0; -} - -.InputfieldCommentsAdmin p label, -.InputfieldCommentsAdmin p input, -.InputfieldCommentsAdmin p select { - display: block; -} - -.InputfieldCommentsAdmin .CommentsAdminItemCite, -.InputfieldCommentsAdmin .CommentsAdminItemEmail, -.InputfieldCommentsAdmin .CommentsAdminItemWebsite, -.InputfieldCommentsAdmin .CommentsAdminItemStatus, -.InputfieldCommentsAdmin .CommentsAdminItemDelete { - float: left; - width: 23%; - margin-right: 2%; -} - -.InputfieldCommentsAdmin .CommentsAdminItemStatus { -} - -.InputfieldCommentsAdmin .CommentsAdminItemCite input, -.InputfieldCommentsAdmin .CommentsAdminItemWebsite input, -.InputfieldCommentsAdmin .CommentsAdminItemEmail input { - width: 100%; +.InputfieldCommentsAdmin input[type=text], +.InputfieldCommentsAdmin input[type=email], +.InputfieldCommentsAdmin input[type=url], +.InputfieldCommentsAdmin select, +.InputfieldCommentsAdmin textarea { + width: 100%; } .InputfieldCommentsAdmin .CommentsAdminItemText { - clear: both; margin-bottom: 0; } -.InputfieldCommentsAdmin .CommentsAdminItemHeadLabel { - float: right; - padding-right: 1em; -} - -.InputfieldCommentsAdminList > li > .ui-widget-content { - padding: 1em; -} -.InputfieldCommentsAdminList > li > .ui-widget-content > p { +.InputfieldCommentsAdmin .InputfieldContent > .ui-helper-clearfix > p { + float: left; + width: 23%; margin-top: 0; + margin-right: 2%; } -.InputfieldCommentsAdminList > li > .ui-widget-content label { - font-weight: bold; +.InputfieldCommentsAdmin .InputfieldContent p label, +.InputfieldCommentsAdmin .InputfieldContent p input { + display: block; +} + +.InputfieldCommentsAdmin:not(.InputfieldIsOffset) .Inputfields > .Inputfield { + margin: 3px 0; +} + +@media screen and (max-width: 768px) { + .InputfieldCommentsAdmin .InputfieldContent > .ui-helper-clearfix > p { + width: 48%; + } +} + +@media screen and (max-width: 500px) { + .InputfieldCommentsAdmin .InputfieldContent > .ui-helper-clearfix > p { + width: 100%; + margin-right: 0; + float: none; + } } diff --git a/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.module b/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.module index 3dab6f79..87ccff9d 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.module +++ b/wire/modules/Fieldtype/FieldtypeComments/InputfieldCommentsAdmin.module @@ -31,26 +31,44 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList { protected function ___renderItem(Comment $comment, $n) { $statuses = array( - Comment::statusApproved => $this->_x('Approved', 'comment-status'), - Comment::statusPending => $this->_x('Pending', 'comment-status'), - Comment::statusSpam => $this->_x('Spam', 'comment-status'), + Comment::statusApproved => array($this->_x('Approved', 'comment-status'), 'check-circle'), + Comment::statusPending => array($this->_x('Pending', 'comment-status'), 'question-circle'), + Comment::statusSpam => array($this->_x('Spam', 'comment-status'), 'warning'), ); + $name = $this->name; + $names = array( + 'status' => "{$this->name}_status_{$comment->id}", + 'parent' => "{$this->name}_parent_id_{$comment->id}", + 'cite' => "{$name}_cite_{$comment->id}", + 'email' => "{$name}_email_{$comment->id}", + 'website' => "{$name}_website_{$comment->id}", + 'stars' => "{$name}_stars_{$comment->id}", + 'text' => "{$name}_text_{$comment->id}" + ); + + + $sanitizer = $this->wire('sanitizer'); $statusName = ''; - $statusOut = ""; + + foreach($statuses as $status => $statusInfo) { + list($label, $icon) = $statusInfo; if($comment->status == $status) { $selected = " selected='selected'"; $statusName = $label; + $statusIcon = $icon; } else { $selected = ''; } $statusOut .= ""; } + $statusOut .= ""; $statusOut .= ""; - $parentOut = ""; $parentID = $comment->parent_id; $_n = 0; foreach($this->value as $_comment) { @@ -76,57 +94,96 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList { $num = $n+1; $liID = "CommentsAdminItem{$comment->id}"; + $f = $this->wire('modules')->get('InputfieldMarkup'); + $f->attr('id', $liID); + $f->addClass("CommentsAdminItem$statusName"); + $f->icon = $statusIcon; - if($comment->status == Comment::statusApproved) $liClass = "InputfieldStateCollapsed"; - else if($comment->status == Comment::statusSpam) $liClass = "InputfieldStateCollapsed CommentsAdminItemSpam ui-state-error"; - else $liClass = ''; - - if($comment->status == Comment::statusSpam) $note = $this->_("Spam is automatically deleted after the amount of time specified in the field configuration."); - else if($comment->status == Comment::statusPending) $note = $this->_("This item is awaiting approval or deletion."); - else $note = ''; - - if($note) $note = "\n\t\t\t

$note

"; + if($comment->status == Comment::statusSpam) { + $f->addClass("CommentsAdminItemSpam InputfieldIsError InputfieldStateError", 'wrapClass'); + $f->description = $this->_("Spam is automatically deleted after the amount of time specified in the field configuration."); + $f->collapsed = Inputfield::collapsedYes; + } else if($comment->status == Comment::statusApproved) { + $f->collapsed = Inputfield::collapsedYes; + $f->addClass('InputfieldIsSuccess'); + } else if($comment->status == Comment::statusPending) { + $f->addClass('InputfieldIsPrimary'); + $f->description = $this->_("This item is awaiting approval or deletion."); + } + $cite = $sanitizer->entities($comment->cite); + $email = $sanitizer->entities($comment->email); + $website = $sanitizer->entities($comment->website); + $stars = $sanitizer->entities($comment->stars); + $text = $sanitizer->entities(trim($comment->text)); + + $f->label = strtoupper($headLabel) . ': ' . sprintf( + $this->_('Comment #%1$d Posted %2$s by %3$s'), + $num, + wireRelativeTimeStr($comment->created), + $cite + ); + + $f->value = + "
" . + "

" . + "" . + $statusOut . + "

" . + "

" . + "" . + $parentOut . + "

" . + "
" . + "

" . + "" . + "" . + "

" . + "

" . + "" . + "" . + "

" . + "

" . + "" . + "" . + "

" . + "

" . + "" . + "" . + "

" . + "
" . + "

" . + "" . + "" . + "

" . + ($notifyOut ? "

" . $this->_('Email notifications:') . " $notifyOut

" : "") . + "" . + ""; - $out = - "\n\t
  • " . - "\n\t\t" . - "\n\t\t
    " . $note . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - "\n\t\t\t

    " . - ($notifyOut ? "\n\t\t\t

    " . $this->_('Email notifications:') . " $notifyOut

    " : "") . - "\n\t\t\t" . - "\n\t\t
    " . - "\n\t
  • "; - - return $out; + return $f; } public function ___render() { - $out = ''; - if(!count($this->value)) return "

    " . $this->_('There are currently no items to display.') . "

    "; $n = 0; foreach($this->value as $comment) { $this->commentIDsToNumbers[$comment->id] = ++$n; } - + + $fieldset = new InputfieldWrapper(); + $this->wire($fieldset); + $n = 0; - $out = "\n"; + + $out = $fieldset->render(); + //$this->addClass('InputfieldFieldset', 'wrapClass'); return $out; } diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.css b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.css index f812fc88..56a42dce 100755 --- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.css +++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.css @@ -27,7 +27,10 @@ padding: .3em .5em; } .gridImages { + list-style: none; + padding-left: 0; position: relative; + margin: 0; margin-right: -.6em; display: block; list-style: none; } diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js index 0bfdc175..831aac10 100755 --- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js +++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js @@ -713,16 +713,20 @@ function InputfieldImage($) { var w = $img.width(); var h = $img.height(); - //if(!w) w = gridSize; // parseInt($img.attr('data-w')); - //if(!h) h = gridSize; // parseInt($img.attr('data-h')); + if(!w) w = parseInt($img.attr('data-w')); + if(!h) h = parseInt($img.attr('data-h')); if(ragged) { + $img.css('max-height', '100%').css('max-width', 'none'); $img.attr('height', gridSize).removeAttr('width'); } else if(w >= h) { + $img.css('max-height', '100%').css('max-width', 'none'); $img.attr('height', gridSize).removeAttr('width'); } else if(h > w) { + $img.css('max-height', 'none').css('max-width', '100%'); $img.attr('width', gridSize).removeAttr('height'); } else { + $img.css('max-height', '100%').css('max-width', 'none'); $img.removeAttr('width').attr('height', gridSize); } @@ -1158,7 +1162,7 @@ function InputfieldImage($) { /** * Setup the dropzone where files are dropped * - * @param $el + * @param $el .InputfieldContent element * */ function setupDropzone($el) { @@ -1167,17 +1171,30 @@ function InputfieldImage($) { if($el.hasClass('InputfieldImageDropzoneInit')) return; var el = $el.get(0); + var $inputfield = $el.closest('.Inputfield'); + + function dragStart() { + if($inputfield.hasClass('pw-drag-in-file')) return; + $el.addClass('ui-state-hover'); + $inputfield.addClass('pw-drag-in-file InputfieldStateConfirmLeave'); + } + + function dragStop() { + if(!$inputfield.hasClass('pw-drag-in-file')) return; + $el.removeClass('ui-state-hover'); + $inputfield.removeClass('pw-drag-in-file'); + } el.addEventListener("dragleave", function() { - $el.removeClass('ui-state-hover'); + dragStop(); }, false); el.addEventListener("dragenter", function() { - $el.addClass('ui-state-hover'); + dragStart(); }, false); el.addEventListener("dragover", function(evt) { - if(!$el.is('ui-state-hover')) $el.addClass('ui-state-hover'); + if(!$el.is('ui-state-hover')) dragStart(); evt.preventDefault(); evt.stopPropagation(); return false; @@ -1185,7 +1202,7 @@ function InputfieldImage($) { el.addEventListener("drop", function(evt) { traverseFiles(evt.dataTransfer.files); - $el.removeClass("ui-state-hover"); + dragStop(); evt.preventDefault(); evt.stopPropagation(); return false; @@ -1205,6 +1222,14 @@ function InputfieldImage($) { var $i = null; // placeholder .gridItem var haltDrag = false; // true when drag should be halted var timer = null; // for setTimeout + var $inputfield = $gridImages.closest('.Inputfield'); + + function addInputfieldClass() { + $inputfield.addClass('pw-drag-in-file'); + } + function removeInputfieldClass() { + $inputfield.removeClass('pw-drag-in-file'); + } function getCenterCoordinates($el) { var offset = $el.offset(); @@ -1228,6 +1253,7 @@ function InputfieldImage($) { if(noDropInPlace()) return; evt.preventDefault(); evt.stopPropagation(); + addInputfieldClass(); haltDrag = false; if($i == null) { var gridSize = $gridImages.attr('data-size') + 'px'; @@ -1249,6 +1275,7 @@ function InputfieldImage($) { if(noDropInPlace()) return; evt.preventDefault(); evt.stopPropagation(); + addInputfieldClass(); haltDrag = false; if($i == null) return; // $('.gridImage', $gridImages).trigger('drag'); @@ -1270,12 +1297,14 @@ function InputfieldImage($) { if(!haltDrag || $i == null) return; $i.remove(); $i = null; + removeInputfieldClass(); }, 1000); } function drop(evt) { if(noDropInPlace()) return; - + + removeInputfieldClass(); // console.log(evt.originalEvent.dataTransfer.files); haltDrag = false; diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.min.js b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.min.js index faf6a94f..879f4f9e 100644 --- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.min.js +++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.min.js @@ -1 +1 @@ -function InputfieldImage(u){var k=null;var b={file:"",item:null,edit:null};var E={type:"image",closeOnContentClick:true,closeBtnInside:true};var c=null;var q=[];function r(){var L=window.File&&window.FileList&&window.FileReader;var K=u(".InputfieldAllowAjaxUpload").length>0;var M=u("#PageIDIndicator").length>0;return(L&&(M||K))}function x(M,K,L){K||(K=250);var N,O;return function(){var R=L||this;var Q=+new Date(),P=arguments;if(N&&Q .gridImage",start:function(P,O){var N=D(L.closest(".Inputfield"),"size");O.placeholder.append(u("
    ").css({display:"block",height:N+"px",width:N+"px"}));M=window.setTimeout(function(){F(L,null)},100);L.addClass("InputfieldImageSorting")},stop:function(P,N){var O=u(this);if(M!==null){N.item.find(".InputfieldImageEdit__edit").click();clearTimeout(M)}O.children("li").each(function(R){var Q=u(this).find(".InputfieldFileSort");if(Q.val()!=R){Q.val(R).change()}});L.removeClass("InputfieldImageSorting")},cancel:".InputfieldImageEdit"};L.sortable(K)}function o(L){var K=u.extend(true,{},E);K.callbacks={elementParse:function(M){var N=u(M.el).attr("data-original");if(typeof N=="undefined"||!N){N=u(M.el).attr("src")}M.src=N}};K.gallery={enabled:true};L.find("img").magnificPopup(K)}function s(L){var K=u.extend(true,{},E);K.callbacks={elementParse:function(M){M.src=u(M.el).attr("src")}};K.gallery={enabled:false};L.find("img").magnificPopup(K)}function B(K){return K.find(".InputfieldImageEdit--active")}function t(K){return u("#"+K.find(".InputfieldImageEdit__edit").attr("data-current"))}function C(M){var K=M.is(":checked");var L=M.parents(".gridImages").find(".gridImage__deletebox");if(K){L.prop("checked","checked").change()}else{L.removeAttr("checked").change()}}function I(L){if(typeof L=="undefined"){var K=u(".gridImages")}else{var K=L.find(".gridImages")}K.each(function(){var M=u(this),N=B(M);if(N.length){i(t(N),N)}})}function v(Q){var M=[];var P=[];var O=0,K=0;var N;if(typeof Q=="undefined"){N=u(".InputfieldImage.Inputfield")}else{N=Q}N.removeClass("InputfieldImageNarrow");N.each(function(){var S=u(this);var T=S.width();if(T<1){return}if(T<=500){M[O]=S;O++}});for(var R=0;R=P){N.attr("height",L).removeAttr("width")}else{if(P>K){N.attr("width",L).removeAttr("height")}else{N.removeAttr("width").attr("height",L)}}}var K=N.width();if(K){M.css({width:(O?K+"px":L+"px"),height:L+"px"})}else{var Q=M.attr("data-tries");if(!Q){Q=0}if(typeof Q=="undefined"){Q=0}Q=parseInt(Q);if(Q>3){M.css({width:L+"px",height:L+"px"})}else{q.push(M);M.attr("data-tries",Q+1)}}}function z(L){if(L.find(".InputfieldImageListToggle").length){return}var O=u("").append("");var Q=u("").append("");var K=u("").append("");var P="InputfieldImageListToggle--active";var N="";var M=function(V){var U=u(this);var T=U.closest(".Inputfield");var R=U.attr("href");var S;U.parent().children("."+P).removeClass(P);U.addClass(P);if(R=="list"){if(!T.hasClass("InputfieldImageEditAll")){T.find(".InputfieldImageEdit--active .InputfieldImageEdit__close").click();T.addClass("InputfieldImageEditAll")}S=D(T,"listSize");l(T,S);e(T,"mode","list")}else{if(R=="left"){T.removeClass("InputfieldImageEditAll");S=D(T,"size");j(T,S,true);e(T,"mode","left");I()}else{if(R=="grid"){T.removeClass("InputfieldImageEditAll");S=D(T,"size");j(T,S,false);e(T,"mode","grid")}}}A(T.find(".gridImages"));U.blur();return false};O.click(M);Q.click(M);K.click(M);if(L.hasClass("InputfieldImage")){L.find(".InputfieldHeader").append(O).append(Q).append(K);N=D(L,"mode")}else{u(".InputfieldImage .InputfieldHeader",L).append(O).append(Q).append(K)}if(N=="list"){O.click()}else{if(N=="left"){Q.click()}else{}}}function y(P){var M=P.children(".InputfieldHeader");if(M.children(".InputfieldImageSizeSlider").length){return}var O=P.find(".gridImages");var L=O.attr("data-gridsize");var N=L/2;var K=L*2;var Q=u('');M.append(Q);Q.slider({min:N,max:K,value:D(P,"size"),range:"min",slide:function(T,V){var U=V.value;var W=15;var X=Math.floor(L/W);var R=U-N;var S=Math.floor(W+(R/X));if(P.hasClass("InputfieldImageEditAll")){e(P,"size",U);l(P,S)}else{e(P,"listSize",S);j(P,U)}},start:function(R,S){if(P.find(".InputfieldImageEdit:visible").length){P.find(".InputfieldImageEdit__close").click()}},stop:function(R,S){I(P)}})}function e(L,O,N){var M=D(L);var P=L.attr("id");var K=P?P.replace("wrap_Inputfield_",""):"";if(!K.length||typeof N=="undefined"){return}if(M[K][O]==N){return}M[K][O]=N;u.cookie("InputfieldImage",M);c=M}function D(L,O){if(c&&typeof O=="undefined"){return c}var P=L.attr("id");var K=P?P.replace("wrap_Inputfield_",""):"na";var N=c?c:u.cookie("InputfieldImage");var M=null;if(!N){var N={}}if(typeof N[K]=="undefined"){N[K]={}}if(typeof N[K].size=="undefined"){N[K].size=parseInt(L.find(".gridImages").attr("data-size"))}if(typeof N[K].listSize=="undefined"){N[K].listSize=23}if(typeof N[K].mode=="undefined"){N[K].mode=L.find(".gridImages").attr("data-gridMode")}if(c==null){c=N}if(typeof O=="undefined"){M=N}else{if(O===true){M=N[K]}else{if(typeof N[K][O]!="undefined"){M=N[K][O]}}}return M}function a(O){if(O.hasClass("InputfieldStateCollapsed")){return}var P=parseInt(O.find(".InputfieldImageMaxFiles").val());var N=O.find(".gridImages");var M=D(O,"size");var Q=D(O,"mode");var L=Q=="left"?true:false;if(!M){M=N.attr("data-gridsize")}M=parseInt(M);j(O,M,L);if(O.hasClass("InputfieldImageEditAll")||Q=="list"){var K=D(O,"listSize");l(O,K)}if(!O.hasClass("InputfieldImageInit")){O.addClass("InputfieldImageInit");if(O.hasClass("InputfieldRenderValueMode")){return o(O)}else{if(P==1){O.addClass("InputfieldImageMax1");s(O)}else{A(N)}}z(O);y(O)}v(O)}function H(){u("body").addClass("ie-no-drop");u(".InputfieldImage.InputfieldFileMultiple").each(function(){var L=u(this),N=parseInt(L.find(".InputfieldFileMaxFiles").val()),K=L.find(".gridImages"),M=L.find(".InputfieldImageUpload");M.on("change","input[type=file]",function(){var R=u(this),P=R.parent(".InputMask");if(R.val().length>1){P.addClass("ui-state-disabled")}else{P.removeClass("ui-state-disabled")}if(R.next("input.InputfieldFile").length>0){return}var O=K.children("li").length+M.find("input[type=file]").length+1;if(N>0&&O>=N){return}M.find(".InputMask").not(":last").each(function(){var S=u(this);if(S.find("input[type=file]").val()<1){S.remove()}});var Q=P.clone().removeClass("ui-state-disabled");Q.children("input[type=file]").val("");Q.insertAfter(P)})})}function J(M){var L;if(M.length>0){L=M.find(".InputfieldImageUpload")}else{L=u(".InputfieldImageUpload")}L.each(function(P){var Q=u(this);var O=Q.closest(".InputfieldContent");if(Q.hasClass("InputfieldImageInitUpload")){return}N(O,P);Q.addClass("InputfieldImageInitUpload")});function N(X,ai){var W=X.parents("form");var O=X.closest(".InputfieldRepeaterItem");var S=O.length?O.attr("data-editUrl"):W.attr("action");S+=(S.indexOf("?")>-1?"&":"?")+"InputfieldFileAjax=1";var am=W.find("input._post_token");var V=am.attr("name");var aa=am.val();var Z=X.find(".InputfieldImageErrors").first();var R=X.find(".InputfieldImageUpload").data("fieldname");R=R.slice(0,-2);var ah=X.closest(".Inputfield.InputfieldImage");var al=X.find(".InputfieldImageUpload").data("extensions").toLowerCase();var ag=X.find(".InputfieldImageUpload").data("maxfilesize");var Y=X.find("input[type=file]").get(0);var Q=X.find(".gridImages");var aj=Q.get(0);var ac=Q.data("gridsize");var ad=null;var ab=parseInt(X.find(".InputfieldImageMaxFiles").val());ak(X);if(ab!=1){af(Q)}Q.children().addClass("InputfieldFileItemExisting");function U(ao,an){if(typeof an!=="undefined"){ao=""+an+": "+ao}return"
  • "+ao+"
  • "}function P(ao){var an=new String(ao).substring(ao.lastIndexOf("/")+1);if(an.lastIndexOf(".")!=-1){an=an.substring(0,an.lastIndexOf("."))}return an}function ak(an){if(an.hasClass("InputfieldImageDropzoneInit")){return}var ao=an.get(0);ao.addEventListener("dragleave",function(){an.removeClass("ui-state-hover")},false);ao.addEventListener("dragenter",function(){an.addClass("ui-state-hover")},false);ao.addEventListener("dragover",function(ap){if(!an.is("ui-state-hover")){an.addClass("ui-state-hover")}ap.preventDefault();ap.stopPropagation();return false},false);ao.addEventListener("drop",function(ap){ae(ap.dataTransfer.files);an.removeClass("ui-state-hover");ap.preventDefault();ap.stopPropagation();return false},false);an.addClass("InputfieldImageDropzoneInit")}function af(au){var ax=null;var aw=false;var an=null;function aq(az){var aD=az.offset();var aA=az.width();var ay=az.height();var aC=aD.left+aA/2;var aB=aD.top+ay/2;return{clientX:aC,clientY:aB}}function at(){return au.find(".InputfieldImageEdit--active").length>0}function ar(az){if(at()){return}az.preventDefault();az.stopPropagation();aw=false;if(ax==null){var ay=au.attr("data-size")+"px";var aA=u("
    ").addClass("gridImage__overflow");if(au.closest(".InputfieldImageEditAll").length){aA.css({width:"100%",height:ay})}else{aA.css({width:ay,height:ay})}ax=u("
  • ").addClass("ImageOuter gridImage gridImagePlaceholder").append(aA);au.append(ax)}var aB=aq(ax);ax.simulate("mousedown",aB)}function av(ay){if(at()){return}ay.preventDefault();ay.stopPropagation();aw=false;if(ax==null){return}var az={clientX:ay.originalEvent.clientX,clientY:ay.originalEvent.clientY};ax.simulate("mousemove",az)}function ap(ay){if(at()){return}ay.preventDefault();ay.stopPropagation();if(ax==null){return false}aw=true;if(an){clearTimeout(an)}an=setTimeout(function(){if(!aw||ax==null){return}ax.remove();ax=null},1000)}function ao(ay){if(at()){return}aw=false;var az={clientX:ay.clientX,clientY:ay.clientY};ax.simulate("mouseup",az);k=ax.next(".gridImage");ax.remove();ax=null}if(au.length&&!au.hasClass("gridImagesInitDropInPlace")){au.on("dragenter",ar);au.on("dragover",av);au.on("dragleave",ap);au.on("drop",ao);au.addClass("gridImagesInitDropInPlace")}}function T(aI){var aG=ProcessWire.config.InputfieldImage.labels;var au=parseInt(aI.size/1024,10)+" kB";var aH='
    '+aG.dimensions+''+aG.na+"
    "+aG.filesize+""+au+"
    "+aG.variations+"0
    ";var aK=u('
  • '),aD=u(aH),aw=u('
    '),an=u('
    '),aA=u("
    "),aC=u(""),aF=u(' '),aE=u('
    '),ao,ay,aJ,az=URL.createObjectURL(aI),ap=ah.find(".gridImages"),ar=ab==1,aB=D(ah,"size"),at=D(ah,"listSize"),aq=ah.hasClass("InputfieldImageEditAll"),ax=u('');aw.append(ax);aA.find(".gridImage__inner").append(aF);aA.find(".gridImage__inner").append(aE.css("display","none"));aA.find(".gridImage__inner").append(aC);an.append(u('

    '+aI.name+'

    '+au+""));if(aq){aw.css("width",at+"%");an.css("width",(100-at)+"%")}else{aw.css({width:aB+"px",height:aB+"px"})}aK.append(aD).append(aw).append(aA).append(an);ax.attr({src:az,"data-original":az});img=new Image();img.addEventListener("load",function(){aD.find(".dimensions").html(this.width+" × "+this.height);var aL=Math.min(this.width,this.height)/aB;ax.attr({width:this.width/aL,height:this.height/aL})},false);img.src=az;ay=new XMLHttpRequest();ay.upload.addEventListener("progress",function(aL){if(!aL.lengthComputable){return}u("body").addClass("pw-uploading");aC.attr("value",parseInt((aL.loaded/aL.total)*100));aE.css("display","block")},false);ay.addEventListener("load",function(){ay.getAllResponseHeaders();var aM=u.parseJSON(ay.responseText),aP=aM.length>1;if(aM.error!==undefined){aM=[aM]}for(var aR=0;aR1){ah.removeClass("InputfieldFileEmpty").removeClass("InputfieldFileSingle").addClass("InputfieldFileMultiple")}}}function ae(ar){var ao=function(aw){return parseInt(aw/1024,10)};if(typeof ar==="undefined"){aj.innerHTML="No support for the File API in this web browser";return}for(var ap=0,an=ar.length;apag&&ag>2000000){var au=ao(ar[ap].size),at=ao(ag);aq="Filesize "+au+" kb is too big. Maximum allowed is "+at+" kb";Z.append(U(aq,ar[ap].name))}else{T(ar[ap])}}if(ab==1){break}}}Y.addEventListener("change",function(an){ae(this.files);an.preventDefault();an.stopPropagation();this.value=""},false)}function K(){var O=".InputfieldImageEdit__imagewrapper img";u(document).on("dragenter",O,function(){var R=u(this);if(R.closest(".InputfieldImageMax1").length){return}var S=R.attr("src");var P=R.closest(".InputfieldImageEdit");var Q=R.closest(".InputfieldImageEdit__imagewrapper");Q.addClass("InputfieldImageEdit__replace");b.file=new String(S).substring(S.lastIndexOf("/")+1);b.item=u("#"+P.attr("data-for"));b.edit=P}).on("dragleave",O,function(){var Q=u(this);if(Q.closest(".InputfieldImageMax1").length){return}var P=Q.closest(".InputfieldImageEdit__imagewrapper");P.removeClass("InputfieldImageEdit__replace");b.file="";b.item=null;b.edit=null})}K()}function G(){u(".InputfieldImage.Inputfield").each(function(){a(u(this))});w();if(r()){J("")}else{H()}u(document).on("reloaded",".InputfieldImage",function(){var K=u(this);a(K);J(K)}).on("wiretabclick",function(M,L,K){L.find(".InputfieldImage").each(function(){a(u(this))})}).on("opened",".InputfieldImage",function(){a(u(this))})}G()}jQuery(document).ready(function(a){InputfieldImage(a)}); \ No newline at end of file +function InputfieldImage(u){var k=null;var b={file:"",item:null,edit:null};var E={type:"image",closeOnContentClick:true,closeBtnInside:true};var c=null;var q=[];function r(){var L=window.File&&window.FileList&&window.FileReader;var K=u(".InputfieldAllowAjaxUpload").length>0;var M=u("#PageIDIndicator").length>0;return(L&&(M||K))}function x(M,K,L){K||(K=250);var N,O;return function(){var R=L||this;var Q=+new Date(),P=arguments;if(N&&Q .gridImage",start:function(P,O){var N=D(L.closest(".Inputfield"),"size");O.placeholder.append(u("
    ").css({display:"block",height:N+"px",width:N+"px"}));M=window.setTimeout(function(){F(L,null)},100);L.addClass("InputfieldImageSorting")},stop:function(P,N){var O=u(this);if(M!==null){N.item.find(".InputfieldImageEdit__edit").click();clearTimeout(M)}O.children("li").each(function(R){var Q=u(this).find(".InputfieldFileSort");if(Q.val()!=R){Q.val(R).change()}});L.removeClass("InputfieldImageSorting")},cancel:".InputfieldImageEdit"};L.sortable(K)}function o(L){var K=u.extend(true,{},E);K.callbacks={elementParse:function(M){var N=u(M.el).attr("data-original");if(typeof N=="undefined"||!N){N=u(M.el).attr("src")}M.src=N}};K.gallery={enabled:true};L.find("img").magnificPopup(K)}function s(L){var K=u.extend(true,{},E);K.callbacks={elementParse:function(M){M.src=u(M.el).attr("src")}};K.gallery={enabled:false};L.find("img").magnificPopup(K)}function B(K){return K.find(".InputfieldImageEdit--active")}function t(K){return u("#"+K.find(".InputfieldImageEdit__edit").attr("data-current"))}function C(M){var K=M.is(":checked");var L=M.parents(".gridImages").find(".gridImage__deletebox");if(K){L.prop("checked","checked").change()}else{L.removeAttr("checked").change()}}function I(L){if(typeof L=="undefined"){var K=u(".gridImages")}else{var K=L.find(".gridImages")}K.each(function(){var M=u(this),N=B(M);if(N.length){i(t(N),N)}})}function v(Q){var M=[];var P=[];var O=0,K=0;var N;if(typeof Q=="undefined"){N=u(".InputfieldImage.Inputfield")}else{N=Q}N.removeClass("InputfieldImageNarrow");N.each(function(){var S=u(this);var T=S.width();if(T<1){return}if(T<=500){M[O]=S;O++}});for(var R=0;R=P){N.css("max-height","100%").css("max-width","none");N.attr("height",L).removeAttr("width")}else{if(P>K){N.css("max-height","none").css("max-width","100%");N.attr("width",L).removeAttr("height")}else{N.css("max-height","100%").css("max-width","none");N.removeAttr("width").attr("height",L)}}}var K=N.width();if(K){M.css({width:(O?K+"px":L+"px"),height:L+"px"})}else{var Q=M.attr("data-tries");if(!Q){Q=0}if(typeof Q=="undefined"){Q=0}Q=parseInt(Q);if(Q>3){M.css({width:L+"px",height:L+"px"})}else{q.push(M);M.attr("data-tries",Q+1)}}}function z(L){if(L.find(".InputfieldImageListToggle").length){return}var O=u("").append("");var Q=u("").append("");var K=u("").append("");var P="InputfieldImageListToggle--active";var N="";var M=function(V){var U=u(this);var T=U.closest(".Inputfield");var R=U.attr("href");var S;U.parent().children("."+P).removeClass(P);U.addClass(P);if(R=="list"){if(!T.hasClass("InputfieldImageEditAll")){T.find(".InputfieldImageEdit--active .InputfieldImageEdit__close").click();T.addClass("InputfieldImageEditAll")}S=D(T,"listSize");l(T,S);e(T,"mode","list")}else{if(R=="left"){T.removeClass("InputfieldImageEditAll");S=D(T,"size");j(T,S,true);e(T,"mode","left");I()}else{if(R=="grid"){T.removeClass("InputfieldImageEditAll");S=D(T,"size");j(T,S,false);e(T,"mode","grid")}}}A(T.find(".gridImages"));U.blur();return false};O.click(M);Q.click(M);K.click(M);if(L.hasClass("InputfieldImage")){L.find(".InputfieldHeader").append(O).append(Q).append(K);N=D(L,"mode")}else{u(".InputfieldImage .InputfieldHeader",L).append(O).append(Q).append(K)}if(N=="list"){O.click()}else{if(N=="left"){Q.click()}else{}}}function y(P){var M=P.children(".InputfieldHeader");if(M.children(".InputfieldImageSizeSlider").length){return}var O=P.find(".gridImages");var L=O.attr("data-gridsize");var N=L/2;var K=L*2;var Q=u('');M.append(Q);Q.slider({min:N,max:K,value:D(P,"size"),range:"min",slide:function(T,V){var U=V.value;var W=15;var X=Math.floor(L/W);var R=U-N;var S=Math.floor(W+(R/X));if(P.hasClass("InputfieldImageEditAll")){e(P,"size",U);l(P,S)}else{e(P,"listSize",S);j(P,U)}},start:function(R,S){if(P.find(".InputfieldImageEdit:visible").length){P.find(".InputfieldImageEdit__close").click()}},stop:function(R,S){I(P)}})}function e(L,O,N){var M=D(L);var P=L.attr("id");var K=P?P.replace("wrap_Inputfield_",""):"";if(!K.length||typeof N=="undefined"){return}if(M[K][O]==N){return}M[K][O]=N;u.cookie("InputfieldImage",M);c=M}function D(L,O){if(c&&typeof O=="undefined"){return c}var P=L.attr("id");var K=P?P.replace("wrap_Inputfield_",""):"na";var N=c?c:u.cookie("InputfieldImage");var M=null;if(!N){var N={}}if(typeof N[K]=="undefined"){N[K]={}}if(typeof N[K].size=="undefined"){N[K].size=parseInt(L.find(".gridImages").attr("data-size"))}if(typeof N[K].listSize=="undefined"){N[K].listSize=23}if(typeof N[K].mode=="undefined"){N[K].mode=L.find(".gridImages").attr("data-gridMode")}if(c==null){c=N}if(typeof O=="undefined"){M=N}else{if(O===true){M=N[K]}else{if(typeof N[K][O]!="undefined"){M=N[K][O]}}}return M}function a(O){if(O.hasClass("InputfieldStateCollapsed")){return}var P=parseInt(O.find(".InputfieldImageMaxFiles").val());var N=O.find(".gridImages");var M=D(O,"size");var Q=D(O,"mode");var L=Q=="left"?true:false;if(!M){M=N.attr("data-gridsize")}M=parseInt(M);j(O,M,L);if(O.hasClass("InputfieldImageEditAll")||Q=="list"){var K=D(O,"listSize");l(O,K)}if(!O.hasClass("InputfieldImageInit")){O.addClass("InputfieldImageInit");if(O.hasClass("InputfieldRenderValueMode")){return o(O)}else{if(P==1){O.addClass("InputfieldImageMax1");s(O)}else{A(N)}}z(O);y(O)}v(O)}function H(){u("body").addClass("ie-no-drop");u(".InputfieldImage.InputfieldFileMultiple").each(function(){var L=u(this),N=parseInt(L.find(".InputfieldFileMaxFiles").val()),K=L.find(".gridImages"),M=L.find(".InputfieldImageUpload");M.on("change","input[type=file]",function(){var R=u(this),P=R.parent(".InputMask");if(R.val().length>1){P.addClass("ui-state-disabled")}else{P.removeClass("ui-state-disabled")}if(R.next("input.InputfieldFile").length>0){return}var O=K.children("li").length+M.find("input[type=file]").length+1;if(N>0&&O>=N){return}M.find(".InputMask").not(":last").each(function(){var S=u(this);if(S.find("input[type=file]").val()<1){S.remove()}});var Q=P.clone().removeClass("ui-state-disabled");Q.children("input[type=file]").val("");Q.insertAfter(P)})})}function J(M){var L;if(M.length>0){L=M.find(".InputfieldImageUpload")}else{L=u(".InputfieldImageUpload")}L.each(function(P){var Q=u(this);var O=Q.closest(".InputfieldContent");if(Q.hasClass("InputfieldImageInitUpload")){return}N(O,P);Q.addClass("InputfieldImageInitUpload")});function N(X,ai){var W=X.parents("form");var O=X.closest(".InputfieldRepeaterItem");var S=O.length?O.attr("data-editUrl"):W.attr("action");S+=(S.indexOf("?")>-1?"&":"?")+"InputfieldFileAjax=1";var am=W.find("input._post_token");var V=am.attr("name");var aa=am.val();var Z=X.find(".InputfieldImageErrors").first();var R=X.find(".InputfieldImageUpload").data("fieldname");R=R.slice(0,-2);var ah=X.closest(".Inputfield.InputfieldImage");var al=X.find(".InputfieldImageUpload").data("extensions").toLowerCase();var ag=X.find(".InputfieldImageUpload").data("maxfilesize");var Y=X.find("input[type=file]").get(0);var Q=X.find(".gridImages");var aj=Q.get(0);var ac=Q.data("gridsize");var ad=null;var ab=parseInt(X.find(".InputfieldImageMaxFiles").val());ak(X);if(ab!=1){af(Q)}Q.children().addClass("InputfieldFileItemExisting");function U(ao,an){if(typeof an!=="undefined"){ao=""+an+": "+ao}return"
  • "+ao+"
  • "}function P(ao){var an=new String(ao).substring(ao.lastIndexOf("/")+1);if(an.lastIndexOf(".")!=-1){an=an.substring(0,an.lastIndexOf("."))}return an}function ak(ao){if(ao.hasClass("InputfieldImageDropzoneInit")){return}var ar=ao.get(0);var aq=ao.closest(".Inputfield");function an(){if(aq.hasClass("pw-drag-in-file")){return}ao.addClass("ui-state-hover");aq.addClass("pw-drag-in-file InputfieldStateConfirmLeave")}function ap(){if(!aq.hasClass("pw-drag-in-file")){return}ao.removeClass("ui-state-hover");aq.removeClass("pw-drag-in-file")}ar.addEventListener("dragleave",function(){ap()},false);ar.addEventListener("dragenter",function(){an()},false);ar.addEventListener("dragover",function(at){if(!ao.is("ui-state-hover")){an()}at.preventDefault();at.stopPropagation();return false},false);ar.addEventListener("drop",function(at){ae(at.dataTransfer.files);ap();at.preventDefault();at.stopPropagation();return false},false);ao.addClass("InputfieldImageDropzoneInit")}function af(aw){var aA=null;var ay=false;var ao=null;var an=aw.closest(".Inputfield");function at(){an.addClass("pw-drag-in-file")}function az(){an.removeClass("pw-drag-in-file")}function ar(aC){var aG=aC.offset();var aD=aC.width();var aB=aC.height();var aF=aG.left+aD/2;var aE=aG.top+aB/2;return{clientX:aF,clientY:aE}}function av(){return aw.find(".InputfieldImageEdit--active").length>0}function au(aC){if(av()){return}aC.preventDefault();aC.stopPropagation();at();ay=false;if(aA==null){var aB=aw.attr("data-size")+"px";var aD=u("
    ").addClass("gridImage__overflow");if(aw.closest(".InputfieldImageEditAll").length){aD.css({width:"100%",height:aB})}else{aD.css({width:aB,height:aB})}aA=u("
  • ").addClass("ImageOuter gridImage gridImagePlaceholder").append(aD);aw.append(aA)}var aE=ar(aA);aA.simulate("mousedown",aE)}function ax(aB){if(av()){return}aB.preventDefault();aB.stopPropagation();at();ay=false;if(aA==null){return}var aC={clientX:aB.originalEvent.clientX,clientY:aB.originalEvent.clientY};aA.simulate("mousemove",aC)}function aq(aB){if(av()){return}aB.preventDefault();aB.stopPropagation();if(aA==null){return false}ay=true;if(ao){clearTimeout(ao)}ao=setTimeout(function(){if(!ay||aA==null){return}aA.remove();aA=null;az()},1000)}function ap(aB){if(av()){return}az();ay=false;var aC={clientX:aB.clientX,clientY:aB.clientY};aA.simulate("mouseup",aC);k=aA.next(".gridImage");aA.remove();aA=null}if(aw.length&&!aw.hasClass("gridImagesInitDropInPlace")){aw.on("dragenter",au);aw.on("dragover",ax);aw.on("dragleave",aq);aw.on("drop",ap);aw.addClass("gridImagesInitDropInPlace")}}function T(aI){var aG=ProcessWire.config.InputfieldImage.labels;var au=parseInt(aI.size/1024,10)+" kB";var aH='
    '+aG.dimensions+''+aG.na+"
    "+aG.filesize+""+au+"
    "+aG.variations+"0
    ";var aK=u('
  • '),aD=u(aH),aw=u('
    '),an=u('
    '),aA=u("
    "),aC=u(""),aF=u(' '),aE=u('
    '),ao,ay,aJ,az=URL.createObjectURL(aI),ap=ah.find(".gridImages"),ar=ab==1,aB=D(ah,"size"),at=D(ah,"listSize"),aq=ah.hasClass("InputfieldImageEditAll"),ax=u('');aw.append(ax);aA.find(".gridImage__inner").append(aF);aA.find(".gridImage__inner").append(aE.css("display","none"));aA.find(".gridImage__inner").append(aC);an.append(u('

    '+aI.name+'

    '+au+""));if(aq){aw.css("width",at+"%");an.css("width",(100-at)+"%")}else{aw.css({width:aB+"px",height:aB+"px"})}aK.append(aD).append(aw).append(aA).append(an);ax.attr({src:az,"data-original":az});img=new Image();img.addEventListener("load",function(){aD.find(".dimensions").html(this.width+" × "+this.height);var aL=Math.min(this.width,this.height)/aB;ax.attr({width:this.width/aL,height:this.height/aL})},false);img.src=az;ay=new XMLHttpRequest();ay.upload.addEventListener("progress",function(aL){if(!aL.lengthComputable){return}u("body").addClass("pw-uploading");aC.attr("value",parseInt((aL.loaded/aL.total)*100));aE.css("display","block")},false);ay.addEventListener("load",function(){ay.getAllResponseHeaders();var aM=u.parseJSON(ay.responseText),aP=aM.length>1;if(aM.error!==undefined){aM=[aM]}for(var aR=0;aR1){ah.removeClass("InputfieldFileEmpty").removeClass("InputfieldFileSingle").addClass("InputfieldFileMultiple")}}}function ae(ar){var ao=function(aw){return parseInt(aw/1024,10)};if(typeof ar==="undefined"){aj.innerHTML="No support for the File API in this web browser";return}for(var ap=0,an=ar.length;apag&&ag>2000000){var au=ao(ar[ap].size),at=ao(ag);aq="Filesize "+au+" kb is too big. Maximum allowed is "+at+" kb";Z.append(U(aq,ar[ap].name))}else{T(ar[ap])}}if(ab==1){break}}}Y.addEventListener("change",function(an){ae(this.files);an.preventDefault();an.stopPropagation();this.value=""},false)}function K(){var O=".InputfieldImageEdit__imagewrapper img";u(document).on("dragenter",O,function(){var R=u(this);if(R.closest(".InputfieldImageMax1").length){return}var S=R.attr("src");var P=R.closest(".InputfieldImageEdit");var Q=R.closest(".InputfieldImageEdit__imagewrapper");Q.addClass("InputfieldImageEdit__replace");b.file=new String(S).substring(S.lastIndexOf("/")+1);b.item=u("#"+P.attr("data-for"));b.edit=P}).on("dragleave",O,function(){var Q=u(this);if(Q.closest(".InputfieldImageMax1").length){return}var P=Q.closest(".InputfieldImageEdit__imagewrapper");P.removeClass("InputfieldImageEdit__replace");b.file="";b.item=null;b.edit=null})}K()}function G(){u(".InputfieldImage.Inputfield").each(function(){a(u(this))});w();if(r()){J("")}else{H()}u(document).on("reloaded",".InputfieldImage",function(){var K=u(this);a(K);J(K)}).on("wiretabclick",function(M,L,K){L.find(".InputfieldImage").each(function(){a(u(this))})}).on("opened",".InputfieldImage",function(){a(u(this))})}G()}jQuery(document).ready(function(a){InputfieldImage(a)}); \ No newline at end of file diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module index 1eb3ca10..159643bc 100755 --- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module +++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module @@ -79,6 +79,8 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu * */ protected $modalClass = 'pw-modal-large'; + + protected $themeSettings = array(); public function init() { parent::init(); @@ -90,7 +92,6 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $this->set('minWidth', ''); $this->set('minHeight', ''); $this->set('dimensionsByAspectRatio', 0); - $this->set('itemClass', 'gridImage ui-widget'); $options = $this->wire('config')->adminThumbOptions; @@ -125,6 +126,14 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu 'na' => $this->_('N/A'), // for JS 'changes' => $this->_('This images field may have unsaved changes that could be lost after this action. Please save before cropping, or double-click the button proceed anyway.'), )); + + $themeDefaults = array( + 'error' => "{out}", + 'buttonClass' => "ui-button ui-corner-all ui-state-default", + 'buttonText' => "{out}", + ); + $themeSettings = $this->wire('config')->InputfieldImage; + $this->themeSettings = is_array($themeSettings) ? array_merge($themeDefaults, $themeSettings) : $themeDefaults; } @@ -299,7 +308,7 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $out .= " -  $dropLabel +  $dropLabel "; } @@ -435,8 +444,10 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $attr = array(); $is2x = false; - $thumbHeight = $thumb->height; - $thumbWidth = $thumb->width; + $_thumbHeight = $thumb->height; + $thumbHeight = $_thumbHeight; + $_thumbWidth = $thumb->width; + $thumbWidth = $_thumbWidth; $useResize = ($img->ext == 'svg' && $thumbHeight == '100%') || ($this->gridSize && $thumbHeight > $this->gridSize) || ($this->gridSize && $thumbWidth > $this->gridSize); @@ -511,8 +522,8 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $attr['src'] = $thumb->URL; $attr['alt'] = $this->wire('sanitizer')->entities1($img->description); - //$attr['data-w'] = $is2x ? floor($thumb->width() / 2) : $thumb->width(); - //$attr['data-h'] = $is2x ? floor($thumb->height() / 2) : $thumb->height(); + $attr['data-w'] = $_thumbWidth; + $attr['data-h'] = $_thumbHeight; $attr["data-original"] = $img->URL; $markup = " $value) $markup .= "$key=\"$value\" "; @@ -570,7 +581,10 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $buttons = $pagefile->ext() == 'svg' ? '' : $this->renderButtons($pagefile, $id, $n); $description = $this->renderItemDescriptionField($pagefile, $id, $n); $additional = $this->renderAdditionalFields($pagefile, $id, $n); - $error = $thumb['error'] ? "" . $sanitizer->entities($thumb['error']) . "" : ""; + $error = ''; + if($thumb['error']) { + $error = str_replace('{out}', $sanitizer->entities($thumb['error']), $this->themeSettings['error']); + } $labels = $this->labels; $out .= "
    @@ -692,26 +706,15 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu $variationCount = count($variations); $editUrl = $this->getEditUrl($pagefile, $pageID); $variationUrl = $this->getVariationUrl($pagefile, $id); - $buttonClass = "ui-button ui-corner-all ui-state-default $this->modalClass pw-modal"; + $buttonClass = $this->themeSettings['buttonClass'] . " $this->modalClass pw-modal"; $modalAttrs = "data-buttons='#non_rte_dialog_buttons button' data-autoclose='1' data-close='#non_rte_cancel'"; $labels = $this->labels; - if($n) {} - - $out = " - - - "; + $buttonText = str_replace('{out}', " $labels[crop]", $this->themeSettings['buttonText']); + $out = ""; + $buttonText = " $labels[variations] ($variationCount)"; + $buttonText = str_replace('{out}', $buttonText, $this->themeSettings['buttonText']); + $out .= ""; return $out; } diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.scss b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.scss index 8d12e8a4..63dabeee 100755 --- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.scss +++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.scss @@ -58,7 +58,10 @@ $itemPadding: 0.4em; // The
      element containing li.gridImage items and .InputfieldImageEdit .gridImages { + list-style: none; + padding-left: 0; position: relative; + margin: 0; margin-right: -.6em; display: block; list-style: none; diff --git a/wire/modules/Inputfield/InputfieldMarkup.module b/wire/modules/Inputfield/InputfieldMarkup.module index e8f61846..44e30aba 100644 --- a/wire/modules/Inputfield/InputfieldMarkup.module +++ b/wire/modules/Inputfield/InputfieldMarkup.module @@ -29,6 +29,15 @@ class InputfieldMarkup extends InputfieldWrapper { $this->skipLabel = Inputfield::skipLabelBlank; parent::init(); } + + public function renderReady(Inputfield $parent = null, $renderValueMode = false) { + $label = $this->getSetting('label'); + + if(!strlen($label) && $this->skipLabel == Inputfield::skipLabelBlank) { + $this->addClass('InputfieldHeaderHidden'); + } + return parent::renderReady($parent, $renderValueMode); + } public function ___render() { diff --git a/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.module b/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.module index a386bf8f..5fc9d994 100644 --- a/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.module +++ b/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.module @@ -153,6 +153,8 @@ class InputfieldPageName extends InputfieldName implements ConfigurableModule { $this->set('sanitizeMethod', 'pageName'); } $this->hasLanguagePageNames = $this->wire('modules')->isInstalled('LanguageSupportPageNames'); + + $this->removeClass('InputfieldNoBorder', 'wrapClass'); } public function ___render() { diff --git a/wire/modules/Inputfield/InputfieldPassword/InputfieldPassword.module b/wire/modules/Inputfield/InputfieldPassword/InputfieldPassword.module index 439d1ec9..61381f84 100644 --- a/wire/modules/Inputfield/InputfieldPassword/InputfieldPassword.module +++ b/wire/modules/Inputfield/InputfieldPassword/InputfieldPassword.module @@ -172,6 +172,8 @@ class InputfieldPassword extends InputfieldText { $this->attr('data-banMode', $this->complexifyBanMode ? $this->complexifyBanMode : 'loose'); $this->attr('data-factor', $this->complexifyFactor ? $this->complexifyFactor : '0.7'); + + $inputClass = $this->wire('sanitizer')->entities($this->attr('class')); $this->addClass('InputfieldPasswordComplexify'); $failIcon = ""; @@ -193,7 +195,7 @@ class InputfieldPassword extends InputfieldText { "" . "

      " . "

      " . - " " . + " " . "" . "" . $this->_('Confirm') . "" . "$goodIcon" . $this->_('Matches') . "" . diff --git a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.css b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.css index beaed0d1..200e889a 100644 --- a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.css +++ b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.css @@ -1,6 +1,14 @@ .InputfieldSelector .selector-list { + margin-left: 0; + padding-left: 0; + list-style: none; margin-bottom: 0.5em; } +.InputfieldSelector .selector-list li { + margin-left: 0; + padding-left: 0; + list-style: none; +} .InputfieldSelector .selector-row { margin: 0; diff --git a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.js b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.js index 8f899339..3606e986 100644 --- a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.js +++ b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.js @@ -71,9 +71,11 @@ var InputfieldSelector = { InputfieldSelector.normalizeHeightRows($inputfield); }); + /* $(".InputfieldSelector .InputfieldContent").eq(0).each(function() { InputfieldSelector.borderColor = $(this).css('border-bottom-color'); }); + */ // trigger change any event for first item, in case we have one already populated //var $rows = $(".InputfieldSelector .selector-row:not(.selector-template-row)"); diff --git a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.min.js b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.min.js index 42b30f87..4aaf4bda 100644 --- a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.min.js +++ b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.min.js @@ -1 +1 @@ -var InputfieldSelector={selector:"",spinner:"",borderColor:"#eee",init:function(){$(document).on("change",".InputfieldSelector select.select-field",InputfieldSelector.changeField);$(document).on("change",".InputfieldSelector select.select-subfield",InputfieldSelector.changeField);$(document).on("change",".InputfieldSelector :input:not(.select-field):not(.input-value-autocomplete)",function(){InputfieldSelector.changeAny($(this))});$(document).on("opened",".InputfieldSelector",function(){InputfieldSelector.normalizeHeightRows($(this))});var b=null;$(document).on("keyup",".InputfieldSelector input.input-value",function(){var d=$(this);clearTimeout(b);if(d.hasClass("input-value-subselect")&&InputfieldSelector.valueHasOperator(d.val())){var c=d.parents(".selector-list").siblings(".selector-preview");c.html('Subselect detected: when done click here to commit your change.');return}b=setTimeout(function(){InputfieldSelector.changeAny(d)},100)});$(document).on("click",".InputfieldSelector .selector-add",function(){InputfieldSelector.addRow($(this));return false});$(document).on("click",".InputfieldSelector a.delete-row",InputfieldSelector.deleteRow);$(".InputfieldSelector .selector-preview").hide();$(document).on("wiretabclick",function(f,d,c){var e=d.find(".InputfieldSelector");if(e.length==0){return}InputfieldSelector.normalizeHeightRows(e)});$(".InputfieldSelector .InputfieldContent").eq(0).each(function(){InputfieldSelector.borderColor=$(this).css("border-bottom-color")});var a=$(".InputfieldSelector .selector-row");if(a.length>0){a.eq(0).find(".select-field").each(function(){InputfieldSelector.changeAny($(this))});a.eq(1).find(".input-value").change();a.each(function(){var c=$(this);c.css("border-color",InputfieldSelector.borderColor);InputfieldSelector.normalizeHeightRow(c);var f=c.find(".input-value-autocomplete");if(f.length>0){var d=c.find(".select-subfield");var g=d.length?d.val():c.find(".select-field").val();var e=c.parents(".InputfieldSelector").find("input.selector-value").attr("name");InputfieldSelector.setupAutocomplete(f,g,e)}})}$(".InputfieldSelector").each(function(){if($(this).find(".selector-preview-disabled").length>0){return}$(this).find(".input-value:eq(0)").change()})},disableOption:function(a){a.attr("disabled","disabled")},enableOption:function(a){a.removeAttr("disabled")},valueHasOperator:function(b){var a=["=","<",">"];var d=false;for(n=0;n-1&&b.substring(c-1,1)!="\\"){d=true;break}}return d},addRow:function(b){var c=b.parents(".InputfieldSelector").find(".selector-list");var a=c.find(".selector-template-row");var d=a.clone();d.removeClass("selector-template-row");d.find(".opval").html("");d.find(".select-field").val("");d.hide();d.find("option[disabled=disabled]").remove();c.append(d);d.slideDown("fast");InputfieldSelector.normalizeHeightRow(d)},deleteRow:function(){var b=$(this).parents(".selector-row");var a=b.find(".select-field");if(a.val()=="template"){b.parents(".InputfieldSelector").find("select.select-field").each(function(){$(this).find("option[disabled=disabled]").each(function(){InputfieldSelector.enableOption($(this))})})}var c=b.siblings();b.slideUp("fast",function(){b.remove();InputfieldSelector.changeAny(c.eq(0))});return false},changeFieldToggle:function(b){var d=b.parents(".InputfieldSelector");var c=d.hasClass("InputfieldSelector_names")?"names":"labels";var a=(c==="labels"?"names":"labels");d.find(".select-field, .select-subfield").each(function(){$(this).find("option").each(function(){var e=$(this).attr("data-name");if(!e){if($(this).attr("value")=="toggle-names-labels"){$(this).html($(this).attr("data-"+c))}return}if(c=="labels"){$(this).html(e)}else{$(this).html($(this).attr("data-label"))}})});d.removeClass("InputfieldSelector_"+c).addClass("InputfieldSelector_"+a);b.val(b.attr("data-selected"));return false},changeField:function(f){var f=$(this);var i=f.val();if(!i||i.length==0){return}if(i=="toggle-names-labels"){return InputfieldSelector.changeFieldToggle(f)}var g=f.parents(".selector-row");var e="opval";g.children(".opval").html("");f.attr("data-selected",i);var c=f.parents(".InputfieldSelector").find(".selector-value");var a=c.attr("name");var h=f.attr("data-type");if(i.match(/\.$/)){e="subfield";if(i.indexOf("@")>-1){i=i.substring(1,i.length-1)}else{i=i.substring(0,i.length-1)}g.addClass("has-subfield")}else{if(i.match(/\.id$/)){i="id";e="opval";h="selector"}else{if(f.is(".select-field")){g.children(".subfield").html("");g.removeClass("has-subfield")}}}var b="./?InputfieldSelector="+e+"&field="+i+"&type="+h+"&name="+a;var d=$(InputfieldSelector.spinner);g.append(d);$.get(b,function(m){d.remove();var j=$(m);j.hide();if(e=="opval"){var l=g.children(".opval");l.html("").append(j);l.children(":not(.input-or)").fadeIn("fast");InputfieldSelector.changeAny(f);var k=l.find(".input-value-autocomplete");if(k.length>0){InputfieldSelector.setupAutocomplete(k,i,a)}}else{var o=g.children(".subfield");o.html("").append(j);j.fadeIn("fast")}InputfieldSelector.normalizeHeightRow(g);g.closest(".InputfieldContent").find(".hasDatepicker").datepicker("destroy").removeAttr("id").removeClass("hasDatepicker")})},normalizeHeightRow:function(a){InputfieldSelector.normalizeHeight(a.find(":input, i.fa"))},normalizeHeightRows:function(a){a.find(".selector-row").each(function(){InputfieldSelector.normalizeHeightRow($(this))})},normalizeHeight:function(b){var a=0;b.each(function(){$(this).css("margin-top",0);var c=$(this).outerHeight();if(c>a){a=c}});b.each(function(){var d=$(this).outerHeight();if(d0){f.push(C)}}if(E.is(".has-subfield")){var H=E.find(".select-subfield").val();if(H.length>0){if(H.indexOf(".")>0){if(K.indexOf("@")>-1){K="@"+H}else{K=H}}else{K+=H}if(K.indexOf(".data")>0){K=K.replace(/\.data$/,"")}}}var y=z.siblings(".opval").children(".select-operator");var B=y.val();var G=y.next(".input-value");var J=G.val();if(B&&B.indexOf('"')>-1){J=" ";G.attr("disabled","disabled")}else{if(G.is(":disabled")){G.removeAttr("disabled")}}if(typeof J!="undefined"){if(J.length){if(G.hasClass("input-value-subselect")&&InputfieldSelector.valueHasOperator(J)){J="["+J+"]"}else{if(J.indexOf(",")>-1&&K!="_custom"){if(J.indexOf('"')>-1){if(J.indexOf("'")==-1){J="'"+J+"'"}else{J='"'+J.replace(/"/g,"")+'"'}}else{J='"'+J+'"'}}}}}var D=","+K+"~"+B+"~";var F="~"+B+"~"+J+",";var A=J&&J.length>0&&q.indexOf(D)>-1;var x=J&&J.length>0&&q.indexOf(F)>-1;var I=E.find(".input-or");var s=A&&I.is(":checked");var i=x&&I.is(":checked");var w=(i||s)&&K=="_custom";if(s){E.addClass("has-or-value");E.find(".select-field, .select-operator, .select-subfield").attr("disabled","disabled")}else{if(E.is(".has-or-value")){E.removeClass("has-or-value");E.find(".select-field, .select-operator, .select-subfield").removeAttr("disabled")}}if(i){E.addClass("has-or-field");E.find(".input-value, .select-operator").attr("disabled","disabled")}else{if(E.is(".has-or-field")){E.removeClass("has-or-field");E.find(".input-value, .select-operator").removeAttr("disabled")}}c[k++]={field:K,operator:B,value:J,mayOrValue:A,mayOrField:x,useOrValue:s,useOrField:i,isOrGroup:w,checkbox:I};if(x||A){h=true}q+=","+K+"~"+B+"~"+J+",";m+=","+K+B+J});if(f.length>0){var d=null;t.each(function(){var i=$(this);var s=0;i.find("option").each(function(){var x=$(this);var w=x.attr("data-templates");if(typeof w!="undefined"&&w!="*"){InputfieldSelector.enableOption(x);var y=0;for(p=0;p-1){y++}}if(y){InputfieldSelector.enableOption(x)}else{if(!x.is(":selected")){InputfieldSelector.disableOption(x)}s++}}});if(s>0&&!i.parent().is(".selector-template-row")){i.find("option[disabled=disabled]").remove()}})}m="";for(k=0;k0){m+=", "}for(var p=0;p0&&m!=InputfieldSelector.selector){if(!j.is(".selector-preview-disabled")){j.html(""+e+m+"");j.fadeIn()}var u=j.siblings(".selector-counter");if(u.length>0&&!u.is(".selector-counter-disabled")){u.html(InputfieldSelector.spinner).fadeIn("fast");$.post("./?InputfieldSelector=test&name="+o.attr("name"),{selector:m},function(i){u.hide();u.html(i);u.show()})}}if(o.val()!=m){o.val(m);if(m.length==0){j.hide();j.siblings(".selector-counter").html("")}o.change()}InputfieldSelector.selector=m;var a=l.find(".or-notes");if(h){a.fadeIn()}else{a.hide()}}};$(document).ready(function(){InputfieldSelector.init()}); \ No newline at end of file +var InputfieldSelector={selector:"",spinner:"",borderColor:"#eee",init:function(){$(document).on("change",".InputfieldSelector select.select-field",InputfieldSelector.changeField);$(document).on("change",".InputfieldSelector select.select-subfield",InputfieldSelector.changeField);$(document).on("change",".InputfieldSelector :input:not(.select-field):not(.input-value-autocomplete)",function(){InputfieldSelector.changeAny($(this))});$(document).on("opened",".InputfieldSelector",function(){InputfieldSelector.normalizeHeightRows($(this))});var b=null;$(document).on("keyup",".InputfieldSelector input.input-value",function(){var d=$(this);clearTimeout(b);if(d.hasClass("input-value-subselect")&&InputfieldSelector.valueHasOperator(d.val())){var c=d.parents(".selector-list").siblings(".selector-preview");c.html('Subselect detected: when done click here to commit your change.');return}b=setTimeout(function(){InputfieldSelector.changeAny(d)},100)});$(document).on("click",".InputfieldSelector .selector-add",function(){InputfieldSelector.addRow($(this));return false});$(document).on("click",".InputfieldSelector a.delete-row",InputfieldSelector.deleteRow);$(".InputfieldSelector .selector-preview").hide();$(document).on("wiretabclick",function(f,d,c){var e=d.find(".InputfieldSelector");if(e.length==0){return}InputfieldSelector.normalizeHeightRows(e)});var a=$(".InputfieldSelector .selector-row");if(a.length>0){a.eq(0).find(".select-field").each(function(){InputfieldSelector.changeAny($(this))});a.eq(1).find(".input-value").change();a.each(function(){var c=$(this);c.css("border-color",InputfieldSelector.borderColor);InputfieldSelector.normalizeHeightRow(c);var f=c.find(".input-value-autocomplete");if(f.length>0){var d=c.find(".select-subfield");var g=d.length?d.val():c.find(".select-field").val();var e=c.parents(".InputfieldSelector").find("input.selector-value").attr("name");InputfieldSelector.setupAutocomplete(f,g,e)}})}$(".InputfieldSelector").each(function(){if($(this).find(".selector-preview-disabled").length>0){return}$(this).find(".input-value:eq(0)").change()})},disableOption:function(a){a.attr("disabled","disabled")},enableOption:function(a){a.removeAttr("disabled")},valueHasOperator:function(b){var a=["=","<",">"];var d=false;for(n=0;n-1&&b.substring(c-1,1)!="\\"){d=true;break}}return d},addRow:function(b){var c=b.parents(".InputfieldSelector").find(".selector-list");var a=c.find(".selector-template-row");var d=a.clone();d.removeClass("selector-template-row");d.find(".opval").html("");d.find(".select-field").val("");d.hide();d.find("option[disabled=disabled]").remove();c.append(d);d.slideDown("fast");InputfieldSelector.normalizeHeightRow(d)},deleteRow:function(){var b=$(this).parents(".selector-row");var a=b.find(".select-field");if(a.val()=="template"){b.parents(".InputfieldSelector").find("select.select-field").each(function(){$(this).find("option[disabled=disabled]").each(function(){InputfieldSelector.enableOption($(this))})})}var c=b.siblings();b.slideUp("fast",function(){b.remove();InputfieldSelector.changeAny(c.eq(0))});return false},changeFieldToggle:function(b){var d=b.parents(".InputfieldSelector");var c=d.hasClass("InputfieldSelector_names")?"names":"labels";var a=(c==="labels"?"names":"labels");d.find(".select-field, .select-subfield").each(function(){$(this).find("option").each(function(){var e=$(this).attr("data-name");if(!e){if($(this).attr("value")=="toggle-names-labels"){$(this).html($(this).attr("data-"+c))}return}if(c=="labels"){$(this).html(e)}else{$(this).html($(this).attr("data-label"))}})});d.removeClass("InputfieldSelector_"+c).addClass("InputfieldSelector_"+a);b.val(b.attr("data-selected"));return false},changeField:function(f){var f=$(this);var i=f.val();if(!i||i.length==0){return}if(i=="toggle-names-labels"){return InputfieldSelector.changeFieldToggle(f)}var g=f.parents(".selector-row");var e="opval";g.children(".opval").html("");f.attr("data-selected",i);var c=f.parents(".InputfieldSelector").find(".selector-value");var a=c.attr("name");var h=f.attr("data-type");if(i.match(/\.$/)){e="subfield";if(i.indexOf("@")>-1){i=i.substring(1,i.length-1)}else{i=i.substring(0,i.length-1)}g.addClass("has-subfield")}else{if(i.match(/\.id$/)){i="id";e="opval";h="selector"}else{if(f.is(".select-field")){g.children(".subfield").html("");g.removeClass("has-subfield")}}}var b="./?InputfieldSelector="+e+"&field="+i+"&type="+h+"&name="+a;var d=$(InputfieldSelector.spinner);g.append(d);$.get(b,function(m){d.remove();var j=$(m);j.hide();if(e=="opval"){var l=g.children(".opval");l.html("").append(j);l.children(":not(.input-or)").fadeIn("fast");InputfieldSelector.changeAny(f);var k=l.find(".input-value-autocomplete");if(k.length>0){InputfieldSelector.setupAutocomplete(k,i,a)}}else{var o=g.children(".subfield");o.html("").append(j);j.fadeIn("fast")}InputfieldSelector.normalizeHeightRow(g);g.closest(".InputfieldContent").find(".hasDatepicker").datepicker("destroy").removeAttr("id").removeClass("hasDatepicker")})},normalizeHeightRow:function(a){InputfieldSelector.normalizeHeight(a.find(":input, i.fa"))},normalizeHeightRows:function(a){a.find(".selector-row").each(function(){InputfieldSelector.normalizeHeightRow($(this))})},normalizeHeight:function(b){var a=0;b.each(function(){$(this).css("margin-top",0);var c=$(this).outerHeight();if(c>a){a=c}});b.each(function(){var d=$(this).outerHeight();if(d0){f.push(C)}}if(E.is(".has-subfield")){var H=E.find(".select-subfield").val();if(H.length>0){if(H.indexOf(".")>0){if(K.indexOf("@")>-1){K="@"+H}else{K=H}}else{K+=H}if(K.indexOf(".data")>0){K=K.replace(/\.data$/,"")}}}var y=z.siblings(".opval").children(".select-operator");var B=y.val();var G=y.next(".input-value");var J=G.val();if(B&&B.indexOf('"')>-1){J=" ";G.attr("disabled","disabled")}else{if(G.is(":disabled")){G.removeAttr("disabled")}}if(typeof J!="undefined"){if(J.length){if(G.hasClass("input-value-subselect")&&InputfieldSelector.valueHasOperator(J)){J="["+J+"]"}else{if(J.indexOf(",")>-1&&K!="_custom"){if(J.indexOf('"')>-1){if(J.indexOf("'")==-1){J="'"+J+"'"}else{J='"'+J.replace(/"/g,"")+'"'}}else{J='"'+J+'"'}}}}}var D=","+K+"~"+B+"~";var F="~"+B+"~"+J+",";var A=J&&J.length>0&&q.indexOf(D)>-1;var x=J&&J.length>0&&q.indexOf(F)>-1;var I=E.find(".input-or");var s=A&&I.is(":checked");var i=x&&I.is(":checked");var w=(i||s)&&K=="_custom";if(s){E.addClass("has-or-value");E.find(".select-field, .select-operator, .select-subfield").attr("disabled","disabled")}else{if(E.is(".has-or-value")){E.removeClass("has-or-value");E.find(".select-field, .select-operator, .select-subfield").removeAttr("disabled")}}if(i){E.addClass("has-or-field");E.find(".input-value, .select-operator").attr("disabled","disabled")}else{if(E.is(".has-or-field")){E.removeClass("has-or-field");E.find(".input-value, .select-operator").removeAttr("disabled")}}c[k++]={field:K,operator:B,value:J,mayOrValue:A,mayOrField:x,useOrValue:s,useOrField:i,isOrGroup:w,checkbox:I};if(x||A){h=true}q+=","+K+"~"+B+"~"+J+",";m+=","+K+B+J});if(f.length>0){var d=null;t.each(function(){var i=$(this);var s=0;i.find("option").each(function(){var x=$(this);var w=x.attr("data-templates");if(typeof w!="undefined"&&w!="*"){InputfieldSelector.enableOption(x);var y=0;for(p=0;p-1){y++}}if(y){InputfieldSelector.enableOption(x)}else{if(!x.is(":selected")){InputfieldSelector.disableOption(x)}s++}}});if(s>0&&!i.parent().is(".selector-template-row")){i.find("option[disabled=disabled]").remove()}})}m="";for(k=0;k0){m+=", "}for(var p=0;p0&&m!=InputfieldSelector.selector){if(!j.is(".selector-preview-disabled")){j.html(""+e+m+"");j.fadeIn()}var u=j.siblings(".selector-counter");if(u.length>0&&!u.is(".selector-counter-disabled")){u.html(InputfieldSelector.spinner).fadeIn("fast");$.post("./?InputfieldSelector=test&name="+o.attr("name"),{selector:m},function(i){u.hide();u.html(i);u.show()})}}if(o.val()!=m){o.val(m);if(m.length==0){j.hide();j.siblings(".selector-counter").html("")}o.change()}InputfieldSelector.selector=m;var a=l.find(".or-notes");if(h){a.fadeIn()}else{a.hide()}}};$(document).ready(function(){InputfieldSelector.init()}); \ No newline at end of file diff --git a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.module b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.module index 51060fa3..0306317c 100644 --- a/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.module +++ b/wire/modules/Inputfield/InputfieldSelector/InputfieldSelector.module @@ -1816,15 +1816,19 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {

        $rows
      +
      "; + + if($this->allowAddRemove) $out .= " - $this->addLabel + $this->addLabel "; $out .= " - -

      $attr[value]

      - -

      $notes

      + +

      $attr[value]

      + +

      $notes

      +
      "; diff --git a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js index 53521fa3..da232041 100644 --- a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js +++ b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js @@ -15,14 +15,22 @@ items: null, skipRememberTabIDs: [], itemsParent: null, + ulClass: 'WireTabs nav', + ulAttrs: '', + liActiveClass: '', + aActiveClass: 'on', id: '' // id for tabList. if already exists, existing tabList will be used }; - - if(ProcessWire.config.JqueryWireTabs.rememberTabs != "undefined") { - options.rememberTabs = ProcessWire.config.JqueryWireTabs.rememberTabs; - } - var totalTabs = 0; + var totalTabs = 0; + var cfg = ProcessWire.config.JqueryWireTabs; + var keys = [ 'rememberTabs', 'cookieName', 'liActiveClass', 'aActiveClass', 'ulClass', 'ulAttrs' ]; + + for(var n = 0; n < keys.length; n++) { + var key = keys[n]; + if(cfg[key] != "undefined") options[key] = cfg[key]; + } + $.extend(options, customOptions); return this.each(function(index) { @@ -43,7 +51,8 @@ else $tabList = null; } if(!$tabList) { - $tabList = $("
        ").addClass("WireTabs nav"); + $tabList = $('
      '); + $tabList.addClass(options.ulClass); if(options.id.length) $tabList.attr('id', options.id); } @@ -128,21 +137,40 @@ } function tabClick() { - var $oldTab = $($tabList.find("a.on").removeClass("on").attr('href')).hide(); - var $newTab = $($(this).addClass('on').attr('href')).show(); + + var aActiveClass = options.aActiveClass; + var liActiveClass = options.liActiveClass; + + var $oldTab = $tabList.find("a." + aActiveClass); + var $newTab = $(this); + + var $oldTabContent = $($oldTab.attr('href')); + var $newTabContent = $($newTab.attr('href')); + var newTabID = $newTab.attr('id'); - var oldTabID = $oldTab.attr('id'); + var oldTabID = $oldTab.attr('id'); + $oldTab.removeClass(aActiveClass); + $newTab.addClass(aActiveClass); + + if(liActiveClass.length) { + $oldTab.closest('li').removeClass(liActiveClass); + $newTab.closest('li').addClass(liActiveClass); + } + + $oldTabContent.hide(); + $newTabContent.show(); + // add a target classname equal to the ID of the selected tab // so there is opportunity for 3rd party CSS adjustments outside this plugin - if(oldTabID) $target.removeClass($oldTab.attr('id')); + if(oldTabID) $target.removeClass($oldTabContent.attr('id')); $target.addClass(newTabID); if(options.rememberTabs > -1) { if(jQuery.inArray(newTabID, options.skipRememberTabIDs) != -1) newTabID = ''; if(options.rememberTabs == 1) setTabCookie(newTabID); lastTabID = newTabID; } - $(document).trigger('wiretabclick', [ $newTab, $oldTab ]); + $(document).trigger('wiretabclick', [ $newTabContent, $oldTabContent ]); return false; } diff --git a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.min.js b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.min.js index a6321fd3..019dd70a 100644 --- a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.min.js +++ b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.min.js @@ -1 +1 @@ -(function(a){a.fn.WireTabs=function(c){var d={rememberTabs:0,cookieName:"WireTabs",items:null,skipRememberTabIDs:[],itemsParent:null,id:""};if(ProcessWire.config.JqueryWireTabs.rememberTabs!="undefined"){d.rememberTabs=ProcessWire.config.JqueryWireTabs.rememberTabs}var b=0;a.extend(d,c);return this.each(function(i){var k=null;var e=a(this);var h="";var m=true;function n(){if(!d.items){return}if(d.items.length<1){return}if(d.id.length){k=a("#"+d.id);if(k.length){m=false}else{k=null}}if(!k){k=a("
        ").addClass("WireTabs nav");if(d.id.length){k.attr("id",d.id)}}d.items.each(f);if(m){e.prepend(k)}var p=e;var s=null;var u=l();if(d.rememberTabs==0){p.submit(function(){g(h);return true})}var o=window.location.href;var q="";if(o.indexOf("WireTab")){var r=new RegExp("[&;?]WireTab=([-_a-z0-9]+)","i");q=o.match(r);q=q?q[1]:"";if(q.length){s=k.find("a#_"+q)}}if(s==null){var t=document.location.hash.replace("#","");if(t.length){s=k.find("a#_"+t);if(s.length==0){s=null}else{document.location.hash=""}}}if(s==null&&u.length>0&&d.rememberTabs>-1){s=k.find("a#_"+u)}if(s&&s.length>0){s.click();if(d.rememberTabs==0){g("")}setTimeout(function(){s.click()},200)}else{k.children("li:first").children("a").click()}}function f(){b++;var s=a(this);if(!s.attr("id")){s.attr("id","WireTab"+b)}var r=s.attr("title")||s.attr("id");s.removeAttr("title");var o=s.attr("id");var q=a("a#_"+o);if(q.length>0){q.click(j)}else{var q=a("").attr("href","#"+o).attr("id","_"+o).html(r).click(j);k.append(a("
      • ").append(q))}var p=s.attr("data-tooltip");if(s.hasClass("WireTabTip")||p){q.addClass("tooltip");q.attr("title",p?p:r)}s.hide()}function j(){var o=a(k.find("a.on").removeClass("on").attr("href")).hide();var p=a(a(this).addClass("on").attr("href")).show();var q=p.attr("id");var r=o.attr("id");if(r){e.removeClass(o.attr("id"))}e.addClass(q);if(d.rememberTabs>-1){if(jQuery.inArray(q,d.skipRememberTabIDs)!=-1){q=""}if(d.rememberTabs==1){g(q)}h=q}a(document).trigger("wiretabclick",[p,o]);return false}function g(o){document.cookie=d.cookieName+"="+escape(o)}function l(){var p=new RegExp("(?:^|;)\\s?"+d.cookieName+"=(.*?)(?:;|$)","i");var o=document.cookie.match(p);o=o?o[1]:"";return o}n()})}})(jQuery); \ No newline at end of file +(function(a){a.fn.WireTabs=function(d){var e={rememberTabs:0,cookieName:"WireTabs",items:null,skipRememberTabIDs:[],itemsParent:null,ulClass:"WireTabs nav",ulAttrs:"",liActiveClass:"",aActiveClass:"on",id:""};var c=0;var b=ProcessWire.config.JqueryWireTabs;var g=["rememberTabs","cookieName","liActiveClass","aActiveClass","ulClass","ulAttrs"];for(var h=0;h");o.addClass(e.ulClass);if(e.id.length){o.attr("id",e.id)}}e.items.each(j);if(q){i.prepend(o)}var t=i;var w=null;var y=p();if(e.rememberTabs==0){t.submit(function(){k(l);return true})}var s=window.location.href;var u="";if(s.indexOf("WireTab")){var v=new RegExp("[&;?]WireTab=([-_a-z0-9]+)","i");u=s.match(v);u=u?u[1]:"";if(u.length){w=o.find("a#_"+u)}}if(w==null){var x=document.location.hash.replace("#","");if(x.length){w=o.find("a#_"+x);if(w.length==0){w=null}else{document.location.hash=""}}}if(w==null&&y.length>0&&e.rememberTabs>-1){w=o.find("a#_"+y)}if(w&&w.length>0){w.click();if(e.rememberTabs==0){k("")}setTimeout(function(){w.click()},200)}else{o.children("li:first").children("a").click()}}function j(){c++;var w=a(this);if(!w.attr("id")){w.attr("id","WireTab"+c)}var v=w.attr("title")||w.attr("id");w.removeAttr("title");var s=w.attr("id");var u=a("a#_"+s);if(u.length>0){u.click(n)}else{var u=a("").attr("href","#"+s).attr("id","_"+s).html(v).click(n);o.append(a("
      • ").append(u))}var t=w.attr("data-tooltip");if(w.hasClass("WireTabTip")||t){u.addClass("tooltip");u.attr("title",t?t:v)}w.hide()}function n(){var u=e.aActiveClass;var s=e.liActiveClass;var t=o.find("a."+u);var w=a(this);var v=a(t.attr("href"));var y=a(w.attr("href"));var x=w.attr("id");var z=t.attr("id");t.removeClass(u);w.addClass(u);if(s.length){t.closest("li").removeClass(s);w.closest("li").addClass(s)}v.hide();y.show();if(z){i.removeClass(v.attr("id"))}i.addClass(x);if(e.rememberTabs>-1){if(jQuery.inArray(x,e.skipRememberTabIDs)!=-1){x=""}if(e.rememberTabs==1){k(x)}l=x}a(document).trigger("wiretabclick",[y,v]);return false}function k(s){document.cookie=e.cookieName+"="+escape(s)}function p(){var t=new RegExp("(?:^|;)\\s?"+e.cookieName+"=(.*?)(?:;|$)","i");var s=document.cookie.match(t);s=s?s[1]:"";return s}r()})}})(jQuery); \ No newline at end of file diff --git a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.module b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.module index 26a9be58..5ab3c702 100644 --- a/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.module +++ b/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.module @@ -6,6 +6,8 @@ * ProcessWire 3.x, Copyright 2016 by Ryan Cramer * https://processwire.com * + * @property int $rememberTabs + * */ class JqueryWireTabs extends ModuleJS implements ConfigurableModule { @@ -26,10 +28,31 @@ class JqueryWireTabs extends ModuleJS implements ConfigurableModule { // extending this class causes the class named JS and CSS files to automatically be loaded public function init() { - parent::init(); - wire('config')->js('JqueryWireTabs', array( + + $defaults = array( + 'ulClass' => 'WireTabs nav', + 'ulAttrs' => '', + 'liActiveClass' => '', + 'aActiveClass' => 'on', 'rememberTabs' => (int) $this->rememberTabs, - )); + 'loadStyles' => true, + 'cookieName' => 'WireTabs', + ); + + $className = 'JqueryWireTabs'; + $settings = $this->wire('config')->get($className); + + if(is_array($settings)) { + $settings = array_merge($defaults, $settings); + } else { + $settings = $defaults; + } + + $this->loadStyles = $settings['loadStyles']; + + $this->wire('config')->js($className, $settings); + + parent::init(); } public function getModuleConfigInputfields(array $data) { @@ -54,12 +77,15 @@ class JqueryWireTabs extends ModuleJS implements ConfigurableModule { * */ public function renderTabList(array $tabs, array $options = array()) { + $settings = $this->wire('config')->get('JqueryWireTabs'); $defaults = array( - 'class' => 'WireTabs nav', + 'class' => isset($options['class']) ? $options['class'] : $settings['ulClass'], 'id' => '', ); $options = array_merge($defaults, $options); - $out = "
          "; + $attrs = "class='$options[class]'" . ($options['id'] ? " id='$options[id]'" : ""); + if(!empty($settings['ulAttrs'])) $attrs .= " $settings[ulAttrs]"; + $out = "
            "; foreach($tabs as $tabID => $title) { //$title = $this->wire('sanitizer')->entities1($title); diff --git a/wire/modules/LanguageSupport/LanguageTabs.css b/wire/modules/LanguageSupport/LanguageTabs.css index 1bd60ae8..4a44d392 100644 --- a/wire/modules/LanguageSupport/LanguageTabs.css +++ b/wire/modules/LanguageSupport/LanguageTabs.css @@ -1,92 +1,69 @@ -.pw-content .langTabsContainer, -#content .langTabsContainer { - padding-bottom: 0; -} +.langTabs { + position: relative; + padding: 0; } -.pw-content .langTabsContainer .InputfieldError, -#content .langTabsContainer .InputfieldError { - margin-bottom: 0; -} +.LanguageTabsJqueryUI .langTabs > ul { + display: none; } +.LanguageTabsJqueryUI .hasLangTabs .langTabs > ul { + display: block; } +.LanguageTabsJqueryUI .pw-content .langTabsContainer, +.LanguageTabsJqueryUI #content .langTabsContainer { + padding-bottom: 0; } +.LanguageTabsJqueryUI .pw-content .langTabsContainer .InputfieldError, +.LanguageTabsJqueryUI #content .langTabsContainer .InputfieldError { + margin-bottom: 0; } +.LanguageTabsJqueryUI .langTabs .ui-tabs-nav.ui-widget-header { + padding: 2px 3px 0; + border-bottom: none; } +.LanguageTabsJqueryUI .langTabs .ui-tabs-panel { + padding: 0.9em; + border-top: none; } +.LanguageTabsJqueryUI .langTabs .ui-tabs-panel .LanguageSupportLabel { + display: none; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav { + margin-bottom: 0; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav li { + margin: 0 4px 0 0; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav li a { + padding: 0.3em 0.7em; + font-weight: bold; + outline: none; + font-size: 0.846153846153846em; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active.ui-state-default { + border: 1px solid #fff; + padding-bottom: 0; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active { + background: #fff; } +.LanguageTabsJqueryUI .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active a { + cursor: default; + background: #fff; + margin: 0; } +.LanguageTabsJqueryUI .langTabEmpty a { + opacity: 0.7; + font-weight: normal !important; } +.LanguageTabsJqueryUI .InputfieldImage .InputfieldFileLink + .langTabsContainer { + margin-top: 0.5em; } +.LanguageTabsJqueryUI .hadLanguageSupport > .InputfieldContent > .LanguageSupport { + margin-bottom: 0; } -.langTabs{ - position: relative; - padding: 0; -} -.langTabs .ui-tabs-nav.ui-widget-header{ - padding: 2px 3px 0 ; - border-bottom: none; -} -.langTabs .ui-tabs-panel { - padding: 0.9em; - border-top: none; -} -.langTabs .ui-tabs-panel .LanguageSupportLabel { - display: none; - -} -.langTabs.ui-tabs .ui-tabs-nav { - margin-bottom: 0; -} -.langTabs.ui-tabs .ui-tabs-nav li { - margin: 0 4px 0 0; -} -.langTabs.ui-tabs .ui-tabs-nav li a { - padding: 0.3em 0.7em; - font-weight: bold; - outline: none; - font-size: 0.846153846153846em; -} -.langTabs.ui-tabs .ui-tabs-nav li.ui-state-active.ui-state-default{ - border: 1px solid #fff; - padding-bottom: 0; -} -.langTabs.ui-tabs .ui-tabs-nav li.ui-state-active { - background: #fff; -} -.langTabs.ui-tabs .ui-tabs-nav li.ui-state-active a { - cursor: default; - background: #fff; - margin: 0; -} - -.langTabsToggle{ - float: right; - margin-right: 1em; -} +.langTabsToggle { + float: right; + margin-right: 1em; } .InputfieldStateCollapsed .langTabsToggle { - display: none; -} - -.langTabEmpty a { - opacity: 0.7; - font-weight: normal !important; -} - -.langTabs > ul { - display: none; -} - -.hasLangTabs .langTabs > ul { - display: block; -} - -.InputfieldImage .InputfieldFileLink + .langTabsContainer { - margin-top: 0.5em; -} - -.hadLanguageSupport > .InputfieldContent > .LanguageSupport { - margin-bottom: 0; -} + display: none; } .langTabsHidden, .hadLanguageSupport .LanguageSupportLabel { - display: none; -} + display: none; } .langTabsNote { - position: absolute; - top: 5px; - right: 1em; - display: none; -} + position: absolute; + top: 5px; + right: 1em; + display: none; } + +.langTabs > ul > li { + cursor: pointer; } + +/*# sourceMappingURL=LanguageTabs.css.map */ diff --git a/wire/modules/LanguageSupport/LanguageTabs.js b/wire/modules/LanguageSupport/LanguageTabs.js index 72f3c03f..39a78294 100644 --- a/wire/modules/LanguageSupport/LanguageTabs.js +++ b/wire/modules/LanguageSupport/LanguageTabs.js @@ -34,29 +34,33 @@ function longclickLanguageTab(e) { */ function setupLanguageTabs($form) { var $langTabs; + var cfg = ProcessWire.config.LanguageTabs; if($form.hasClass('langTabs')) $langTabs = $form; else $langTabs = $form.find('.langTabs'); $langTabs.each(function() { var $this = $(this); - if($this.hasClass('ui-tabs')) return; + if($this.hasClass('langTabsInit')) return; var $inputfield = $this.closest('.Inputfield'); var $content = $inputfield.children('.InputfieldContent'); if(!$content.hasClass('langTabsContainer')) { if($inputfield.find('.langTabsContainer').length == 0) $content.addClass('langTabsContainer'); } - $this.tabs({ active: ProcessWire.config.LanguageTabs.activeTab }); + if(cfg.jQueryUI) $this.tabs({active: cfg.activeTab}); + $this.addClass('langTabsInit'); if($inputfield.length) $inputfield.addClass('hasLangTabs'); var $parent = $this.parent('.InputfieldContent'); if($parent.length) { var $span = $("") - .attr('title', ProcessWire.config.LanguageTabs.title) + .attr('title', cfg.labelOpen) .attr('class', 'langTabsToggle') .append(""); $parent.prev('.InputfieldHeader').append($span); } + var $links = $this.find('a'); var timeout = null; var $note = $parent.find('.langTabsNote'); + $links.on('mouseover', function() { if(timeout) clearTimeout(timeout); if($parent.width() < 500) return; @@ -65,7 +69,22 @@ function setupLanguageTabs($form) { if(timeout) clearTimeout(timeout); if($parent.width() < 500) return; timeout = setTimeout(function() { $note.fadeOut('fast'); }, 250); - }); + }).on('click', function() { + var $a = $(this); + var $items = $a.closest('ul').siblings('.LanguageSupport'); + var $closeItem = $items.filter('.LanguageSupportCurrent'); + var $openItem = $items.filter($a.attr('href')); + if($closeItem.attr('id') == $openItem.attr('id')) { + $a.trigger('longclick'); + } else { + $closeItem.removeClass('LanguageSupportCurrent'); + $openItem.addClass('LanguageSupportCurrent'); + } + }); + + if(!cfg.jQueryUI) { + $links.eq(cfg.activeTab).click(); + } }); } @@ -81,22 +100,32 @@ function toggleLanguageTabs() { var $content = $header.next('.InputfieldContent'); var $inputfield = $header.parent('.Inputfield'); var $langTabs = $content.children('.langTabs'); + var $ul = $langTabs.children('ul'); + var cfg = ProcessWire.config.LanguageTabs; + if($content.hasClass('langTabsContainer')) { - $content.find('.ui-tabs-nav').find('a').click(); // activate all (i.e. for CKEditor) + $ul.find('a').click(); // activate all (i.e. for CKEditor) $content.removeClass('langTabsContainer'); - $inputfield.removeClass('hasLangTabs'); + $inputfield.removeClass('hasLangTabs').addClass('langTabsOff'); $this.addClass('langTabsOff'); - $langTabs.tabs('destroy'); + if(cfg.jQueryUI) { + $langTabs.tabs('destroy'); + } else { + $ul.hide(); + } $this.attr("title", ProcessWire.config.LanguageTabs.labelClose) .find('i').removeClass("fa-folder-o").addClass("fa-folder-open-o"); } else { $content.addClass('langTabsContainer'); - $inputfield.addClass('hasLangTabs'); + $inputfield.addClass('hasLangTabs').removeClass('langTabsOff'); $this.removeClass('langTabsOff'); - $langTabs.tabs(); - $(this).attr("title", ProcessWire.config.LanguageTabs.labelOpen) - .find('i').addClass("fa-folder-o").removeClass("fa-folder-open-o"); + if(cfg.jQueryUI) { + $langTabs.tabs(); + } else { + $ul.show(); + } + $(this).attr("title", cfg.labelOpen).find('i').addClass("fa-folder-o").removeClass("fa-folder-open-o"); } return false; } @@ -122,7 +151,8 @@ function hideLanguageTabs() { // make sure first tab is clicked var $tab = $(".langTabs").find("li:eq(0)"); - if(!$tab.hasClass('ui-state-active')) $tab.find('a').click(); + var cfg = ProcessWire.config.LanguageTabs; + if(!$tab.hasClass(cfg.liActiveClass)) $tab.find('a').click(); // hide the tab toggler $(".langTabsToggle, .LanguageSupportLabel:visible, .langTabs > ul").addClass('langTabsHidden'); diff --git a/wire/modules/LanguageSupport/LanguageTabs.min.js b/wire/modules/LanguageSupport/LanguageTabs.min.js index 369be2a3..8cbd80ae 100644 --- a/wire/modules/LanguageSupport/LanguageTabs.min.js +++ b/wire/modules/LanguageSupport/LanguageTabs.min.js @@ -1 +1 @@ -var clickLanguageTabActive=false;function longclickLanguageTab(c){if(clickLanguageTabActive){return}clickLanguageTabActive=true;var b=$(this);var d=b.attr("data-lang");var a=b.closest("form").find("a.langTab"+d).not(b);b.click();a.click();a.effect("highlight",250);setTimeout(function(){clickLanguageTabActive=false},250)}function setupLanguageTabs(a){var b;if(a.hasClass("langTabs")){b=a}else{b=a.find(".langTabs")}b.each(function(){var i=$(this);if(i.hasClass("ui-tabs")){return}var f=i.closest(".Inputfield");var e=f.children(".InputfieldContent");if(!e.hasClass("langTabsContainer")){if(f.find(".langTabsContainer").length==0){e.addClass("langTabsContainer")}}i.tabs({active:ProcessWire.config.LanguageTabs.activeTab});if(f.length){f.addClass("hasLangTabs")}var h=i.parent(".InputfieldContent");if(h.length){var d=$("").attr("title",ProcessWire.config.LanguageTabs.title).attr("class","langTabsToggle").append("");h.prev(".InputfieldHeader").append(d)}var j=i.find("a");var g=null;var c=h.find(".langTabsNote");j.on("mouseover",function(){if(g){clearTimeout(g)}if(h.width()<500){return}g=setTimeout(function(){c.fadeIn("fast")},250)}).on("mouseout",function(){if(g){clearTimeout(g)}if(h.width()<500){return}g=setTimeout(function(){c.fadeOut("fast")},250)})})}function toggleLanguageTabs(){var e=$(this);var a=e.closest(".InputfieldHeader");var b=a.next(".InputfieldContent");var d=a.parent(".Inputfield");var c=b.children(".langTabs");if(b.hasClass("langTabsContainer")){b.find(".ui-tabs-nav").find("a").click();b.removeClass("langTabsContainer");d.removeClass("hasLangTabs");e.addClass("langTabsOff");c.tabs("destroy");e.attr("title",ProcessWire.config.LanguageTabs.labelClose).find("i").removeClass("fa-folder-o").addClass("fa-folder-open-o")}else{b.addClass("langTabsContainer");d.addClass("hasLangTabs");e.removeClass("langTabsOff");c.tabs();$(this).attr("title",ProcessWire.config.LanguageTabs.labelOpen).find("i").addClass("fa-folder-o").removeClass("fa-folder-open-o")}return false}function hideLanguageTabs(){$(".InputfieldContent").each(function(){var b=0;$(this).children(".LanguageSupport").each(function(){if(++b==1){$(this).closest(".Inputfield").addClass("hadLanguageSupport");return}$(this).addClass("langTabsHidden")})});var a=$(".langTabs").find("li:eq(0)");if(!a.hasClass("ui-state-active")){a.find("a").click()}$(".langTabsToggle, .LanguageSupportLabel:visible, .langTabs > ul").addClass("langTabsHidden");$(".hasLangTabs").removeClass("hasLangTabs").addClass("hadLangTabs")}function unhideLanguageTabs(){$(".langTabsHidden").removeClass("langTabsHidden");$(".hadLangTabs").removeClass("hadLangTabs").addClass("hasLangTabs");$(".hadLanguageSupport").removeClass("hadLanguageSupport")}jQuery(document).ready(function(){$(document).on("click",".langTabsToggle",toggleLanguageTabs);$(document).on("longclick",".langTabs a",longclickLanguageTab);$(document).on("reloaded",".Inputfield",function(){setupLanguageTabs($(this))});$(document).on("AjaxUploadDone",".InputfieldHasFileList .InputfieldFileList",function(){setupLanguageTabs($(this))})}); \ No newline at end of file +var clickLanguageTabActive=false;function longclickLanguageTab(c){if(clickLanguageTabActive){return}clickLanguageTabActive=true;var b=$(this);var d=b.attr("data-lang");var a=b.closest("form").find("a.langTab"+d).not(b);b.click();a.click();a.effect("highlight",250);setTimeout(function(){clickLanguageTabActive=false},250)}function setupLanguageTabs(b){var c;var a=ProcessWire.config.LanguageTabs;if(b.hasClass("langTabs")){c=b}else{c=b.find(".langTabs")}c.each(function(){var j=$(this);if(j.hasClass("langTabsInit")){return}var g=j.closest(".Inputfield");var f=g.children(".InputfieldContent");if(!f.hasClass("langTabsContainer")){if(g.find(".langTabsContainer").length==0){f.addClass("langTabsContainer")}}if(a.jQueryUI){j.tabs({active:a.activeTab})}j.addClass("langTabsInit");if(g.length){g.addClass("hasLangTabs")}var i=j.parent(".InputfieldContent");if(i.length){var e=$("").attr("title",a.labelOpen).attr("class","langTabsToggle").append("");i.prev(".InputfieldHeader").append(e)}var k=j.find("a");var h=null;var d=i.find(".langTabsNote");k.on("mouseover",function(){if(h){clearTimeout(h)}if(i.width()<500){return}h=setTimeout(function(){d.fadeIn("fast")},250)}).on("mouseout",function(){if(h){clearTimeout(h)}if(i.width()<500){return}h=setTimeout(function(){d.fadeOut("fast")},250)}).on("click",function(){var n=$(this);var o=n.closest("ul").siblings(".LanguageSupport");var m=o.filter(".LanguageSupportCurrent");var l=o.filter(n.attr("href"));if(m.attr("id")==l.attr("id")){n.trigger("longclick")}else{m.removeClass("LanguageSupportCurrent");l.addClass("LanguageSupportCurrent")}});if(!a.jQueryUI){k.eq(a.activeTab).click()}})}function toggleLanguageTabs(){var g=$(this);var b=g.closest(".InputfieldHeader");var d=b.next(".InputfieldContent");var f=b.parent(".Inputfield");var e=d.children(".langTabs");var c=e.children("ul");var a=ProcessWire.config.LanguageTabs;if(d.hasClass("langTabsContainer")){c.find("a").click();d.removeClass("langTabsContainer");f.removeClass("hasLangTabs").addClass("langTabsOff");g.addClass("langTabsOff");if(a.jQueryUI){e.tabs("destroy")}else{c.hide()}g.attr("title",ProcessWire.config.LanguageTabs.labelClose).find("i").removeClass("fa-folder-o").addClass("fa-folder-open-o")}else{d.addClass("langTabsContainer");f.addClass("hasLangTabs").removeClass("langTabsOff");g.removeClass("langTabsOff");if(a.jQueryUI){e.tabs()}else{c.show()}$(this).attr("title",a.labelOpen).find("i").addClass("fa-folder-o").removeClass("fa-folder-open-o")}return false}function hideLanguageTabs(){$(".InputfieldContent").each(function(){var c=0;$(this).children(".LanguageSupport").each(function(){if(++c==1){$(this).closest(".Inputfield").addClass("hadLanguageSupport");return}$(this).addClass("langTabsHidden")})});var b=$(".langTabs").find("li:eq(0)");var a=ProcessWire.config.LanguageTabs;if(!b.hasClass(a.liActiveClass)){b.find("a").click()}$(".langTabsToggle, .LanguageSupportLabel:visible, .langTabs > ul").addClass("langTabsHidden");$(".hasLangTabs").removeClass("hasLangTabs").addClass("hadLangTabs")}function unhideLanguageTabs(){$(".langTabsHidden").removeClass("langTabsHidden");$(".hadLangTabs").removeClass("hadLangTabs").addClass("hasLangTabs");$(".hadLanguageSupport").removeClass("hadLanguageSupport")}jQuery(document).ready(function(){$(document).on("click",".langTabsToggle",toggleLanguageTabs);$(document).on("longclick",".langTabs a",longclickLanguageTab);$(document).on("reloaded",".Inputfield",function(){setupLanguageTabs($(this))});$(document).on("AjaxUploadDone",".InputfieldHasFileList .InputfieldFileList",function(){setupLanguageTabs($(this))})}); \ No newline at end of file diff --git a/wire/modules/LanguageSupport/LanguageTabs.module b/wire/modules/LanguageSupport/LanguageTabs.module index 8da5132b..a22da4b9 100644 --- a/wire/modules/LanguageSupport/LanguageTabs.module +++ b/wire/modules/LanguageSupport/LanguageTabs.module @@ -37,6 +37,8 @@ class LanguageTabs extends WireData implements Module, ConfigurableModule { */ protected $tabs = array(); + protected $settings = array(); + public function __construct() { $this->set('tabField', 'title'); } @@ -48,31 +50,52 @@ class LanguageTabs extends WireData implements Module, ConfigurableModule { public function ready() { if($this->wire('page')->template != 'admin') return; $this->addHookAfter('InputfieldForm::render', $this, 'hookRenderInputfieldForm'); - + } + + public function getSettings() { + if(!empty($this->settings)) return $this->settings; $language = null; // allow for specifying language in your "edit" page link, from front-end // so if you want to focus on the Spanish tabs when the user clicks "edit" // from /es/path/to/page/, then you can by using a page edit link like: // Edit $id = (int) $this->input->get('language'); - if($id) $language = $this->languages->get($id); + if($id) $language = $this->languages->get($id); // if language is not specified as a GET variable, then use the user's language - if(!$language || !$language->id) $language = $this->user->language; + if(!$language || !$language->id) $language = $this->user->language; // determine the index of the tab for the user's language - $activeTab = 0; + $activeTab = 0; foreach($this->languages as $index => $lang) { - if($lang->id == $language->id) $activeTab = $index; + if($lang->id == $language->id) $activeTab = $index; } - $settings = array( + $defaults = array( + 'jQueryUI' => true, // use jQuery UI tabs? 'labelOpen' => $this->_('Expand Language Tabs'), - 'labelClose' => $this->_('Collapse/Convert Back to Tabs'), - 'activeTab' => $activeTab, - ); + 'labelClose' => $this->_('Collapse/Convert Back to Tabs'), + 'activeTab' => $activeTab, + 'ulClass' => '', + 'ulAttrs' => '', + 'liActiveClass' => '', + 'liDisabledClass' => '', + 'liEmptyClass' => '', + 'aClass' => '', + 'loadStyles' => true, + 'loadScripts' => true, + ); - $this->wire('config')->js('LanguageTabs', $settings); + $settings = $this->wire('config')->get('LanguageTabs'); + if(is_array($settings)) { + $this->settings = array_merge($defaults, $settings); + } else { + $this->settings = $defaults; + } + + $this->wire('config')->js('LanguageTabs', $this->settings); + + return $this->settings; } /** @@ -82,7 +105,22 @@ class LanguageTabs extends WireData implements Module, ConfigurableModule { * */ public function hookRenderInputfieldForm(HookEvent $e) { - $this->wire('modules')->loadModuleFileAssets($this); + + $settings = $this->getSettings(); + $config = $this->wire('config'); + + if($settings['jQueryUI']) { + $this->wire('adminTheme')->addBodyClass('LanguageTabsJqueryUI'); + } + + if($settings['loadStyles']) { + $config->styles->add($config->urls->LanguageTabs . 'LanguageTabs.css'); + } + if($settings['loadScripts']) { + $config->scripts->add($config->urls->LanguageTabs . 'LanguageTabs.js'); + } + + // $this->wire('modules')->loadModuleFileAssets($this); $this->wire('modules')->get('JqueryCore')->use('longclick'); if(strpos($e->return, 'LanguageSupport') === false) return; /** @var InputfieldForm $form */ @@ -107,20 +145,26 @@ class LanguageTabs extends WireData implements Module, ConfigurableModule { * */ public function addTab(Inputfield $inputfield, Language $language) { - $liClass = ''; - $class = 'langTab' . $language->id; - if($inputfield->isEmpty()) $liClass .= 'langTabEmpty '; + $settings = $this->getSettings(); + $liClasses = array(); + $aClasses = array('langTab' . $language->id); $title = $language->get($this->tabField); if(empty($title)) $title = $language->get('name'); $title = $this->wire('sanitizer')->entities1($title); if(!$this->wire('languages')->editable($language)) { $title = "$title"; - $liClass .= 'LanguageNotEditable '; + $liClasses[] = 'LanguageNotEditable'; + $liClasses[] = $settings['liDisabledClass']; + } + if($inputfield->isEmpty()) { + $liClasses[] = 'langTabEmpty'; + $liClasses[] = $settings['liEmptyClass']; } $id = $inputfield->attr('id'); - $liClass = trim($liClass); + $liClass = implode(' ', $liClasses); + $aClass = implode(' ', $aClasses); /** @noinspection HtmlUnknownAnchorTarget */ - $this->tabs[] = "
          • $title
          • "; + $this->tabs[] = "
          • $title
          • "; } /** @@ -135,14 +179,18 @@ class LanguageTabs extends WireData implements Module, ConfigurableModule { * */ public function renderTabs(Inputfield $inputfield, $content) { + $settings = $this->getSettings(); if(count($this->tabs) > 1) { $inputfield->wrapClass .= " hasLangTabs"; $inputfield->contentClass .= " langTabsContainer"; $tabs = implode('', $this->tabs); $id = $inputfield->attr('id'); $note = "" . - $this->_('click+hold to change all tabs') . ""; - $content = "
            $note
              $tabs
            $content
            "; + $this->_('click twice to change all tabs') . ""; + $attrs = $settings['ulAttrs']; + $attrs .= $settings['ulClass'] ? " class='$settings[ulClass]'" : ""; + $attrs = strlen($attrs) ? " " . trim($attrs) : ""; + $content = "
            $note$tabs
          $content
        "; } else { // do nothing, just return content because there was only 1 tab (no render necessary) } diff --git a/wire/modules/LanguageSupport/LanguageTabs.scss b/wire/modules/LanguageSupport/LanguageTabs.scss new file mode 100644 index 00000000..55779f87 --- /dev/null +++ b/wire/modules/LanguageSupport/LanguageTabs.scss @@ -0,0 +1,99 @@ + +.langTabs { + position: relative; + padding: 0; +} + +.LanguageTabsJqueryUI { + .langTabs > ul { + display: none; + } + + .hasLangTabs .langTabs > ul { + display: block; + } + .pw-content .langTabsContainer, + #content .langTabsContainer { + padding-bottom: 0; + } + + .pw-content .langTabsContainer .InputfieldError, + #content .langTabsContainer .InputfieldError { + margin-bottom: 0; + } + + .langTabs .ui-tabs-nav.ui-widget-header { + padding: 2px 3px 0; + border-bottom: none; + } + .langTabs .ui-tabs-panel { + padding: 0.9em; + border-top: none; + } + .langTabs .ui-tabs-panel .LanguageSupportLabel { + display: none; + + } + .langTabs.ui-tabs .ui-tabs-nav { + margin-bottom: 0; + } + .langTabs.ui-tabs .ui-tabs-nav li { + margin: 0 4px 0 0; + } + .langTabs.ui-tabs .ui-tabs-nav li a { + padding: 0.3em 0.7em; + font-weight: bold; + outline: none; + font-size: 0.846153846153846em; + } + .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active.ui-state-default { + border: 1px solid #fff; + padding-bottom: 0; + } + .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active { + background: #fff; + } + .langTabs.ui-tabs .ui-tabs-nav li.ui-state-active a { + cursor: default; + background: #fff; + margin: 0; + } + .langTabEmpty a { + opacity: 0.7; + font-weight: normal !important; + } + + .InputfieldImage .InputfieldFileLink + .langTabsContainer { + margin-top: 0.5em; + } + + .hadLanguageSupport > .InputfieldContent > .LanguageSupport { + margin-bottom: 0; + } + +} + +.langTabsToggle { + float: right; + margin-right: 1em; +} + +.InputfieldStateCollapsed .langTabsToggle { + display: none; +} + +.langTabsHidden, +.hadLanguageSupport .LanguageSupportLabel { + display: none; +} + +.langTabsNote { + position: absolute; + top: 5px; + right: 1em; + display: none; +} + +.langTabs > ul > li { + cursor: pointer; +} diff --git a/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.module b/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.module index a9d7dc63..b311fb60 100644 --- a/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.module +++ b/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.module @@ -5,63 +5,146 @@ * * @method string render() * + * @property array $headerRow + * @property array $footerRow + * @property array $rows + * @property array $rowClasses + * @property array $rowAttrs + * @property array $actions + * @property bool $encodeEntities + * @property bool $sortable + * @property bool $resizable + * @property string $class + * @property string $caption + * @property bool $responsive + * @property array $settings + * @property string $id + * */ class MarkupAdminDataTable extends ModuleJS { - - const responsiveNo = 0; - const responsiveYes = 1; // each td becomes 1-row, each 2 columns with th + td side-by-side - const responsiveAlt = 2; // each td becomes 1-row, with th + td stacked on top of each other - - static protected $instanceCnt = 0; - - protected $headerRow = array(); - protected $footerRow = array(); - protected $rows = array(); - protected $rowClasses = array(); - protected $rowAttrs = array(); - protected $actions = array(); - protected $encodeEntities = true; - protected $sortable = true; - protected $resizable = false; - protected $class = ''; - protected $caption = ''; - protected $responsive = self::responsiveYes; - protected $id = ''; public static function getModuleInfo() { return array( - 'title' => 'Admin Data Table', - 'summary' => 'Generates markup for data tables used by ProcessWire admin', - 'version' => 107, - 'permanent' => true, - ); + 'title' => 'Admin Data Table', + 'summary' => 'Generates markup for data tables used by ProcessWire admin', + 'version' => 107, + 'permanent' => true, + ); } + const responsiveNo = 0; // responsive off + const responsiveYes = 1; // each td becomes 1-row, each 2 columns with th + td side-by-side + const responsiveAlt = 2; // each td becomes 1-row, with th + td stacked on top of each other + + /** + * Number of table instances, for unique id attributes + * + * @var int + * + */ + static protected $instanceCnt = 0; + + /** + * Table rows + * + * @var array + * + */ + protected $rows = array(); + + protected $headerRow = array(); + + protected $footerRow = array(); + + protected $rowClasses = array(); + + protected $rowAttrs = array(); + + protected $actions = array(); + + /** + * Initialize module and default settings + * + */ public function init() { + + + // defaults for settings that are typically set globally for all tables + $defaults = array( + 'class' => 'AdminDataTable AdminDataList', + 'addClass' => '', + 'responsiveClass' => 'AdminDataTableResponsive', + 'responsiveAltClass' => 'AdminDataTableResponsiveAlt', + 'sortableClass' => 'AdminDataTableSortable', + 'resizableClass' => 'AdminDataTableResizable', + 'loadStyles' => true, + 'loadScripts' => true, + ); + + // settings set globally for all tables (when present) + $settings = $this->wire('config')->MarkupAdminDataTable; + + if(empty($settings)) { + $settings = $defaults; + } else { + $settings = array_merge($defaults, $settings); + } + + if(!empty($settings['sortableClass'])) { + $this->modules->get("JqueryTableSorter"); + } + + $this->loadStyles = $settings['loadStyles']; + $this->loadScripts = $settings['loadScripts']; + + $this->set('encodeEntities', true); + $this->set('sortable', true); + $this->set('resizable', false); + $this->set('class', ''); // extra class(es), populated by addClass() method + $this->set('caption', ''); + $this->set('responsive', self::responsiveYes); + $this->set('settings', $settings); + $this->set('id', ''); + parent::init(); - $this->modules->get("JqueryTableSorter"); } + /** + * Set the header row for the table + * + * @param array $a Array of header row labels (strings) + * @return $this + * + */ public function headerRow(array $a) { $this->headerRow = $a; return $this; } + /** + * Set the footer row for the table + * + * @param array $a Array of footer row labels (strings) + * @return $this + * + */ public function footerRow(array $a) { $this->footerRow = $this->setupRow($a); return $this; } /** - * @param array $a Array of columns that will each be a , where each element may be one of the following: - * - string: converts to string - * - string => url: converts to string - * - array(string, class): converts to string + * Add a row to the table + * + * @param array $a Array of columns that will each be a ``, where each element may be one of the following: + * - `string`: converts to `string` + * - `array('label' => 'url')`: converts to `label` + * - `array('label', 'class')`: converts to `label` * @param array $options Optionally specify any one of the following: * - separator (bool): specify true to show a stronger visual separator above the column - * - class (string): specify one or more class names to apply to the - * - attrs (array): array of attr => value for attributes to add to the + * - class (string): specify one or more class names to apply to the `` + * - attrs (array): array of attr => value for attributes to add to the `` * @return $this * */ @@ -82,6 +165,13 @@ class MarkupAdminDataTable extends ModuleJS { return $this; } + /** + * Setup/prepare a table row for rendering (internal) + * + * @param array $a + * @return array + * + */ protected function setupRow(array $a) { $row = array(); @@ -103,6 +193,13 @@ class MarkupAdminDataTable extends ModuleJS { return $row; } + /** + * Add action(s) button underneath the table + * + * @param array $action Array in format array('button-label' => 'url') + * @return $this + * + */ public function action(array $action) { foreach($action as $label => $url) { $this->actions[$label] = $url; @@ -110,19 +207,28 @@ class MarkupAdminDataTable extends ModuleJS { return $this; } + /** + * Render the table + * + * @return string + * + */ public function ___render() { - $tableClass = trim("AdminDataTable AdminDataList {$this->class}"); + $tableClass = trim($this->settings('class') . ' ' . $this->class); if($this->responsive == self::responsiveYes) { - $tableClass .= " AdminDataTableResponsive"; + $tableClass .= ' ' . $this->settings('responsiveClass'); } else if($this->responsive == self::responsiveAlt) { - $tableClass .= " AdminDataTableResponsive AdminDataTableResponsiveAlt"; + $tableClass .= ' ' . $this->settings('responsiveClass') . ' ' . $this->settings('responsiveAltClass'); } - if($this->sortable) $tableClass .= " AdminDataTableSortable"; + if($this->sortable) $tableClass .= ' ' . $this->settings('sortableClass'); if($this->resizable) { - $tableClass .= " AdminDataTableResizable"; - $this->modules->get("JqueryTableSorter")->use('widgets'); + $tableClass .= ' ' . $this->settings('resizableClass'); + /** @var JqueryTableSorter $tableSorter */ + $tableSorter = $this->modules->get('JqueryTableSorter'); + $tableSorter->use('widgets'); } + if($this->settings('addClass')) $tableClass .= ' ' . $this->settings('addClass'); $out = ''; $maxCols = 0; $id = $this->id ? $this->id : "AdminDataTable" . (++self::$instanceCnt); @@ -177,7 +283,7 @@ class MarkupAdminDataTable extends ModuleJS { $out .= "\n\t"; $out .= "\n"; - if($this->responsive) { + if($this->responsive && strpos($this->settings('responsiveClass'), 'AdminDataTableResponsive') === 0) { $out .= "\n"; } } @@ -185,6 +291,7 @@ class MarkupAdminDataTable extends ModuleJS { if(count($this->actions)) { $out .= "\n

        "; foreach($this->actions as $label => $url) { + /** @var InputfieldButton $button */ $button = $this->modules->get("InputfieldButton"); $button->href = $url; $button->value = $label; @@ -196,35 +303,84 @@ class MarkupAdminDataTable extends ModuleJS { return $out; } + /** + * Entity encode string (when entity encoding enabled) + * + * @param string $str + * @return string + * + */ protected function encode($str) { if(!$this->encodeEntities) return $str; return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); - } + } + /** + * Set whether or not entity encoding is enabled + * + * @param bool $encodeEntities + * + */ public function setEncodeEntities($encodeEntities = true) { $this->encodeEntities = $encodeEntities ? true : false; } + /** + * Set class(es) to add to table + * + * @param string $class + * + */ public function setClass($class) { $this->class = $this->encode($class); } - + + /** + * Add a class to the table (without replacing existing ones) + * + * @param string $class + * + */ public function addClass($class) { $this->class = trim($this->class . " " . $this->encode($class)); } + /** + * Set whether or not table is sortable + * + * @param bool $sortable + * + */ public function setSortable($sortable) { $this->sortable = $sortable ? true : false; } - + + /** + * Set whether or not table is resizable + * + * @param bool $resizable + * + */ public function setResizable($resizable) { $this->resizable = $resizable ? true : false; } + /** + * Set table caption + * + * @param string $caption + * + */ public function setCaption($caption) { $this->caption = $this->encode($caption); } - + + /** + * Set table id attribute + * + * @param string $id + * + */ public function setID($id) { $this->id = $id; } @@ -241,9 +397,27 @@ class MarkupAdminDataTable extends ModuleJS { public function setResponsive($responsive = true) { $this->responsive = (int) $responsive; } - - /** the following are specific to the Module interface **/ + /** + * Get or set an internal setting + * + * @pw-internal + * + * @param string $key Setting to get or set + * @param mixed $value Optional value to set + * @return string|int|array|null|MarkupAdminDataTable + * + */ + public function settings($key, $value = null) { + $settings = parent::get('settings'); + if(is_null($value)) { + return isset($settings[$key]) ? $settings[$key] : null; + } else { + $settings[$key] = $value; + parent::set('settings', $settings); + return $this; + } + } public function isSingular() { return false; diff --git a/wire/modules/Markup/MarkupPagerNav/MarkupPagerNav.module b/wire/modules/Markup/MarkupPagerNav/MarkupPagerNav.module index 61ccba19..763e70ad 100644 --- a/wire/modules/Markup/MarkupPagerNav/MarkupPagerNav.module +++ b/wire/modules/Markup/MarkupPagerNav/MarkupPagerNav.module @@ -233,6 +233,10 @@ class MarkupPagerNav extends Wire implements Module { $this->options['nextItemAriaLabel'] = $this->_('Next page'); $this->options['previousItemAriaLabel'] = $this->_('Previous page'); $this->options['lastItemAriaLabel'] = $this->_('Page {n}, last page'); + + // check for all-instance options + $options = $this->wire('config')->MarkupPagerNav; + if(is_array($options)) $this->options = array_merge($this->options, $options); } /** diff --git a/wire/modules/Process/ProcessList.module b/wire/modules/Process/ProcessList.module index b9473e4b..1c7db45a 100644 --- a/wire/modules/Process/ProcessList.module +++ b/wire/modules/Process/ProcessList.module @@ -32,24 +32,46 @@ class ProcessList extends Process { } protected function render() { - $out = "\n

        "){m=a.indexOf("
        ");a=a.substring(0,m);$("body").append("