diff --git a/wire/core/Process.php b/wire/core/Process.php index c5204832..5a0e1cfd 100644 --- a/wire/core/Process.php +++ b/wire/core/Process.php @@ -375,11 +375,11 @@ abstract class Process extends WireData implements Module { // already have what we need } else if(ctype_digit("$parent")) { $parent = $pages->get((int) $parent); - } else if(strpos($parent, '/') !== false) { + } else if(strpos("$parent", '/') !== false) { $parent = $pages->get($parent); } else if($parent) { $parent = $sanitizer->pageName($parent); - $parent = $adminPage->child("include=all, name=$parent"); + if(strlen($parent)) $parent = $adminPage->child("include=all, name=$parent"); } if(!$parent || !$parent->id) $parent = $adminPage; // default $page = $parent->child("include=all, name=$name"); // does it already exist? diff --git a/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.js b/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.js index 59b9b15f..96706d12 100644 --- a/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.js +++ b/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.js @@ -166,7 +166,7 @@ $(document).ready(function() { } var $linkRel = $("#link_rel"); - if($linkRel.length && $linkRel.val().length) { + if($linkRel.length && $linkRel.val() && $linkRel.val().length) { $link.attr('rel', $linkRel.val()); } @@ -274,7 +274,11 @@ $(document).ready(function() { } var extLinkClass = cfg.extLinkClass; if(extLinkClass.length > 0) { - extLinkClass = extLinkClass.split(' '); + if(extLinkClass.indexOf(' ') > -1) { + var extLinkClassAll = extLinkClass.replace(' ', '_'); + $("#link_class_" + extLinkClassAll).prop('checked', true); // all classes in 1 option + extLinkClass = extLinkClass.split(' '); + } for(n = 0; n < extLinkClass.length; n++) { // $("#link_class_" + extLinkClass[n]).attr('checked', 'checked'); // JQM $("#link_class_" + extLinkClass[n]).prop('checked', true); diff --git a/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.min.js b/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.min.js index e91fcfdc..e7c888f8 100644 --- a/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.min.js +++ b/wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.min.js @@ -1 +1 @@ -$(document).ready(function(){if(!ProcessWire.config.ProcessPageEditLink)return;var cfg=ProcessWire.config.ProcessPageEditLink;var options={selectStartLabel:cfg.selectStartLabel,selectSelectLabel:cfg.selectStartLabel,langID:cfg.langID};var options2={selectStartLabel:options.selectStartLabel,selectSelectLabel:options.selectStartLabel,langID:options.langID,rootPageID:cfg.pageID};var selectedPageData={id:0,title:"",url:""};var $fileSelect=$("#link_page_file");var $anchorSelect=$("#link_page_anchor");var $linkPageURL=$("#link_page_url_input");var $linkText=$("#link_text");$linkPageURL.val($("#link_page_url").val());function populateFileSelect(selectedPageData){var $wrap=$("#wrap_link_page_file");$.getJSON("./files?id="+selectedPageData.id,function(data){$fileSelect.empty();$fileSelect.append("");$.each(data,function(key,val){var $option=$("");$fileSelect.append($option)});$wrap.find("p.notes strong").text(selectedPageData.url);if($fileSelect.is(":visible")){$wrap.children().effect("highlight",{},500);$fileSelect.effect("bounce",{},50)}})}function absoluteToRelativePath(path){if(cfg.urlType==0)return path;function slashesToRelative(url){url=url.replace(/\//g,"../");url=url.replace(/[^.\/]/g,"");return url}var url;if(path===cfg.pageUrl){path="./";if(!cfg.slashUrls)path+=cfg.pageName}else if(path.indexOf(cfg.pageUrl)===0){path=path.substring(cfg.pageUrl.length);if(!cfg.slashUrls)path=cfg.pageName+path}else if(cfg.pageUrl.indexOf(path)===0){url=cfg.pageUrl.substring(path.length);if(url.indexOf("/")!=-1){url=slashesToRelative(url)}else{url="./"}path=url}else if(path.indexOf(cfg.rootParentUrl)===0){url=path.substring(cfg.rootParentUrl.length);var url2=url;url=slashesToRelative(url)+url2;path=url}else if(cfg.urlType==2){url=cfg.pageUrl.substring(ProcessWire.config.urls.root.length);url=slashesToRelative(url);path=path.substring(ProcessWire.config.urls.root.length);path=url+path}return path}function pageSelected(event,data){if(data.url&&data.url.length){selectedPageData=data;selectedPageData.url=ProcessWire.config.urls.root+data.url.substring(1);selectedPageData.url=absoluteToRelativePath(selectedPageData.url);$linkPageURL.val(selectedPageData.url).trigger("change");populateFileSelect(selectedPageData)}$(this).parents(".InputfieldInteger").children(".InputfieldHeader").trigger("click").parent().find(".PageListSelectHeader").removeClass("hidden").show()}$("#link_page_id").ProcessPageList(options).hide().on("pageSelected",pageSelected);$("#child_page_id").ProcessPageList(options2).hide().on("pageSelected",pageSelected);$fileSelect.on("change",function(){var $t=$(this);var src=$t.val();if(src.length)$linkPageURL.val(src).trigger("change")});if($anchorSelect.length){var anchorPreviousValue=$anchorSelect.val();$anchorSelect.on("change",function(){var val=$(this).val();if(val.length){$linkPageURL.val(val);anchorPreviousValue=val}else{if($linkPageURL.val()==anchorPreviousValue)$linkPageURL.val("")}$linkPageURL.trigger("change")})}function updateLinkPreview(){if(!$linkPageURL.val().length){$("#link_markup").text("");return}var $link=$("");$link.attr("href",$linkPageURL.val());var $linkTitle=$("#link_title");if($linkTitle.length&&$linkTitle.val().length){var val=$("
").text($linkTitle.val()).html();$link.attr("title",val)}if(cfg.noLinkTextEdit){}else if($linkText.length&&$linkText.val().length){$link.text($linkText.val())}var $linkRel=$("#link_rel");if($linkRel.length&&$linkRel.val().length){$link.attr("rel",$linkRel.val())}var $linkTarget=$("#link_target");if($linkTarget.length&&$linkTarget.val().length){$link.attr("target",$linkTarget.val())}var $linkClass=$("#wrap_link_class").find("input:checked");if($linkClass.length){$linkClass.each(function(){$link.addClass($(this).val())})}$("#link_markup").text($link[0].outerHTML)}function urlKeydown(){var $this=$linkPageURL;var val=ProcessWire.trim($this.val());var dotpos=val.indexOf(".");var slashespos=val.indexOf("//");var hasScheme=slashespos>-1&&slashespos-1?val.indexOf("/",slashespos+2):val.indexOf("/");var httpHost;var n;if(dotpos>-1&&val.indexOf("..")==-1&&val.indexOf("./")==-1&&(slashpos>dotpos&&!hasScheme||slashpos==-1&&dotpos>1&&val.match(/^[a-z][-a-z.0-9]+\.[a-z]{2,}($|\/)/i))){var domain=val.substring(0,slashpos>0?slashpos:val.length);hasScheme=true;if($this.attr("data-ignore")==domain){}else{$this.val("http://"+val);$this.closest(".InputfieldContent").find(".notes").text("http://"+val);$this.attr("data-ignore",domain)}}else if(dotpos>0&&val.indexOf("@")>0&&val.indexOf(":")==-1&&val.match(/^[^@]+@[-.a-z0-9]{2,}\.[a-z]{2,}$/i)){$this.val("mailto:"+val);$this.addClass("email")}else if(val.indexOf("@")==-1&&$this.hasClass("email")){$this.removeClass("email")}if(val.substring(0,1)=="#"){$this.addClass("anchor")}else if($this.hasClass("anchor")){$this.removeClass("anchor")}if(hasScheme){if(slashpos==-1)slashpos=val.length;httpHost=slashespos>-1?val.substring(slashespos+2,slashpos):val.substring(0,slashpos);$this.attr("data-httphost",httpHost)}else{$this.removeAttr("data-httphost")}function icon(){return $this.closest(".Inputfield").children(".InputfieldHeader").children("i").eq(0)}var external=false;httpHost=$this.attr("data-httphost");if(httpHost&&httpHost.length){external=true;for(n=0;n0){$("#link_target").val(extLinkTarget)}var extLinkRel=cfg.extLinkRel;if(extLinkRel.length>0){$("#link_rel").val(extLinkRel)}var extLinkClass=cfg.extLinkClass;if(extLinkClass.length>0){extLinkClass=extLinkClass.split(" ");for(n=0;n");$.each(data,function(key,val){var $option=$("");$fileSelect.append($option)});$wrap.find("p.notes strong").text(selectedPageData.url);if($fileSelect.is(":visible")){$wrap.children().effect("highlight",{},500);$fileSelect.effect("bounce",{},50)}})}function absoluteToRelativePath(path){if(cfg.urlType==0)return path;function slashesToRelative(url){url=url.replace(/\//g,"../");url=url.replace(/[^.\/]/g,"");return url}var url;if(path===cfg.pageUrl){path="./";if(!cfg.slashUrls)path+=cfg.pageName}else if(path.indexOf(cfg.pageUrl)===0){path=path.substring(cfg.pageUrl.length);if(!cfg.slashUrls)path=cfg.pageName+path}else if(cfg.pageUrl.indexOf(path)===0){url=cfg.pageUrl.substring(path.length);if(url.indexOf("/")!=-1){url=slashesToRelative(url)}else{url="./"}path=url}else if(path.indexOf(cfg.rootParentUrl)===0){url=path.substring(cfg.rootParentUrl.length);var url2=url;url=slashesToRelative(url)+url2;path=url}else if(cfg.urlType==2){url=cfg.pageUrl.substring(ProcessWire.config.urls.root.length);url=slashesToRelative(url);path=path.substring(ProcessWire.config.urls.root.length);path=url+path}return path}function pageSelected(event,data){if(data.url&&data.url.length){selectedPageData=data;selectedPageData.url=ProcessWire.config.urls.root+data.url.substring(1);selectedPageData.url=absoluteToRelativePath(selectedPageData.url);$linkPageURL.val(selectedPageData.url).trigger("change");populateFileSelect(selectedPageData)}$(this).parents(".InputfieldInteger").children(".InputfieldHeader").trigger("click").parent().find(".PageListSelectHeader").removeClass("hidden").show()}$("#link_page_id").ProcessPageList(options).hide().on("pageSelected",pageSelected);$("#child_page_id").ProcessPageList(options2).hide().on("pageSelected",pageSelected);$fileSelect.on("change",function(){var $t=$(this);var src=$t.val();if(src.length)$linkPageURL.val(src).trigger("change")});if($anchorSelect.length){var anchorPreviousValue=$anchorSelect.val();$anchorSelect.on("change",function(){var val=$(this).val();if(val.length){$linkPageURL.val(val);anchorPreviousValue=val}else{if($linkPageURL.val()==anchorPreviousValue)$linkPageURL.val("")}$linkPageURL.trigger("change")})}function updateLinkPreview(){if(!$linkPageURL.val().length){$("#link_markup").text("");return}var $link=$("");$link.attr("href",$linkPageURL.val());var $linkTitle=$("#link_title");if($linkTitle.length&&$linkTitle.val().length){var val=$("
").text($linkTitle.val()).html();$link.attr("title",val)}if(cfg.noLinkTextEdit){}else if($linkText.length&&$linkText.val().length){$link.text($linkText.val())}var $linkRel=$("#link_rel");if($linkRel.length&&$linkRel.val()&&$linkRel.val().length){$link.attr("rel",$linkRel.val())}var $linkTarget=$("#link_target");if($linkTarget.length&&$linkTarget.val().length){$link.attr("target",$linkTarget.val())}var $linkClass=$("#wrap_link_class").find("input:checked");if($linkClass.length){$linkClass.each(function(){$link.addClass($(this).val())})}$("#link_markup").text($link[0].outerHTML)}function urlKeydown(){var $this=$linkPageURL;var val=ProcessWire.trim($this.val());var dotpos=val.indexOf(".");var slashespos=val.indexOf("//");var hasScheme=slashespos>-1&&slashespos-1?val.indexOf("/",slashespos+2):val.indexOf("/");var httpHost;var n;if(dotpos>-1&&val.indexOf("..")==-1&&val.indexOf("./")==-1&&(slashpos>dotpos&&!hasScheme||slashpos==-1&&dotpos>1&&val.match(/^[a-z][-a-z.0-9]+\.[a-z]{2,}($|\/)/i))){var domain=val.substring(0,slashpos>0?slashpos:val.length);hasScheme=true;if($this.attr("data-ignore")==domain){}else{$this.val("http://"+val);$this.closest(".InputfieldContent").find(".notes").text("http://"+val);$this.attr("data-ignore",domain)}}else if(dotpos>0&&val.indexOf("@")>0&&val.indexOf(":")==-1&&val.match(/^[^@]+@[-.a-z0-9]{2,}\.[a-z]{2,}$/i)){$this.val("mailto:"+val);$this.addClass("email")}else if(val.indexOf("@")==-1&&$this.hasClass("email")){$this.removeClass("email")}if(val.substring(0,1)=="#"){$this.addClass("anchor")}else if($this.hasClass("anchor")){$this.removeClass("anchor")}if(hasScheme){if(slashpos==-1)slashpos=val.length;httpHost=slashespos>-1?val.substring(slashespos+2,slashpos):val.substring(0,slashpos);$this.attr("data-httphost",httpHost)}else{$this.removeAttr("data-httphost")}function icon(){return $this.closest(".Inputfield").children(".InputfieldHeader").children("i").eq(0)}var external=false;httpHost=$this.attr("data-httphost");if(httpHost&&httpHost.length){external=true;for(n=0;n0){$("#link_target").val(extLinkTarget)}var extLinkRel=cfg.extLinkRel;if(extLinkRel.length>0){$("#link_rel").val(extLinkRel)}var extLinkClass=cfg.extLinkClass;if(extLinkClass.length>0){if(extLinkClass.indexOf(" ")>-1){var extLinkClassAll=extLinkClass.replace(" ","_");$("#link_class_"+extLinkClassAll).prop("checked",true);extLinkClass=extLinkClass.split(" ")}for(n=0;nwire()->sanitizer->htmlClasses($value, true); - $value = implode("\n", $value); + $value = $this->sanitizeOptions($value); } else if($key === 'extLinkRel' || $key === 'extLinkClass') { $value = $this->wire()->sanitizer->htmlClasses($value); } else if($key === 'extLinkTarget') { @@ -162,6 +161,51 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { return parent::set($key, $value); } + /** + * Sanitize single option 'value', 'value=label', or 'value="label"' + * + * @param string $value + * @return string + * + */ + protected function sanitizeOption($value) { + $sanitizer = $this->wire()->sanitizer; + $value = trim($value); + $plus = strpos($value, '+') === 0 ? '+' : ''; + if($plus) $value = ltrim($value, '+'); + if(strpos($value, '=') === false) return $plus . $sanitizer->htmlClasses($value); + // value=label or value="label" + list($value, $label) = explode('=', $value, 2); + $value = trim($value); + $label = trim($label); + $value = $sanitizer->htmlClasses($value); + if(!strlen($value)) return ''; + $quote = strpos($label, '"') === 0 ? '"' : ''; + $label = str_replace('"', '', $label); + $label = $sanitizer->text($label); + $value = strlen($label) ? "$plus$value=$quote$label$quote" : "$value"; + return $value; + } + + /** + * Sanitize multiple newline separated options + * + * @param string $value + * @return string + * + */ + protected function sanitizeOptions($value) { + $value = trim($value); + if(!strlen($value)) return ''; + if(strpos($value, "\n") === false) return $this->sanitizeOption($value); + $lines = array(); + foreach(explode("\n", $value) as $line) { + $line = $this->sanitizeOption($line); + if(strlen($line)) $lines[] = $line; + } + return implode("\n", $lines); + } + /** * Primary execute * @@ -303,10 +347,14 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { $field->description = $this->_('Where this link will open.'); $this->addSelectOptions($field, 'target', $this->targetOptions); if($this->relOptions) $field->columnWidth = 50; - $fieldset->add($field); + $fieldset->add($field); + if($this->extLinkTarget) { + $options = $field->getOptions(); + if(!isset($options[$this->extLinkTarget])) $field->addOption($this->extLinkTarget); + } } - if($this->relOptions) { + if($this->relOptions || $this->extLinkRel) { /** @var InputfieldSelect $field */ $field = $modules->get('InputfieldSelect'); $field->attr('id+name', 'link_rel'); @@ -314,7 +362,11 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { $field->description = $this->_('Relationship of link to document.'); if($this->targetOptions) $field->columnWidth = 50; $this->addSelectOptions($field, 'rel', $this->relOptions); - $fieldset->add($field); + $fieldset->add($field); + if($this->extLinkRel) { + $options = $field->getOptions(); + if(!isset($options[$this->extLinkRel])) $field->addOption($this->extLinkRel); + } } $classOptions = $this->getClassOptions(); @@ -326,6 +378,10 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { $field->description = $this->_('Additional classes that can affect the look or behavior of the link.'); $field->optionColumns = 1; $this->addSelectOptions($field, 'class', $classOptions); + if($this->extLinkClass) { + $options = $field->getOptions(); + if(!isset($options[$this->extLinkClass])) $field->addOption($this->extLinkClass); + } $fieldset->add($field); } @@ -350,13 +406,44 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { protected function getClassOptions() { $sanitizer = $this->wire()->sanitizer; - $class = $this->wire()->input->get->text('class'); - if(!$class) return $this->classOptions; + $inputClass = $this->wire()->input->get->text('class'); - $classOptions = $this->classOptions ? explode("\n", trim("$this->classOptions")) : array(); - $classOptions = array_merge($classOptions, explode(' ', $class)); - $classOptions = $sanitizer->htmlClasses($classOptions, true); + if(empty($inputClass)) return $this->classOptions; + $inputClass = $sanitizer->htmlClasses($inputClass, true); + + if(!count($inputClass)) return $this->classOptions; + + sort($inputClass); + + $inputClasses = $inputClass; + $inputClass = implode(' ', $inputClass); + $classOptions = array(); + + if($this->classOptions) { + foreach(explode("\n", $this->classOptions) as $line) { + $value = ltrim(trim($line), '+'); + if(strpos($value, '=')) { + list($value, /*$label*/) = explode('=', $value, 2); + } + if(strpos($value, ' ')) { + $value = $sanitizer->htmlClasses($value, true); + sort($value); + $value = implode(' ', $value); + } + $classOptions[$value] = $line; + } + } + + if(isset($classOptions[$inputClass])) { + // class already appears as-is, i.e. "uk-text-muted" or "uk-text-muted uk-text-small", etc. + } else { + // add new classes from input + foreach($inputClasses as $class) { + if(!isset($classOptions[$class])) $classOptions[$class] = $class; + } + } + return count($classOptions) ? implode("\n", $classOptions) : ''; } @@ -616,4 +703,3 @@ class ProcessPageEditLink extends Process implements ConfigurableModule { $inputfields->add($f); } } -