mirror of
https://github.com/typemill/typemill.git
synced 2025-10-18 08:07:31 +02:00
Version 1.2.16
This commit is contained in:
@@ -1,47 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\Analytics;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Analytics extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* get Twig Instance and add the cookieconsent template-folder to the path */
|
||||
$twig = $this->getTwig();
|
||||
$loader = $twig->getLoader();
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
|
||||
$analyticSettings = $this->settings['settings']['plugins']['analytics'];
|
||||
|
||||
if(isset($analyticSettings['tool']))
|
||||
{
|
||||
/* fetch the template, render it with twig and add javascript with settings */
|
||||
if($analyticSettings['tool'] == 'piwik')
|
||||
{
|
||||
$this->addInlineJS($twig->fetch('/piwikanalytics.twig', $this->settings));
|
||||
}
|
||||
elseif($analyticSettings['tool'] == 'google')
|
||||
{
|
||||
$this->addJS('https://www.googletagmanager.com/gtag/js?id=' . $analyticSettings['google_id']);
|
||||
$this->addInlineJS($twig->fetch('/googleanalytics.twig', $analyticSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
namespace Plugins\Analytics;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Analytics extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* get Twig Instance and add the cookieconsent template-folder to the path */
|
||||
$twig = $this->getTwig();
|
||||
$loader = $twig->getLoader();
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
|
||||
$analyticSettings = $this->settings['settings']['plugins']['analytics'];
|
||||
|
||||
if(isset($analyticSettings['tool']))
|
||||
{
|
||||
/* fetch the template, render it with twig and add javascript with settings */
|
||||
if($analyticSettings['tool'] == 'piwik')
|
||||
{
|
||||
$this->addInlineJS($twig->fetch('/piwikanalytics.twig', $this->settings));
|
||||
}
|
||||
elseif($analyticSettings['tool'] == 'google')
|
||||
{
|
||||
$this->addJS('https://www.googletagmanager.com/gtag/js?id=' . $analyticSettings['google_id']);
|
||||
$this->addInlineJS($twig->fetch('/googleanalytics.twig', $analyticSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,38 +1,38 @@
|
||||
name: Analytics
|
||||
version: 1.0.0
|
||||
description: Integrate Piwik or Google Analytics Script
|
||||
author: Sebastian Schürmanns
|
||||
homepage: http://typemill.net
|
||||
licence: MIT
|
||||
|
||||
settings:
|
||||
tool: none
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
tool:
|
||||
type: radio
|
||||
label: Choose Your Tool
|
||||
options:
|
||||
none: None
|
||||
piwik: Piwik
|
||||
google: Google Analytics
|
||||
|
||||
piwik_url:
|
||||
type: text
|
||||
label: Piwik URL
|
||||
help: Add the URL to your piwik installation without protocol like this: my-site.com.
|
||||
placeholder: 'url like my-piwik-installation.com'
|
||||
|
||||
piwik_id:
|
||||
type: number
|
||||
label: Piwik Site-ID
|
||||
help: You can find the id in Piwik under configuration and tracking code.
|
||||
placeholder: 'simple number like 8'
|
||||
|
||||
google_id:
|
||||
type: text
|
||||
label: Google Tracking ID
|
||||
help: You can find the tracking id in google under property. It starts with UA-
|
||||
name: Analytics
|
||||
version: 1.0.0
|
||||
description: Integrate Piwik or Google Analytics Script
|
||||
author: Sebastian Schürmanns
|
||||
homepage: http://typemill.net
|
||||
licence: MIT
|
||||
|
||||
settings:
|
||||
tool: none
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
tool:
|
||||
type: radio
|
||||
label: Choose Your Tool
|
||||
options:
|
||||
none: None
|
||||
piwik: Piwik
|
||||
google: Google Analytics
|
||||
|
||||
piwik_url:
|
||||
type: text
|
||||
label: Piwik URL
|
||||
help: Add the URL to your piwik installation without protocol like this: my-site.com.
|
||||
placeholder: 'url like my-piwik-installation.com'
|
||||
|
||||
piwik_id:
|
||||
type: number
|
||||
label: Piwik Site-ID
|
||||
help: You can find the id in Piwik under configuration and tracking code.
|
||||
placeholder: 'simple number like 8'
|
||||
|
||||
google_id:
|
||||
type: text
|
||||
label: Google Tracking ID
|
||||
help: You can find the tracking id in google under property. It starts with UA-
|
||||
placeholder: 'UA-12345-6'
|
@@ -1,5 +1,5 @@
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '{{ google_id }}');
|
@@ -1,11 +1,11 @@
|
||||
var _paq = _paq || [];
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
|
||||
(function(){
|
||||
var u="//{{ settings.plugins.analytics.piwik_url }}/";
|
||||
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||
_paq.push(['setSiteId', '{{ settings.plugins.analytics.piwik_id }}']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||
var _paq = _paq || [];
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
|
||||
(function(){
|
||||
var u="//{{ settings.plugins.analytics.piwik_url }}/";
|
||||
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||
_paq.push(['setSiteId', '{{ settings.plugins.analytics.piwik_id }}']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
@@ -1,38 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\CookieConsent;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class CookieConsent extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addCSS('/cookieconsent/public/cookieconsent.min.css');
|
||||
$this->addJS('/cookieconsent/public/cookieconsent.min.js');
|
||||
|
||||
/* get Twig Instance and add the cookieconsent template-folder to the path */
|
||||
$twig = $this->getTwig();
|
||||
$loader = $twig->getLoader();
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
|
||||
/* fetch the template, render it with twig and add it as inline-javascript */
|
||||
$this->addInlineJS($twig->fetch('/cookieconsent.twig', $this->settings));
|
||||
}
|
||||
<?php
|
||||
|
||||
namespace Plugins\CookieConsent;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class CookieConsent extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addCSS('/cookieconsent/public/cookieconsent.min.css');
|
||||
$this->addJS('/cookieconsent/public/cookieconsent.min.js');
|
||||
|
||||
/* get Twig Instance and add the cookieconsent template-folder to the path */
|
||||
$twig = $this->getTwig();
|
||||
$loader = $twig->getLoader();
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
|
||||
/* fetch the template, render it with twig and add it as inline-javascript */
|
||||
$this->addInlineJS($twig->fetch('/cookieconsent.twig', $this->settings));
|
||||
}
|
||||
}
|
@@ -1,88 +1,88 @@
|
||||
name: Cookie Consent
|
||||
version: 1.0.1
|
||||
description: Enables a cookie consent for websites
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://cookieconsent.insites.com/
|
||||
licence: MIT
|
||||
|
||||
settings:
|
||||
popup_background: '#70c1b3'
|
||||
popup_text: '#ffffff'
|
||||
button_background: '#66b0a3'
|
||||
button_text: '#ffffff'
|
||||
theme: 'edgeless'
|
||||
position: 'bottom'
|
||||
message: 'This website uses cookies to ensure you get the best experience on our website.'
|
||||
link: 'Learn More'
|
||||
href: 'https://cookiesandyou.com/'
|
||||
dismiss: 'Got It'
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
theme:
|
||||
type: select
|
||||
label: Theme
|
||||
placeholder: 'Add name of theme'
|
||||
required: true
|
||||
options:
|
||||
edgeless: Edgeless
|
||||
block: Block
|
||||
classic: Classic
|
||||
|
||||
position:
|
||||
type: select
|
||||
label: Position of Cookie Banner
|
||||
options:
|
||||
bottom: Bottom
|
||||
top: Top
|
||||
bottom-left: Bottom left
|
||||
bottom-right: Bottom right
|
||||
|
||||
message:
|
||||
type: textarea
|
||||
label: Message
|
||||
placeholder: 'Message for cookie-popup'
|
||||
required: true
|
||||
|
||||
href:
|
||||
type: url
|
||||
label: Link to more informations
|
||||
placeholder: 'https://cookiesandyou.com/'
|
||||
required: true
|
||||
|
||||
link:
|
||||
type: text
|
||||
label: Label for Link
|
||||
placeholder: 'Link-Lable like More infos'
|
||||
required: true
|
||||
|
||||
dismiss:
|
||||
type: text
|
||||
label: Label for Button
|
||||
placeholder: 'Got it'
|
||||
required: true
|
||||
|
||||
popup_background:
|
||||
type: color
|
||||
label: Background Color of Popup
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
popup_text:
|
||||
type: color
|
||||
label: Text Color of Popup
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
button_background:
|
||||
type: color
|
||||
label: Background Color of Button
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
button_text:
|
||||
type: color
|
||||
label: Text Color of Button
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
name: Cookie Consent
|
||||
version: 1.0.1
|
||||
description: Enables a cookie consent for websites
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://cookieconsent.insites.com/
|
||||
licence: MIT
|
||||
|
||||
settings:
|
||||
popup_background: '#70c1b3'
|
||||
popup_text: '#ffffff'
|
||||
button_background: '#66b0a3'
|
||||
button_text: '#ffffff'
|
||||
theme: 'edgeless'
|
||||
position: 'bottom'
|
||||
message: 'This website uses cookies to ensure you get the best experience on our website.'
|
||||
link: 'Learn More'
|
||||
href: 'https://cookiesandyou.com/'
|
||||
dismiss: 'Got It'
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
theme:
|
||||
type: select
|
||||
label: Theme
|
||||
placeholder: 'Add name of theme'
|
||||
required: true
|
||||
options:
|
||||
edgeless: Edgeless
|
||||
block: Block
|
||||
classic: Classic
|
||||
|
||||
position:
|
||||
type: select
|
||||
label: Position of Cookie Banner
|
||||
options:
|
||||
bottom: Bottom
|
||||
top: Top
|
||||
bottom-left: Bottom left
|
||||
bottom-right: Bottom right
|
||||
|
||||
message:
|
||||
type: textarea
|
||||
label: Message
|
||||
placeholder: 'Message for cookie-popup'
|
||||
required: true
|
||||
|
||||
href:
|
||||
type: url
|
||||
label: Link to more informations
|
||||
placeholder: 'https://cookiesandyou.com/'
|
||||
required: true
|
||||
|
||||
link:
|
||||
type: text
|
||||
label: Label for Link
|
||||
placeholder: 'Link-Lable like More infos'
|
||||
required: true
|
||||
|
||||
dismiss:
|
||||
type: text
|
||||
label: Label for Button
|
||||
placeholder: 'Got it'
|
||||
required: true
|
||||
|
||||
popup_background:
|
||||
type: color
|
||||
label: Background Color of Popup
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
popup_text:
|
||||
type: color
|
||||
label: Text Color of Popup
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
button_background:
|
||||
type: color
|
||||
label: Background Color of Button
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
||||
|
||||
button_text:
|
||||
type: color
|
||||
label: Text Color of Button
|
||||
placeholder: 'Add hex color value like #ffffff'
|
||||
required: true
|
@@ -1,6 +1,6 @@
|
||||
.cc-window{opacity:1;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{transition:transform 1s ease}.cc-animate.cc-revoke.cc-top{transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-bottom,.cc-animate.cc-revoke.cc-active.cc-top,.cc-revoke:hover{transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;transition:max-height 1s}
|
||||
.cc-link,.cc-revoke:hover{text-decoration:underline}.cc-revoke,.cc-window{position:fixed;overflow:hidden;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1}
|
||||
.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{display:block;-ms-flex:1 1 auto;flex:1 1 auto;max-width:100%;margin-right:1em}.cc-compliance{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-floating .cc-compliance>.cc-btn{-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em}
|
||||
@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-floating,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-ms-flex:1 1 auto;flex:1 1 auto}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-ms-flex-align:unset;align-items:unset}.cc-window.cc-banner .cc-message{margin-right:0}}
|
||||
.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block}
|
||||
.cc-window{opacity:1;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{transition:transform 1s ease}.cc-animate.cc-revoke.cc-top{transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-bottom,.cc-animate.cc-revoke.cc-active.cc-top,.cc-revoke:hover{transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;transition:max-height 1s}
|
||||
.cc-link,.cc-revoke:hover{text-decoration:underline}.cc-revoke,.cc-window{position:fixed;overflow:hidden;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1}
|
||||
.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{display:block;-ms-flex:1 1 auto;flex:1 1 auto;max-width:100%;margin-right:1em}.cc-compliance{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-floating .cc-compliance>.cc-btn{-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em}
|
||||
@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-floating,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-ms-flex:1 1 auto;flex:1 1 auto}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-ms-flex-align:unset;align-items:unset}.cc-window.cc-banner .cc-message{margin-right:0}}
|
||||
.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block}
|
||||
.cc-theme-edgeless.cc-window{padding:0}.cc-floating.cc-theme-edgeless .cc-message{margin:2em 2em 1.5em}.cc-banner.cc-theme-edgeless .cc-btn{margin:0;padding:.8em 1.8em;height:100%}.cc-banner.cc-theme-edgeless .cc-message{margin-left:1em}.cc-floating.cc-theme-edgeless .cc-btn+.cc-btn{margin-left:0}
|
@@ -1,22 +1,22 @@
|
||||
window.addEventListener("load", function(){
|
||||
window.cookieconsent.initialise({
|
||||
"palette": {
|
||||
"popup": {
|
||||
"background": "{{ settings.plugins.cookieconsent.popup_background }}",
|
||||
"text": "{{ settings.plugins.cookieconsent.popup_text }}"
|
||||
},
|
||||
"button": {
|
||||
"background": "{{ settings.plugins.cookieconsent.button_background }}",
|
||||
"text": "{{ settings.plugins.cookieconsent.button_text }}"
|
||||
}
|
||||
},
|
||||
"theme": "{{ settings.plugins.cookieconsent.theme }}",
|
||||
"position": "{{ settings.plugins.cookieconsent.position }}",
|
||||
"content": {
|
||||
"message": "{{ settings.plugins.cookieconsent.message }}",
|
||||
"dismiss": "{{ settings.plugins.cookieconsent.dismiss }}",
|
||||
"link": "{{ settings.plugins.cookieconsent.link }}",
|
||||
"href": "{{ settings.plugins.cookieconsent.href }}"
|
||||
}
|
||||
})
|
||||
});
|
||||
window.addEventListener("load", function(){
|
||||
window.cookieconsent.initialise({
|
||||
"palette": {
|
||||
"popup": {
|
||||
"background": "{{ settings.plugins.cookieconsent.popup_background }}",
|
||||
"text": "{{ settings.plugins.cookieconsent.popup_text }}"
|
||||
},
|
||||
"button": {
|
||||
"background": "{{ settings.plugins.cookieconsent.button_background }}",
|
||||
"text": "{{ settings.plugins.cookieconsent.button_text }}"
|
||||
}
|
||||
},
|
||||
"theme": "{{ settings.plugins.cookieconsent.theme }}",
|
||||
"position": "{{ settings.plugins.cookieconsent.position }}",
|
||||
"content": {
|
||||
"message": "{{ settings.plugins.cookieconsent.message }}",
|
||||
"dismiss": "{{ settings.plugins.cookieconsent.dismiss }}",
|
||||
"link": "{{ settings.plugins.cookieconsent.link }}",
|
||||
"href": "{{ settings.plugins.cookieconsent.href }}"
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@@ -1,28 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\Highlight;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Highlight extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addCSS('/highlight/public/default.css');
|
||||
$this->addJS('/highlight/public/highlight.pack.js');
|
||||
|
||||
/* initialize the script */
|
||||
$this->addInlineJS('hljs.initHighlightingOnLoad();');
|
||||
}
|
||||
<?php
|
||||
|
||||
namespace Plugins\Highlight;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Highlight extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addCSS('/highlight/public/default.css');
|
||||
$this->addJS('/highlight/public/highlight.pack.js');
|
||||
|
||||
/* initialize the script */
|
||||
$this->addInlineJS('hljs.initHighlightingOnLoad();');
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
name: Highlight
|
||||
version: 1.0.0
|
||||
description: Adds the famous javascript syntax highlighter.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://highlightjs.org/
|
||||
name: Highlight
|
||||
version: 1.0.0
|
||||
description: Adds the famous javascript syntax highlighter.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://highlightjs.org/
|
||||
licence: BSD
|
@@ -1,24 +1,24 @@
|
||||
Copyright (c) 2006, Ivan Sagalaev
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of highlight.js nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Copyright (c) 2006, Ivan Sagalaev
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of highlight.js nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
@@ -1,99 +1,99 @@
|
||||
/*
|
||||
|
||||
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
|
||||
/* Base color: saturation 0; */
|
||||
|
||||
.hljs,
|
||||
.hljs-subst {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.hljs-comment {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-attribute,
|
||||
.hljs-selector-tag,
|
||||
.hljs-meta-keyword,
|
||||
.hljs-doctag,
|
||||
.hljs-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* User color: hue: 0 */
|
||||
|
||||
.hljs-type,
|
||||
.hljs-string,
|
||||
.hljs-number,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-quote,
|
||||
.hljs-template-tag,
|
||||
.hljs-deletion {
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section {
|
||||
color: #880000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-symbol,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-link,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #BC6060;
|
||||
}
|
||||
|
||||
|
||||
/* Language color: hue: 90; */
|
||||
|
||||
.hljs-literal {
|
||||
color: #78A960;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-bullet,
|
||||
.hljs-code,
|
||||
.hljs-addition {
|
||||
color: #397300;
|
||||
}
|
||||
|
||||
|
||||
/* Meta color: hue: 200 */
|
||||
|
||||
.hljs-meta {
|
||||
color: #1f7199;
|
||||
}
|
||||
|
||||
.hljs-meta-string {
|
||||
color: #4d99bf;
|
||||
}
|
||||
|
||||
|
||||
/* Misc effects */
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
/*
|
||||
|
||||
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
|
||||
/* Base color: saturation 0; */
|
||||
|
||||
.hljs,
|
||||
.hljs-subst {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.hljs-comment {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-attribute,
|
||||
.hljs-selector-tag,
|
||||
.hljs-meta-keyword,
|
||||
.hljs-doctag,
|
||||
.hljs-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* User color: hue: 0 */
|
||||
|
||||
.hljs-type,
|
||||
.hljs-string,
|
||||
.hljs-number,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-quote,
|
||||
.hljs-template-tag,
|
||||
.hljs-deletion {
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section {
|
||||
color: #880000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-symbol,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-link,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #BC6060;
|
||||
}
|
||||
|
||||
|
||||
/* Language color: hue: 90; */
|
||||
|
||||
.hljs-literal {
|
||||
color: #78A960;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-bullet,
|
||||
.hljs-code,
|
||||
.hljs-addition {
|
||||
color: #397300;
|
||||
}
|
||||
|
||||
|
||||
/* Meta color: hue: 200 */
|
||||
|
||||
.hljs-meta {
|
||||
color: #1f7199;
|
||||
}
|
||||
|
||||
.hljs-meta-string {
|
||||
color: #4d99bf;
|
||||
}
|
||||
|
||||
|
||||
/* Misc effects */
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
204
plugins/hyer/getads.php
Normal file
204
plugins/hyer/getads.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\hyer;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class getads extends Plugin
|
||||
{
|
||||
|
||||
public static function getSubscribedEvents(){}
|
||||
|
||||
# get only pro ads for product
|
||||
public function pro()
|
||||
{
|
||||
|
||||
# get referrer url
|
||||
if(!isset($_SERVER['HTTP_REFERER']))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Referrer is missing']);
|
||||
}
|
||||
|
||||
# get the url parameter
|
||||
$input = $this->getParams();
|
||||
|
||||
# create secret
|
||||
$secret = time();
|
||||
$secret = substr($secret,0,-1);
|
||||
$oldsecret = $secret -1;
|
||||
$secret = md5($secret . $this->getSalt());
|
||||
$oldsecret = md5($oldsecret . $this->getSalt());
|
||||
|
||||
if(!isset($input['access']) OR ($input['access'] != $secret AND $input['access'] != $oldsecret))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Secret is incorrect']);
|
||||
}
|
||||
|
||||
# get the last segment of url
|
||||
$referrer = $_SERVER['HTTP_REFERER'];
|
||||
$segment = basename($referrer);
|
||||
|
||||
# get the settings
|
||||
$settings = \Typemill\Settings::loadSettings();
|
||||
|
||||
# get url-map to find the correct cms for requesting page
|
||||
$urlmap = json_decode($settings['settings']['plugins']['hyer']['urlmap'],true);
|
||||
|
||||
# map the request with the map in settings
|
||||
if(!isset($urlmap[$segment]))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'We could not map that url']);
|
||||
}
|
||||
|
||||
# make call
|
||||
# $hyerApi = 'http://localhost/typemillService/public/publicapi/proads';
|
||||
$hyerApi = 'https://service.cmsstash.de/publicapi/proads';
|
||||
$hyerRequest = ['product' => $urlmap[$segment]];
|
||||
|
||||
$result = $this->makeApiCall($hyerRequest, $hyerApi);
|
||||
|
||||
return $this->returnJson($result);
|
||||
}
|
||||
|
||||
# get 10 latest pro ads
|
||||
public function latest()
|
||||
{
|
||||
# get the url parameter
|
||||
$input = $this->getParams();
|
||||
|
||||
# create secret
|
||||
$secret = time();
|
||||
$secret = substr($secret,0,-1);
|
||||
$oldsecret = $secret -1;
|
||||
$secret = md5($secret . $this->getSalt());
|
||||
$oldsecret = md5($oldsecret . $this->getSalt());
|
||||
|
||||
if(!isset($input['access']) OR ($input['access'] != $secret AND $input['access'] != $oldsecret))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Secret is incorrect']);
|
||||
}
|
||||
|
||||
# $hyerApi = 'http://localhost/typemillService/public/publicapi/latestproads';
|
||||
$hyerApi = 'https://service.cmsstash.de/publicapi/latestproads';
|
||||
$hyerRequest = [];
|
||||
|
||||
$result = $this->makeApiCall($hyerRequest, $hyerApi);
|
||||
|
||||
return $this->returnJson($result);
|
||||
}
|
||||
|
||||
# search for ads from directory
|
||||
public function search()
|
||||
{
|
||||
session_start();
|
||||
|
||||
# get the url parameter
|
||||
$input = $this->getParams();
|
||||
|
||||
# validate input here
|
||||
|
||||
# read session data for simple csrf check
|
||||
$token = isset($_SESSION['hyer']) ? $_SESSION['hyer'] : false;
|
||||
$time = isset($_SESSION['hyer-expire']) ? $_SESSION['hyer-expire'] : false;
|
||||
|
||||
# perform simple security or csrf check
|
||||
if(!isset($input['token']) OR !$token OR !$time OR ($input['token'] != $token ) OR (time() >= $time))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Die Sitzung ist abgelaufen, bitte laden Sie die Seite neu.']);
|
||||
}
|
||||
|
||||
# $hyerApi = 'http://localhost/typemillService/public/publicapi/searchads';
|
||||
$hyerApi = 'https://service.cmsstash.de/publicapi/searchads';
|
||||
$hyerRequest = [];
|
||||
|
||||
if(isset($input['product']) && $input['product'] != '')
|
||||
{
|
||||
if(!$this->validateLengthBetween($input['product'], 2, 50) OR !$this->validateHtml($input['product']))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Product is invalid']);
|
||||
}
|
||||
$hyerRequest['product'] = $input['product'];
|
||||
}
|
||||
if(isset($input['region']) && $input['region'] != '')
|
||||
{
|
||||
if(!$this->validateLengthBetween($input['region'], 2, 50) OR !$this->validateHtml($input['region']))
|
||||
{
|
||||
return $this->returnJsonError(['message' => 'Product is invalid']);
|
||||
}
|
||||
$hyerRequest['region'] = $input['region'];
|
||||
}
|
||||
|
||||
$result = $this->makeApiCall($hyerRequest, $hyerApi);
|
||||
|
||||
if($result)
|
||||
{
|
||||
return $this->returnJson($result);
|
||||
}
|
||||
return $this->returnJsonError(['message' => 'Kein Ergebnis']);
|
||||
}
|
||||
|
||||
private function makeApiCall($hyerRequest, $hyerApi)
|
||||
{
|
||||
|
||||
# get the settings
|
||||
$settings = \Typemill\Settings::loadSettings();
|
||||
|
||||
# get api key from settings
|
||||
$apikey = $settings['settings']['plugins']['hyer']['apikey'];
|
||||
$siteid = $settings['settings']['plugins']['hyer']['siteid'];
|
||||
|
||||
|
||||
# use key 'http' even if you send the request to https://...
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Authorization: Basic " . base64_encode($siteid . ":". $apikey),
|
||||
'method' => 'GET',
|
||||
'content' => http_build_query($hyerRequest),
|
||||
'timeout' => 5
|
||||
)
|
||||
);
|
||||
|
||||
ini_set('allow_url_fopen', '1');
|
||||
|
||||
$context = stream_context_create($options);
|
||||
$result = file_get_contents($hyerApi, false, $context);
|
||||
$result = json_decode($result);
|
||||
|
||||
ini_set('allow_url_fopen', '0');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function validateHtml($value)
|
||||
{
|
||||
if($value == strip_tags($value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function validateLengthBetween($value, $min, $max)
|
||||
{
|
||||
$length = $this->stringLength($value);
|
||||
|
||||
return ($length !== false) && $length >= $min && $length <= $max;
|
||||
}
|
||||
|
||||
private function stringLength($value)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
} elseif (function_exists('mb_strlen')) {
|
||||
return mb_strlen($value);
|
||||
}
|
||||
|
||||
return strlen($value);
|
||||
}
|
||||
|
||||
private function getSalt()
|
||||
{
|
||||
return "asPx9Derf2";
|
||||
}
|
||||
|
||||
}
|
221
plugins/hyer/hyer.php
Normal file
221
plugins/hyer/hyer.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\hyer;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Hyer extends Plugin
|
||||
{
|
||||
protected $item;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onsettingsLoaded',
|
||||
'onItemLoaded' => 'onItemLoaded',
|
||||
'onContentArrayLoaded' => 'onContentArrayLoaded',
|
||||
);
|
||||
}
|
||||
|
||||
public static function addNewRoutes()
|
||||
{
|
||||
# the route for the api calls
|
||||
return array(
|
||||
array(
|
||||
'httpMethod' => 'get',
|
||||
'route' => '/latestadsfe30s8edw4wdkp',
|
||||
'class' => 'Plugins\hyer\getads:latest'
|
||||
),
|
||||
array(
|
||||
'httpMethod' => 'get',
|
||||
'route' => '/proadsfe30s8edw4wdkp',
|
||||
'class' => 'Plugins\hyer\getads:pro'
|
||||
),
|
||||
array(
|
||||
'httpMethod' => 'get',
|
||||
'route' => '/searchadsfe30s8edw4wdkp',
|
||||
'class' => 'Plugins\hyer\getads:search'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onItemLoaded($item)
|
||||
{
|
||||
$this->item = $item->getData();
|
||||
}
|
||||
|
||||
public function onContentArrayLoaded($contentArray)
|
||||
{
|
||||
# get content array
|
||||
$content = $contentArray->getData();
|
||||
$settings = $this->getPluginSettings('hyer');
|
||||
$path = $this->getPath();
|
||||
$segment = basename($path); # get the last url segment
|
||||
$urlmap = json_decode($settings['urlmap'],true); # to find the correct page to include app
|
||||
$directory = trim($settings['directory'],"/"); # the path for the directory
|
||||
$salt = "asPx9Derf2";
|
||||
|
||||
# if we are on the directory page
|
||||
|
||||
if(trim($path,"/") == trim($settings['directory'],"/"))
|
||||
{
|
||||
# activate axios and vue in frontend
|
||||
$this->activateAxios();
|
||||
$this->activateVue();
|
||||
$this->activateTachyons();
|
||||
|
||||
# add the css and vue application
|
||||
$this->addCSS('/hyer/public/hyer.css');
|
||||
$this->addJS('/hyer/public/hyer.js');
|
||||
|
||||
$twig = $this->getTwig(); // get the twig-object
|
||||
$loader = $twig->getLoader(); // get the twig-template-loader
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
$svg = $twig->fetch('/hyer.twig');
|
||||
|
||||
# simple security for first request
|
||||
$secret = time();
|
||||
$secret = substr($secret,0,-1);
|
||||
$secret = md5($secret . $salt);
|
||||
|
||||
# simple csrf protection with a session for long following requests
|
||||
session_start();
|
||||
$length = 32;
|
||||
$token = substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
|
||||
$_SESSION['hyer'] = $token;
|
||||
$_SESSION['hyer-expire'] = time() + 1300; # 60 seconds * 30 minutes
|
||||
|
||||
# use this to secure the api long term
|
||||
# $token = time();
|
||||
# $token = substr($token,0,-4);
|
||||
# $token = md5($token . $salt);
|
||||
|
||||
$products = '';
|
||||
|
||||
foreach($urlmap as $product)
|
||||
{
|
||||
$products .= $product . ',';
|
||||
}
|
||||
$products = trim($products, ",");
|
||||
|
||||
# create div for vue app
|
||||
$textHyer = '<div data-access="' . $secret . '" data-token="' . $token . '" data-products="' . $products . '" id="hyerapp"><directory></directory></div>';
|
||||
|
||||
# create content type
|
||||
$textHyer = Array
|
||||
(
|
||||
'rawHtml' => $svg . $textHyer,
|
||||
'allowRawHtmlInSafeMode' => true,
|
||||
'autobreak' => 1
|
||||
);
|
||||
|
||||
$content[] = $textHyer;
|
||||
|
||||
}
|
||||
# map the url with the map in settings
|
||||
elseif(isset($urlmap[$segment]))
|
||||
{
|
||||
# activate axios and vue in frontend
|
||||
$this->activateAxios();
|
||||
$this->activateVue();
|
||||
$this->activateTachyons();
|
||||
|
||||
# add the css and vue application
|
||||
$this->addCSS('/hyer/public/hyer.css');
|
||||
$this->addJS('/hyer/public/hyer.js');
|
||||
|
||||
$twig = $this->getTwig(); // get the twig-object
|
||||
$loader = $twig->getLoader(); // get the twig-template-loader
|
||||
$loader->addPath(__DIR__ . '/templates');
|
||||
$svg = $twig->fetch('/hyer.twig');
|
||||
|
||||
# use this to secure the api a bit
|
||||
$secret = time();
|
||||
$secret = substr($secret,0,-1);
|
||||
$secret = md5($secret . $salt);
|
||||
|
||||
# create div for vue app
|
||||
$textHyer = '<div data-access="' . $secret . '" id="hyerapp"><premiumads></premiumads></div>';
|
||||
$textHeadline = (isset($settings['headline']) && !empty($settings['headline'])) ? $settings['headline'] : false;
|
||||
$textTeaser = (isset($settings['teaser']) && !empty($settings['teaser'])) ? $settings['teaser'] : false;
|
||||
|
||||
# create content type
|
||||
$textHyer = Array
|
||||
(
|
||||
'rawHtml' => $svg . $textHyer,
|
||||
'allowRawHtmlInSafeMode' => true,
|
||||
'autobreak' => 1
|
||||
);
|
||||
|
||||
if($textHeadline)
|
||||
{
|
||||
$textHeadline = array(
|
||||
'name' => 'h2',
|
||||
'text' => $textHeadline,
|
||||
'handler' => 'line',
|
||||
'attributes' => Array
|
||||
(
|
||||
'id' => $textHeadline
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if($textTeaser)
|
||||
{
|
||||
$textTeaser = array(
|
||||
'name' => 'p',
|
||||
'handler' => Array
|
||||
(
|
||||
'function' => 'lineElements',
|
||||
'argument' => $textTeaser,
|
||||
'destination' => 'elements'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$length = count($content);
|
||||
$thisElement = 0;
|
||||
$pos = false;
|
||||
$i = 0;
|
||||
$position = isset($settings['position']) ? $settings['position'] : 3;
|
||||
|
||||
while($i < $length)
|
||||
{
|
||||
if($content[$i]['name'] == 'h2')
|
||||
{
|
||||
$thisElement = $thisElement + 1;
|
||||
}
|
||||
|
||||
# place hyer app before the 3rd headline h2-level
|
||||
if($thisElement == $position)
|
||||
{
|
||||
$pos = $i;
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if($pos)
|
||||
{
|
||||
$start = array_slice($content, 0, $pos);
|
||||
$end = array_slice($content, $pos);
|
||||
if($textHeadline){ $start[] = $textHeadline; }
|
||||
if($textTeaser){ $start[] = $textTeaser; }
|
||||
$content = array_merge( $start, array($textHyer), $end );
|
||||
}
|
||||
else
|
||||
{
|
||||
if($textHeadline){ $content[] = $textHeadline; }
|
||||
if($textTeaser){ $content[] = $textTeaser; }
|
||||
$content[] = $textHyer;
|
||||
}
|
||||
}
|
||||
|
||||
$contentArray->setData($content);
|
||||
}
|
||||
}
|
44
plugins/hyer/hyer.yaml
Normal file
44
plugins/hyer/hyer.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
name: HYER SPACE
|
||||
version: 1.0.0
|
||||
description: Integrate HYER Text-Adds into typemill.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://typemill.net
|
||||
licence: MIT
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
apikey:
|
||||
type: text
|
||||
label: API KEY
|
||||
placeholder:
|
||||
required: true
|
||||
|
||||
siteid:
|
||||
type: text
|
||||
label: Site ID
|
||||
placeholder:
|
||||
required: true
|
||||
|
||||
urlmap:
|
||||
type: textarea
|
||||
label: URL Map
|
||||
placeholder: '180 characters'
|
||||
required: true
|
||||
|
||||
directory:
|
||||
type: text
|
||||
label: Path to directory
|
||||
placeholder: 'path/to/directory'
|
||||
|
||||
headline:
|
||||
type: text
|
||||
label: Headline before ad-block on review page
|
||||
|
||||
teaser:
|
||||
type: textarea
|
||||
label: Teaser before ad-block on review page
|
||||
|
||||
position:
|
||||
type: number
|
||||
label: Position for the ad-block (before xyz h2 headlines)
|
64
plugins/hyer/public/hyer.css
Normal file
64
plugins/hyer/public/hyer.css
Normal file
@@ -0,0 +1,64 @@
|
||||
/**********************
|
||||
** ICONS **
|
||||
**********************/
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
stroke-width: 0;
|
||||
stroke: currentColor;
|
||||
fill: currentColor;
|
||||
}
|
||||
.icon-users {
|
||||
width: 1.125em;
|
||||
}
|
||||
.bg-customized{
|
||||
background: #f9f8f6;
|
||||
}
|
||||
.bg-customized-2{
|
||||
background: #ff4136;
|
||||
}
|
||||
.b--customized-2{
|
||||
border-color: #ff4136;
|
||||
}
|
||||
.customized-2{
|
||||
color: #ff4136;
|
||||
}
|
||||
.custombutton{
|
||||
line-height: 1.55rem;
|
||||
}
|
||||
.link, .link:active, .link:focus, .link:hover, .link:link, .link:visited {
|
||||
transition: color .15s ease-in;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
.link-white, .link-white.active, .link-white:focus, .link-white:hover, .link-white:link, .link-white:visited{
|
||||
color: #fff;
|
||||
}
|
||||
select{
|
||||
background-color: #f9f8f6;
|
||||
}
|
||||
select{
|
||||
/* reset */
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
/* style */
|
||||
background-image:
|
||||
linear-gradient(45deg, transparent 50%, #444 50%),
|
||||
linear-gradient(135deg, #444 50%, transparent 50%),
|
||||
linear-gradient(to right, transparent, transparent);
|
||||
background-position:
|
||||
calc(100% - 20px) calc(1em + 6px),
|
||||
calc(100% - 15px) calc(1em + 6px),
|
||||
100% 0;
|
||||
background-size:
|
||||
5px 5px,
|
||||
5px 5px,
|
||||
2.8em 2.8em;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
.shadow-hover:hover{
|
||||
box-shadow: 0px 0px 2px 0px rgba(158,158,158,1);
|
||||
}
|
290
plugins/hyer/public/hyer.js
Normal file
290
plugins/hyer/public/hyer.js
Normal file
@@ -0,0 +1,290 @@
|
||||
const myaxios = axios.create({
|
||||
baseURL: document.getElementsByTagName("base")[0].href
|
||||
});
|
||||
|
||||
Vue.component('directory', {
|
||||
data: function () {
|
||||
return {
|
||||
ads: [],
|
||||
products: [],
|
||||
selectedProduct: "",
|
||||
selectedRegion: "",
|
||||
token: "",
|
||||
message: false,
|
||||
messageType: '',
|
||||
}
|
||||
},
|
||||
template: '<div>' +
|
||||
'<div>' +
|
||||
'<form action="#">' +
|
||||
'<fieldset class="bn ma0 pa0">' +
|
||||
'<div class="flex-ns items-end justify-around">' +
|
||||
'<div class="w-100 mr3-ns">' +
|
||||
'<label for="country" class="f6 b db mb2 mt4 tl">CMS</label>' +
|
||||
'<select v-model="selectedProduct" class="input-reset outline-focus ba b--black-20 ph2 pv3 mb2 db w-100" name="location[index][country]" v-model="location.country" required>' +
|
||||
'<option value="">-</option>' +
|
||||
'<option v-for="product in products">{{ product }}</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'<div class="w-100 mr3-ns">' +
|
||||
'<label for="region" class="f6 b db mb2 mt4 tl">Region</label>' +
|
||||
'<select v-model="selectedRegion" class="input-reset outline-focus ba b--black-20 ph2 pv3 mb2 db w-100" name="location[index][region]" v-model="location.region" required>' +
|
||||
'<option value="">-</option>' +
|
||||
'<option>Baden-Würtemberg</option>' +
|
||||
'<option>Bayern</option>' +
|
||||
'<option>Berlin</option>' +
|
||||
'<option>Brandenburg</option>' +
|
||||
'<option>Bremen</option>' +
|
||||
'<option>Hamburg</option>' +
|
||||
'<option>Hessen</option>' +
|
||||
'<option>Mecklenburg-Vorpommern</option>' +
|
||||
'<option>Niedersachsen</option>' +
|
||||
'<option>Nordrhein-Westfalen</option>' +
|
||||
'<option>Rheinland-Pfalz</option>' +
|
||||
'<option>Saarland</option>' +
|
||||
'<option>Sachsen</option>' +
|
||||
'<option>Sachsen-Anhalt</option>' +
|
||||
'<option>Schleswig-Holstein</option>' +
|
||||
'<option>Thüringen</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'<button @click.prevent="searchProducts" class="w-100 w-30-ns link bg-customized-2 custombutton link-white dim bn mb2 pa3 mt3 mt0-ns pointer">Suchen</button>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'</form>' +
|
||||
'</div>' +
|
||||
'<div v-if="message" class="w-100 pa3 tc mv3 customized-2 ba b--customized-2">{{ message }}</div>' +
|
||||
'<div v-for="ad in ads">' +
|
||||
'<div class="w-100 bg-customized dark-gray flex dib tl pa0 mv3 f5 relative">' +
|
||||
'<div class="w-100 ba b--light-gray pa0 shadow-hover">' +
|
||||
'<a :href="getLink(ad)" rel="ugc sponsored" target="_blank" class="link dark-gray pa0 mt3 mb0">' +
|
||||
'<div v-if="ad.pro" class="absolute-ns tc top-0 right-0 ba b--dark-gray pa1 f6 ma3">Premium</div>' +
|
||||
'<h3 class="mt4 mb1 pv0 ph3 underline-hover">{{ getTitle(ad) }}</h3>' +
|
||||
'<small class="pv0 ph3 ma0 underline-hover">{{ getLink(ad) }}</small>' +
|
||||
'<p class="mt1 mb3 pv0 ph3 underline-hover">{{ getTeaser(ad) }}</p>' +
|
||||
'</a>' +
|
||||
'<div class="f5 pv2 ph3 bt dark-gray b--moon-gray w-100 flex">' +
|
||||
'<div class="tl w-50">' +
|
||||
'<svg class="icon icon-location"><use xlink:href="#icon-location"></use></svg> {{ ad.city }} ' +
|
||||
'<span class="pl2"><svg class="icon icon-location"><use xlink:href="#icon-users"></use></svg> {{ ad.size}}</span>' +
|
||||
'</div>' +
|
||||
'<div class="tr w-50">Web:' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" :href="ad.company_link" target="_blank"><svg class="icon icon-location"><use xlink:href="#icon-home"></use></svg></a>' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" v-if="ad.sm_link_1" :href="ad.sm_link_1" target="_blank"><svg :class="getSocialIcon(ad.sm_link_1)" class="icon"><use :xlink:href="getSocialIcon(ad.sm_link_1, true)"></use></svg></a>' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" v-if="ad.sm_link_2" :href="ad.sm_link_2" target="_blank"><svg :class="getSocialIcon(ad.sm_link_2)" class="icon"><use :xlink:href="getSocialIcon(ad.sm_link_2, true)"></use></svg></a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="w-100 bg-white dark-gray dib tl pa0 mv3 f5">' +
|
||||
'<div class="w-100 ba b--light-gray pa0 tc">' +
|
||||
'<h3 class="mt4 mb0 pv0 ph3">Web-Agentur oder Freelancer?</h3>' +
|
||||
'<p class="mt3 mb3 pv0 ph3">Dann ist genau hier Ihre Expertise gefragt!<br/> Mit einem Dienstleister-Eintrag auf cmsstash.de</p>' +
|
||||
'<a href="https://service.cmsstash.de" class="link bg-customized-2 link-white dim ba1 b--red mt0 mb4 ph3 pv2 dib br1">Eintrag erstellen</a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
mounted: function(){
|
||||
|
||||
var products = document.getElementById("hyerapp").dataset.products;
|
||||
this.products = products.split(',');
|
||||
|
||||
this.token = document.getElementById("hyerapp").dataset.token;
|
||||
|
||||
self = this;
|
||||
|
||||
var access = document.getElementById("hyerapp").dataset.access;
|
||||
|
||||
myaxios.get('/latestadsfe30s8edw4wdkp?access='+access)
|
||||
.then(function (response) {
|
||||
|
||||
self.ads = response.data.ads;
|
||||
/* if matomo is on, check dom for new links */
|
||||
if(_paq)
|
||||
{
|
||||
Vue.nextTick(function () {
|
||||
_paq.push(['enableLinkTracking']);
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(function (error) {});
|
||||
},
|
||||
methods: {
|
||||
searchProducts: function()
|
||||
{
|
||||
self = this;
|
||||
|
||||
myaxios.get('/searchadsfe30s8edw4wdkp',{
|
||||
params: {
|
||||
token: this.token,
|
||||
product: this.selectedProduct,
|
||||
region: this.selectedRegion
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
self.ads = response.data.ads;
|
||||
/* if matomo is on, check dom for new links */
|
||||
if(_paq)
|
||||
{
|
||||
Vue.nextTick(function () {
|
||||
_paq.push(['enableLinkTracking']);
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
self.message = error.response.data.message;
|
||||
self.messageType = 'error';
|
||||
}
|
||||
});
|
||||
},
|
||||
getTitle: function(product)
|
||||
{
|
||||
if(product.ad_title)
|
||||
{
|
||||
return product.ad_title;
|
||||
}
|
||||
return product.company_name;
|
||||
},
|
||||
getTeaser: function(product)
|
||||
{
|
||||
if(product.ad_teaser)
|
||||
{
|
||||
return product.ad_teaser;
|
||||
}
|
||||
return product.company_description;
|
||||
},
|
||||
getLink: function(product)
|
||||
{
|
||||
if(product.ad_link)
|
||||
{
|
||||
return product.ad_link;
|
||||
}
|
||||
return product.company_link;
|
||||
},
|
||||
getSocialIcon: function(icon,id)
|
||||
{
|
||||
var prefix = id ? '#' : '';
|
||||
if(icon.indexOf("twitter") > -1){ return prefix+'icon-twitter' }
|
||||
else if(icon.indexOf("facebook") > -1){ return prefix+'icon-facebook' }
|
||||
else if(icon.indexOf("xing") > -1){ return prefix+'icon-xing2' }
|
||||
else if(icon.indexOf("linkedin") > -1){ return prefix+'icon-linkedin2' }
|
||||
return prefix+'icon-link';
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Vue.component('premiumads', {
|
||||
data: function () {
|
||||
return {
|
||||
ads: [],
|
||||
fill: [],
|
||||
}
|
||||
},
|
||||
template: '<div>' +
|
||||
'<div v-for="ad in ads">' +
|
||||
'<div class="w-100 bg-customized dark-gray flex dib tl pa0 mv3 f5 relative">' +
|
||||
'<div class="w-100 ba b--light-gray pa0 shadow-hover">' +
|
||||
'<a rel="ugc sponsored" :href="getLink(ad)" target="_blank" class="link dark-gray pa0 mt3 mb0">' +
|
||||
'<div v-if="ad.pro" class="absolute-ns tc top-0 right-0 ba b--dark-gray pa1 f6 ma3">Premium</div>' +
|
||||
'<h3 class="mt4 mb1 pv0 ph3 underline-hover">{{ getTitle(ad) }}</h3>' +
|
||||
'<small class="pv0 ph3 ma0 underline-hover">{{ getLink(ad) }}</small>' +
|
||||
'<p class="mt1 mb3 pv0 ph3 underline-hover">{{ getTeaser(ad) }}</p>' +
|
||||
'</a>' +
|
||||
'<div class="f5 pv2 ph3 bt dark-gray b--moon-gray w-100 flex">' +
|
||||
'<div class="tl w-50">' +
|
||||
'<svg class="icon icon-location"><use xlink:href="#icon-location"></use></svg> {{ ad.city }} ' +
|
||||
'<span class="pl2"><svg class="icon icon-location"><use xlink:href="#icon-users"></use></svg> {{ ad.size}}</span>' +
|
||||
'</div>' +
|
||||
'<div class="tr w-50">Web:' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" :href="ad.company_link" target="_blank"><svg class="icon icon-location"><use xlink:href="#icon-home"></use></svg></a>' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" v-if="ad.sm_link_1" :href="ad.sm_link_1" target="_blank"><svg :class="getSocialIcon(ad.sm_link_1)" class="icon"><use :xlink:href="getSocialIcon(ad.sm_link_1, true)"></use></svg></a>' +
|
||||
'<a class="link dark-gray ph2" rel="ugc sponsored" v-if="ad.sm_link_2" :href="ad.sm_link_2" target="_blank"><svg :class="getSocialIcon(ad.sm_link_2)" class="icon"><use :xlink:href="getSocialIcon(ad.sm_link_2, true)"></use></svg></a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div v-if="ads.length < 3">' +
|
||||
'<div class="w-100 bg-white dark-gray dib tl pa0 mv3 f5">' +
|
||||
'<div class="w-100 ba b--light-gray pa0 tc">' +
|
||||
'<h3 class="mt4 mb0 pv0 ph3">Web-Agentur oder Freelancer?</h3>' +
|
||||
'<p class="mt3 mb3 pv0 ph3">Dann ist genau hier Ihre Expertise gefragt!<br/> Mit einem Dienstleister-Eintrag auf cmsstash.de</p>' +
|
||||
'<a href="https://service.cmsstash.de" class="link bg-customized-2 link-white dim ba1 b--red mt0 mb4 ph3 pv2 dib br1">Eintrag erstellen</a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
mounted: function(){
|
||||
|
||||
self = this;
|
||||
var access = document.getElementById("hyerapp").dataset.access;
|
||||
|
||||
myaxios.get('/proadsfe30s8edw4wdkp?access='+access)
|
||||
.then(function (response) {
|
||||
self.ads = response.data.ads;
|
||||
var restads = 3 - self.ads.length;
|
||||
for(var i = 0; i < restads; i++)
|
||||
{
|
||||
self.fill.push(1);
|
||||
}
|
||||
/* if matomo is on, check dom for new links */
|
||||
if(_paq)
|
||||
{
|
||||
Vue.nextTick(function () {
|
||||
_paq.push(['enableLinkTracking']);
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getTitle: function(product)
|
||||
{
|
||||
if(product.ad_title)
|
||||
{
|
||||
return product.ad_title;
|
||||
}
|
||||
return product.company_name;
|
||||
},
|
||||
getTeaser: function(product)
|
||||
{
|
||||
if(product.ad_teaser)
|
||||
{
|
||||
return product.ad_teaser;
|
||||
}
|
||||
return product.company_description;
|
||||
},
|
||||
getLink: function(product)
|
||||
{
|
||||
if(product.ad_link)
|
||||
{
|
||||
return product.ad_link;
|
||||
}
|
||||
return product.company_link;
|
||||
},
|
||||
getSocialIcon: function(icon,id)
|
||||
{
|
||||
var prefix = id ? '#' : '';
|
||||
if(icon.indexOf("twitter") > -1){ return prefix+'icon-twitter' }
|
||||
else if(icon.indexOf("facebook") > -1){ return prefix+'icon-facebook' }
|
||||
else if(icon.indexOf("xing") > -1){ return prefix+'icon-xing2' }
|
||||
else if(icon.indexOf("linkedin") > -1){ return prefix+'icon-linkedin2' }
|
||||
return prefix+'icon-link';
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var app = new Vue({
|
||||
el: "#hyerapp",
|
||||
data: {
|
||||
disabled: false,
|
||||
message: '',
|
||||
messageType: '',
|
||||
},
|
||||
});
|
51
plugins/hyer/templates/hyer.twig
Normal file
51
plugins/hyer/templates/hyer.twig
Normal file
@@ -0,0 +1,51 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" style="display:none">
|
||||
<symbol id="icon-facebook" viewBox="0 0 16 16">
|
||||
<title>facebook</title>
|
||||
<path d="M9.5 3h2.5v-3h-2.5c-1.93 0-3.5 1.57-3.5 3.5v1.5h-2v3h2v8h3v-8h2.5l0.5-3h-3v-1.5c0-0.271 0.229-0.5 0.5-0.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-home" viewBox="0 0 16 16">
|
||||
<title>home</title>
|
||||
<path d="M16 9.226l-8-6.21-8 6.21v-2.532l8-6.21 8 6.21zM14 9v6h-4v-4h-4v4h-4v-6l6-4.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-location" viewBox="0 0 16 16">
|
||||
<title>location</title>
|
||||
<path d="M8 0c-2.761 0-5 2.239-5 5 0 5 5 11 5 11s5-6 5-11c0-2.761-2.239-5-5-5zM8 8c-1.657 0-3-1.343-3-3s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-users" viewBox="0 0 18 16">
|
||||
<title>users</title>
|
||||
<path d="M12 12.041v-0.825c1.102-0.621 2-2.168 2-3.716 0-2.485 0-4.5-3-4.5s-3 2.015-3 4.5c0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h14c0-2.015-2.608-3.682-6-3.959z"></path>
|
||||
<path d="M5.112 12.427c0.864-0.565 1.939-0.994 3.122-1.256-0.235-0.278-0.449-0.588-0.633-0.922-0.475-0.863-0.726-1.813-0.726-2.748 0-1.344 0-2.614 0.478-3.653 0.464-1.008 1.299-1.633 2.488-1.867-0.264-1.195-0.968-1.98-2.841-1.98-3 0-3 2.015-3 4.5 0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h4.359c0.227-0.202 0.478-0.393 0.753-0.573z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-twitter" viewBox="0 0 16 16">
|
||||
<title>twitter</title>
|
||||
<path d="M16 3.538c-0.588 0.263-1.222 0.438-1.884 0.516 0.678-0.406 1.197-1.050 1.444-1.816-0.634 0.375-1.338 0.65-2.084 0.797-0.6-0.638-1.453-1.034-2.397-1.034-1.813 0-3.281 1.469-3.281 3.281 0 0.256 0.028 0.506 0.084 0.747-2.728-0.138-5.147-1.444-6.766-3.431-0.281 0.484-0.444 1.050-0.444 1.65 0 1.138 0.578 2.144 1.459 2.731-0.538-0.016-1.044-0.166-1.488-0.409 0 0.013 0 0.028 0 0.041 0 1.591 1.131 2.919 2.634 3.219-0.275 0.075-0.566 0.116-0.866 0.116-0.212 0-0.416-0.022-0.619-0.059 0.419 1.303 1.631 2.253 3.066 2.281-1.125 0.881-2.538 1.406-4.078 1.406-0.266 0-0.525-0.016-0.784-0.047 1.456 0.934 3.181 1.475 5.034 1.475 6.037 0 9.341-5.003 9.341-9.341 0-0.144-0.003-0.284-0.009-0.425 0.641-0.459 1.197-1.038 1.637-1.697z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-linkedin2" viewBox="0 0 16 16">
|
||||
<title>linkedin2</title>
|
||||
<path d="M6 6h2.767v1.418h0.040c0.385-0.691 1.327-1.418 2.732-1.418 2.921 0 3.461 1.818 3.461 4.183v4.817h-2.885v-4.27c0-1.018-0.021-2.329-1.5-2.329-1.502 0-1.732 1.109-1.732 2.255v4.344h-2.883v-9z"></path>
|
||||
<path d="M1 6h3v9h-3v-9z"></path>
|
||||
<path d="M4 3.5c0 0.828-0.672 1.5-1.5 1.5s-1.5-0.672-1.5-1.5c0-0.828 0.672-1.5 1.5-1.5s1.5 0.672 1.5 1.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-xing2" viewBox="0 0 16 16">
|
||||
<title>xing2</title>
|
||||
<path d="M2.431 3.159c-0.138 0-0.256 0.050-0.316 0.144-0.059 0.1-0.050 0.225 0.013 0.353l1.559 2.7c0.003 0.006 0.003 0.009 0 0.013l-2.45 4.331c-0.063 0.128-0.059 0.256 0 0.353 0.059 0.094 0.163 0.156 0.3 0.156h2.306c0.344 0 0.513-0.234 0.628-0.447 0 0 2.397-4.241 2.491-4.406-0.009-0.016-1.588-2.766-1.588-2.766-0.116-0.203-0.287-0.431-0.644-0.431h-2.3z"></path>
|
||||
<path d="M12.125 0c-0.344 0-0.494 0.216-0.619 0.441 0 0-4.972 8.816-5.134 9.106 0.009 0.016 3.278 6.016 3.278 6.016 0.116 0.203 0.291 0.441 0.644 0.441h2.306c0.137 0 0.247-0.053 0.306-0.147 0.063-0.1 0.059-0.228-0.006-0.356l-3.25-5.947c-0.003-0.006-0.003-0.009 0-0.016l5.109-9.034c0.063-0.128 0.066-0.256 0.006-0.356-0.059-0.094-0.169-0.147-0.306-0.147h-2.334z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cart" viewBox="0 0 16 16">
|
||||
<title>cart</title>
|
||||
<path d="M6 14.5c0 0.828-0.672 1.5-1.5 1.5s-1.5-0.672-1.5-1.5c0-0.828 0.672-1.5 1.5-1.5s1.5 0.672 1.5 1.5z"></path>
|
||||
<path d="M16 14.5c0 0.828-0.672 1.5-1.5 1.5s-1.5-0.672-1.5-1.5c0-0.828 0.672-1.5 1.5-1.5s1.5 0.672 1.5 1.5z"></path>
|
||||
<path d="M16 8v-6h-12c0-0.552-0.448-1-1-1h-3v1h2l0.751 6.438c-0.458 0.367-0.751 0.93-0.751 1.562 0 1.105 0.895 2 2 2h12v-1h-12c-0.552 0-1-0.448-1-1 0-0.003 0-0.007 0-0.010l13-1.99z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-warning" viewBox="0 0 16 16">
|
||||
<title>warning</title>
|
||||
<path d="M8 1.45l6.705 13.363h-13.409l6.705-13.363zM8 0c-0.345 0-0.69 0.233-0.951 0.698l-6.829 13.611c-0.523 0.93-0.078 1.691 0.989 1.691h13.583c1.067 0 1.512-0.761 0.989-1.691h0l-6.829-13.611c-0.262-0.465-0.606-0.698-0.951-0.698v0z"></path>
|
||||
<path d="M9 13c0 0.552-0.448 1-1 1s-1-0.448-1-1c0-0.552 0.448-1 1-1s1 0.448 1 1z"></path>
|
||||
<path d="M8 11c-0.552 0-1-0.448-1-1v-3c0-0.552 0.448-1 1-1s1 0.448 1 1v3c0 0.552-0.448 1-1 1z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-coin-euro" viewBox="0 0 16 16">
|
||||
<title>coin-euro</title>
|
||||
<path d="M7.5 1c-4.142 0-7.5 3.358-7.5 7.5s3.358 7.5 7.5 7.5c4.142 0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5zM7.5 14.5c-3.314 0-6-2.686-6-6s2.686-6 6-6c3.314 0 6 2.686 6 6s-2.686 6-6 6z"></path>
|
||||
<path d="M10.482 10.068c-0.239-0.139-0.545-0.058-0.684 0.181-0.27 0.463-0.767 0.751-1.298 0.751h-2c-0.652 0-1.208-0.418-1.414-1h2.414c0.276 0 0.5-0.224 0.5-0.5s-0.224-0.5-0.5-0.5h-2.5v-1h2.5c0.276 0 0.5-0.224 0.5-0.5s-0.224-0.5-0.5-0.5h-2.414c0.206-0.582 0.762-1 1.414-1h2c0.531 0 1.028 0.288 1.298 0.751 0.139 0.239 0.445 0.32 0.684 0.181s0.32-0.445 0.181-0.684c-0.448-0.77-1.277-1.249-2.162-1.249h-2c-1.207 0-2.217 0.86-2.45 2h-0.55c-0.276 0-0.5 0.224-0.5 0.5s0.224 0.5 0.5 0.5h0.5v1h-0.5c-0.276 0-0.5 0.224-0.5 0.5s0.224 0.5 0.5 0.5h0.55c0.232 1.14 1.242 2 2.45 2h2c0.886 0 1.714-0.478 2.162-1.249 0.139-0.239 0.058-0.545-0.181-0.684z"></path>
|
||||
</symbol>
|
||||
</svg>
|
After Width: | Height: | Size: 6.0 KiB |
@@ -1,47 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\Math;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Math extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
$mathSettings = $this->settings['settings']['plugins']['math'];
|
||||
|
||||
if($mathSettings['tool'] == 'mathjax')
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addJS('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-MML-AM_CHTML');
|
||||
}
|
||||
|
||||
if($mathSettings['tool'] == 'katex')
|
||||
{
|
||||
$this->addJS('/math/public/katex.min.js');
|
||||
$this->addJS('/math/public/auto-render.min.js');
|
||||
$this->addCSS('/math/public/katex.min.css');
|
||||
|
||||
/* initialize autorendering of page only in frontend */
|
||||
if (strpos($this->getPath(), 'tm/content') === false)
|
||||
{
|
||||
$this->addInlineJs('renderMathInElement(document.body);');
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
namespace Plugins\Math;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
|
||||
class Math extends Plugin
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onSettingsLoaded',
|
||||
'onTwigLoaded' => 'onTwigLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
$mathSettings = $this->settings['settings']['plugins']['math'];
|
||||
|
||||
if($mathSettings['tool'] == 'mathjax')
|
||||
{
|
||||
/* add external CSS and JavaScript */
|
||||
$this->addJS('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-MML-AM_CHTML');
|
||||
}
|
||||
|
||||
if($mathSettings['tool'] == 'katex')
|
||||
{
|
||||
$this->addJS('/math/public/katex.min.js');
|
||||
$this->addJS('/math/public/auto-render.min.js');
|
||||
$this->addCSS('/math/public/katex.min.css');
|
||||
|
||||
/* initialize autorendering of page only in frontend */
|
||||
if (strpos($this->getPath(), 'tm/content') === false)
|
||||
{
|
||||
$this->addInlineJs('renderMathInElement(document.body);');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,20 +1,20 @@
|
||||
name: Math
|
||||
version: 1.0.2
|
||||
description: Adds support for katex and mathjax.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://mathjax.org/
|
||||
licence: Apache 2.0 / MIT
|
||||
|
||||
settings:
|
||||
tool: none
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
tool:
|
||||
type: radio
|
||||
label: Choose Your Tool
|
||||
options:
|
||||
none: None
|
||||
katex: KaTex
|
||||
name: Math
|
||||
version: 1.0.2
|
||||
description: Adds support for katex and mathjax.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://mathjax.org/
|
||||
licence: Apache 2.0 / MIT
|
||||
|
||||
settings:
|
||||
tool: none
|
||||
|
||||
forms:
|
||||
fields:
|
||||
|
||||
tool:
|
||||
type: radio
|
||||
label: Choose Your Tool
|
||||
options:
|
||||
none: None
|
||||
katex: KaTex
|
||||
mathjax: MathJax
|
@@ -1,140 +1,140 @@
|
||||
# [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/)
|
||||
[](https://travis-ci.org/Khan/KaTeX)
|
||||
[](https://codecov.io/gh/Khan/KaTeX)
|
||||
[](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
|
||||
|
||||
* **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://www.intmath.com/cg5/katex-mathjax-comparison.php).
|
||||
* **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
|
||||
* **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
|
||||
* **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
|
||||
|
||||
KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, Edge, and IE 9 - IE 11. More information can be found on the [list of supported commands](https://khan.github.io/KaTeX/function-support.html) and on the [wiki](https://github.com/khan/katex/wiki).
|
||||
|
||||
## Usage
|
||||
|
||||
You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/katex.min.css" integrity="sha384-VEnyslhHLHiYPca9KFkBB3CMeslnM9CzwjxsEbZTeA21JBm7tdLwKoZmCt3cZTYD" crossorigin="anonymous">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/katex.min.js" integrity="sha384-O4hpKqcplNCe+jLuBVEXC10Rn1QEqAmX98lKAIFBEDxZI0a+6Z2w2n8AEtQbR4CD" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
#### In-browser rendering
|
||||
|
||||
Call `katex.render` with a TeX expression and a DOM element to render into:
|
||||
|
||||
```js
|
||||
katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
|
||||
```
|
||||
|
||||
If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
|
||||
|
||||
#### Server side rendering or rendering to a string
|
||||
|
||||
To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
|
||||
|
||||
```js
|
||||
var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
|
||||
// '<span class="katex">...</span>'
|
||||
```
|
||||
|
||||
Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
|
||||
|
||||
#### Security
|
||||
|
||||
Any HTML generated by KaTeX *should* be safe from `<script>` or other code
|
||||
injection attacks.
|
||||
(See `maxSize` below for preventing large width/height visual affronts.)
|
||||
Of course, it is always a good idea to sanitize the HTML, though you will need
|
||||
a rather generous whitelist (including some of SVG and MathML) to support
|
||||
all of KaTeX.
|
||||
|
||||
#### Handling errors
|
||||
|
||||
If KaTeX encounters an error (invalid or unsupported LaTeX), then it will
|
||||
throw an exception of type `katex.ParseError`. The message in this error
|
||||
includes some of the LaTeX source code, so needs to be escaped if you want
|
||||
to render it to HTML. In particular, you should convert `&`, `<`, `>`
|
||||
characters to `&`, `<`, `>` (e.g., using `_.escape`)
|
||||
before including either LaTeX source code or exception messages in your
|
||||
HTML/DOM. (Failure to escape in this way makes a `<script>` injection
|
||||
attack possible if your LaTeX source is untrusted.)
|
||||
|
||||
#### Rendering options
|
||||
|
||||
You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
|
||||
|
||||
- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
|
||||
- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
|
||||
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
|
||||
- `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters).
|
||||
- `colorIsTextColor`: `boolean`. If `true`, `\color` will work like LaTeX's `\textcolor`, and take two arguments (e.g., `\color{blue}{hello}`), which restores the old behavior of KaTeX (pre-0.8.0). If `false` (the default), `\color` will work like LaTeX's `\color`, and take one argument (e.g., `\color{blue}hello`). In both cases, `\textcolor` works as in LaTeX (e.g., `\textcolor{blue}{hello}`).
|
||||
- `maxSize`: `number`. If non-zero, all user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. Otherwise, users can make elements and spaces arbitrarily large (the default behavior).
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
katex.render("c = \\pm\\sqrt{a^2 + b^2}\\in\\RR", element, {
|
||||
displayMode: true,
|
||||
macros: {
|
||||
"\\RR": "\\mathbb{R}"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Automatic rendering of math on a page
|
||||
|
||||
Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
|
||||
|
||||
#### Font size and lengths
|
||||
|
||||
By default, KaTeX math is rendered in a 1.21× larger font than the surrounding
|
||||
context, which makes super- and subscripts easier to read. You can control
|
||||
this using CSS, for example:
|
||||
|
||||
```css
|
||||
.katex { font-size: 1.1em; }
|
||||
```
|
||||
|
||||
KaTeX supports all TeX units, including absolute units like `cm` and `in`.
|
||||
Absolute units are currently scaled relative to the default TeX font size of
|
||||
10pt, so that `\kern1cm` produces the same results as `\kern2.845275em`.
|
||||
As a result, relative and absolute units are both uniformly scaled relative
|
||||
to LaTeX with a 10pt font; for example, the rectangle `\rule{1cm}{1em}` has
|
||||
the same aspect ratio in KaTeX as in LaTeX. However, because most browsers
|
||||
default to a larger font size, this typically means that a 1cm kern in KaTeX
|
||||
will appear larger than 1cm in browser units.
|
||||
|
||||
### Common Issues
|
||||
- Many Markdown preprocessors, such as the one that Jekyll and GitHub Pages use,
|
||||
have a "smart quotes" feature. This changes `'` to `’` which is an issue for
|
||||
math containing primes, e.g. `f'`. This can be worked around by defining a
|
||||
single character macro which changes them back, e.g. `{"’", "'"}`.
|
||||
- KaTeX follows LaTeX's rendering of `aligned` and `matrix` environments unlike
|
||||
MathJax. When displaying fractions one above another in these vertical
|
||||
layouts there may not be enough space between rows for people who are used to
|
||||
MathJax's rendering. The distance between rows can be adjusted by using
|
||||
`\\[0.1em]` instead of the standard line separator distance.
|
||||
- KaTeX does not support the `align` environment because LaTeX doesn't support
|
||||
`align` in math mode. The `aligned` environment offers the same functionality
|
||||
but in math mode, so use that instead or define a macro that maps `align` to
|
||||
`aligned`.
|
||||
|
||||
## Libraries
|
||||
|
||||
### Angular2+
|
||||
- [ng-katex](https://github.com/garciparedes/ng-katex) Angular module to write beautiful math expressions with TeX syntax boosted by KaTeX library
|
||||
|
||||
### Ruby
|
||||
|
||||
- [katex-ruby](https://github.com/glebm/katex-ruby) Provides server-side rendering and integration with popular Ruby web frameworks (Rails, Hanami, and anything that uses Sprockets).
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
# [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/)
|
||||
[](https://travis-ci.org/Khan/KaTeX)
|
||||
[](https://codecov.io/gh/Khan/KaTeX)
|
||||
[](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
|
||||
|
||||
* **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://www.intmath.com/cg5/katex-mathjax-comparison.php).
|
||||
* **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
|
||||
* **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
|
||||
* **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
|
||||
|
||||
KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, Edge, and IE 9 - IE 11. More information can be found on the [list of supported commands](https://khan.github.io/KaTeX/function-support.html) and on the [wiki](https://github.com/khan/katex/wiki).
|
||||
|
||||
## Usage
|
||||
|
||||
You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/katex.min.css" integrity="sha384-VEnyslhHLHiYPca9KFkBB3CMeslnM9CzwjxsEbZTeA21JBm7tdLwKoZmCt3cZTYD" crossorigin="anonymous">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/katex.min.js" integrity="sha384-O4hpKqcplNCe+jLuBVEXC10Rn1QEqAmX98lKAIFBEDxZI0a+6Z2w2n8AEtQbR4CD" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
#### In-browser rendering
|
||||
|
||||
Call `katex.render` with a TeX expression and a DOM element to render into:
|
||||
|
||||
```js
|
||||
katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
|
||||
```
|
||||
|
||||
If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
|
||||
|
||||
#### Server side rendering or rendering to a string
|
||||
|
||||
To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
|
||||
|
||||
```js
|
||||
var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
|
||||
// '<span class="katex">...</span>'
|
||||
```
|
||||
|
||||
Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
|
||||
|
||||
#### Security
|
||||
|
||||
Any HTML generated by KaTeX *should* be safe from `<script>` or other code
|
||||
injection attacks.
|
||||
(See `maxSize` below for preventing large width/height visual affronts.)
|
||||
Of course, it is always a good idea to sanitize the HTML, though you will need
|
||||
a rather generous whitelist (including some of SVG and MathML) to support
|
||||
all of KaTeX.
|
||||
|
||||
#### Handling errors
|
||||
|
||||
If KaTeX encounters an error (invalid or unsupported LaTeX), then it will
|
||||
throw an exception of type `katex.ParseError`. The message in this error
|
||||
includes some of the LaTeX source code, so needs to be escaped if you want
|
||||
to render it to HTML. In particular, you should convert `&`, `<`, `>`
|
||||
characters to `&`, `<`, `>` (e.g., using `_.escape`)
|
||||
before including either LaTeX source code or exception messages in your
|
||||
HTML/DOM. (Failure to escape in this way makes a `<script>` injection
|
||||
attack possible if your LaTeX source is untrusted.)
|
||||
|
||||
#### Rendering options
|
||||
|
||||
You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
|
||||
|
||||
- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
|
||||
- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
|
||||
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
|
||||
- `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters).
|
||||
- `colorIsTextColor`: `boolean`. If `true`, `\color` will work like LaTeX's `\textcolor`, and take two arguments (e.g., `\color{blue}{hello}`), which restores the old behavior of KaTeX (pre-0.8.0). If `false` (the default), `\color` will work like LaTeX's `\color`, and take one argument (e.g., `\color{blue}hello`). In both cases, `\textcolor` works as in LaTeX (e.g., `\textcolor{blue}{hello}`).
|
||||
- `maxSize`: `number`. If non-zero, all user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. Otherwise, users can make elements and spaces arbitrarily large (the default behavior).
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
katex.render("c = \\pm\\sqrt{a^2 + b^2}\\in\\RR", element, {
|
||||
displayMode: true,
|
||||
macros: {
|
||||
"\\RR": "\\mathbb{R}"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Automatic rendering of math on a page
|
||||
|
||||
Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
|
||||
|
||||
#### Font size and lengths
|
||||
|
||||
By default, KaTeX math is rendered in a 1.21× larger font than the surrounding
|
||||
context, which makes super- and subscripts easier to read. You can control
|
||||
this using CSS, for example:
|
||||
|
||||
```css
|
||||
.katex { font-size: 1.1em; }
|
||||
```
|
||||
|
||||
KaTeX supports all TeX units, including absolute units like `cm` and `in`.
|
||||
Absolute units are currently scaled relative to the default TeX font size of
|
||||
10pt, so that `\kern1cm` produces the same results as `\kern2.845275em`.
|
||||
As a result, relative and absolute units are both uniformly scaled relative
|
||||
to LaTeX with a 10pt font; for example, the rectangle `\rule{1cm}{1em}` has
|
||||
the same aspect ratio in KaTeX as in LaTeX. However, because most browsers
|
||||
default to a larger font size, this typically means that a 1cm kern in KaTeX
|
||||
will appear larger than 1cm in browser units.
|
||||
|
||||
### Common Issues
|
||||
- Many Markdown preprocessors, such as the one that Jekyll and GitHub Pages use,
|
||||
have a "smart quotes" feature. This changes `'` to `’` which is an issue for
|
||||
math containing primes, e.g. `f'`. This can be worked around by defining a
|
||||
single character macro which changes them back, e.g. `{"’", "'"}`.
|
||||
- KaTeX follows LaTeX's rendering of `aligned` and `matrix` environments unlike
|
||||
MathJax. When displaying fractions one above another in these vertical
|
||||
layouts there may not be enough space between rows for people who are used to
|
||||
MathJax's rendering. The distance between rows can be adjusted by using
|
||||
`\\[0.1em]` instead of the standard line separator distance.
|
||||
- KaTeX does not support the `align` environment because LaTeX doesn't support
|
||||
`align` in math mode. The `aligned` environment offers the same functionality
|
||||
but in math mode, so use that instead or define a macro that maps `align` to
|
||||
`aligned`.
|
||||
|
||||
## Libraries
|
||||
|
||||
### Angular2+
|
||||
- [ng-katex](https://github.com/garciparedes/ng-katex) Angular module to write beautiful math expressions with TeX syntax boosted by KaTeX library
|
||||
|
||||
### Ruby
|
||||
|
||||
- [katex-ruby](https://github.com/glebm/katex-ruby) Provides server-side rendering and integration with popular Ruby web frameworks (Rails, Hanami, and anything that uses Sprockets).
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
|
87
plugins/search/index.php
Normal file
87
plugins/search/index.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\search;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
use \Typemill\Models\Write;
|
||||
use \Typemill\Models\WriteCache;
|
||||
|
||||
class Index extends Plugin
|
||||
{
|
||||
public static function getSubscribedEvents(){}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$write = new Write();
|
||||
|
||||
$index = $write->getFile('cache', 'index.json');
|
||||
if(!$index)
|
||||
{
|
||||
$this->createIndex();
|
||||
$index = $write->getFile('cache', 'index.json');
|
||||
}
|
||||
|
||||
return $this->returnJson($index);
|
||||
}
|
||||
|
||||
private function createIndex()
|
||||
{
|
||||
$write = new WriteCache();
|
||||
|
||||
# get content structure
|
||||
$structure = $write->getCache('cache', 'structure.txt');
|
||||
|
||||
# get data for search-index
|
||||
$index = $this->getAllContent($structure, $write);
|
||||
|
||||
# store the index file here
|
||||
$write->writeFile('cache', 'index.json', json_encode($index, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
private function getAllContent($structure, $write, $index = NULL)
|
||||
{
|
||||
foreach($structure as $item)
|
||||
{
|
||||
if($item->elementType == "folder")
|
||||
{
|
||||
if($item->fileType == 'md')
|
||||
{
|
||||
$page = $write->getFileWithPath('content' . $item->path . DIRECTORY_SEPARATOR . 'index.md');
|
||||
$pageArray = $this->getPageContentArray($page, $item->urlAbs);
|
||||
$index[$pageArray['url']] = $pageArray;
|
||||
}
|
||||
|
||||
$index = $this->getAllContent($item->folderContent, $write, $index);
|
||||
}
|
||||
else
|
||||
{
|
||||
$page = $write->getFileWithPath('content' . $item->path);
|
||||
$pageArray = $this->getPageContentArray($page, $item->urlAbs);
|
||||
$index[$pageArray['url']] = $pageArray;
|
||||
}
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
private function getPageContentArray($page, $url)
|
||||
{
|
||||
$parts = explode("\n", $page, 2);
|
||||
|
||||
# get the title / headline
|
||||
$title = trim($parts[0], '# ');
|
||||
$title = str_replace(["\r\n", "\n", "\r"],' ', $title);
|
||||
|
||||
# get and cleanup the content
|
||||
$content = $parts[1];
|
||||
$content = strip_tags($content);
|
||||
$content = str_replace(["\r\n", "\n", "\r"],' ', $content);
|
||||
|
||||
$pageContent = [
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'url' => $url
|
||||
];
|
||||
|
||||
return $pageContent;
|
||||
}
|
||||
}
|
19
plugins/search/public/lunr-licence.md
Normal file
19
plugins/search/public/lunr-licence.md
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2013 by Oliver Nightingale
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
6
plugins/search/public/lunr.min.js
vendored
Normal file
6
plugins/search/public/lunr.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
64
plugins/search/public/search.css
Normal file
64
plugins/search/public/search.css
Normal file
@@ -0,0 +1,64 @@
|
||||
.searchContainer{
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.searchContainer input{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1rem;
|
||||
float: left;
|
||||
padding-left: 15px;
|
||||
border-radius: 2px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.searchContainer button{
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
border: none;
|
||||
background: #232833;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
color: #fff;
|
||||
font-size: 10pt;
|
||||
margin-left: -50px;
|
||||
}
|
||||
.searchContainer button:hover,.searchContainer button:focus, .searchContainer button:active{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#searchresult{
|
||||
}
|
||||
.resultwrapper{
|
||||
}
|
||||
button#closeSearchResult{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
margin: 10px;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
padding: 15px;
|
||||
}
|
||||
button#closeSearchResult:hover,#closeSearchResult:focus{
|
||||
cursor: pointer;
|
||||
}
|
||||
.resultlist{
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style:none;
|
||||
}
|
||||
.resultitem{
|
||||
|
||||
}
|
||||
.resultheader{
|
||||
|
||||
}
|
||||
.resultsnippet{
|
||||
|
||||
}
|
115
plugins/search/public/search.js
Normal file
115
plugins/search/public/search.js
Normal file
@@ -0,0 +1,115 @@
|
||||
var searchField = document.getElementById("searchField");
|
||||
var searchButton = document.getElementById("searchButton");
|
||||
|
||||
if(searchField && searchButton)
|
||||
{
|
||||
var searchIndex = false;
|
||||
var documents = false;
|
||||
var holdcontent = false;
|
||||
var contentwrapper = false;
|
||||
|
||||
searchField.addEventListener("focus", function(event){
|
||||
|
||||
if(!searchIndex)
|
||||
{
|
||||
myaxios.get('/indexrs51gfe2o2')
|
||||
.then(function (response) {
|
||||
|
||||
documents = JSON.parse(response.data);
|
||||
|
||||
searchIndex = lunr(function() {
|
||||
this.ref("id");
|
||||
this.field("title", { boost: 10 });
|
||||
this.field("content");
|
||||
for (var key in documents){
|
||||
this.add({
|
||||
"id": documents[key].url,
|
||||
"title": documents[key].title,
|
||||
"content": documents[key].content
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
.catch(function (error) {});
|
||||
}
|
||||
});
|
||||
|
||||
searchButton.addEventListener("click", function(event){
|
||||
event.preventDefault();
|
||||
|
||||
var term = document.getElementById('searchField').value;
|
||||
var results = searchIndex.search(term);
|
||||
|
||||
var resultPages = results.map(function (match) {
|
||||
return documents[match.ref];
|
||||
});
|
||||
|
||||
resultsString = "<div class='resultwrapper'><h1>Result for " + term + "</h1>";
|
||||
resultsString += "<button id='closeSearchResult'>close</button>";
|
||||
resultsString += "<ul class='resultlist'>";
|
||||
resultPages.forEach(function (r) {
|
||||
resultsString += "<li class='resultitem'>";
|
||||
resultsString += "<a class='resultheader' href='" + r.url + "?q=" + term + "'><h3>" + r.title + "</h3></a>";
|
||||
resultsString += "<div class='resultsnippet'>" + r.content.substring(0, 200) + " ...</div>";
|
||||
resultsString += "</li>"
|
||||
});
|
||||
resultsString += "</ul></div>";
|
||||
|
||||
if(!holdcontent)
|
||||
{
|
||||
contentwrapper = document.getElementById("searchresult").parentNode;
|
||||
holdcontent = contentwrapper.innerHTML;
|
||||
}
|
||||
|
||||
contentwrapper.innerHTML = resultsString;
|
||||
|
||||
document.getElementById("closeSearchResult").addEventListener("click", function(event){
|
||||
contentwrapper.innerHTML = holdcontent;
|
||||
});
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
/*
|
||||
var searchIndex = lunr(function() {
|
||||
this.ref("id");
|
||||
this.field("title", { boost: 10 });
|
||||
this.field("content");
|
||||
for (var key in window.pages) {
|
||||
this.add({
|
||||
"id": key,
|
||||
"title": pages[key].title,
|
||||
"content": pages[key].content
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getQueryVariable(variable) {
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if (pair[0] === variable) {
|
||||
return decodeURIComponent(pair[1].replace(/\+/g, "%20"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var searchTerm = getQueryVariable("q");
|
||||
// creation of searchIndex from earlier example
|
||||
var results = searchIndex.search(searchTerm);
|
||||
var resultPages = results.map(function (match) {
|
||||
return pages[match.ref];
|
||||
});
|
||||
|
||||
// resultPages from previous example
|
||||
resultsString = "";
|
||||
resultPages.forEach(function (r) {
|
||||
resultsString += "<li>";
|
||||
resultsString += "<a class='result' href='" + r.url + "?q=" + searchTerm + "'><h3>" + r.title + "</h3></a>";
|
||||
resultsString += "<div class='snippet'>" + r.content.substring(0, 200) + "</div>";
|
||||
resultsString += "</li>"
|
||||
});
|
||||
document.querySelector("#search-results").innerHTML = resultsString;
|
||||
*/
|
128
plugins/search/search.php
Normal file
128
plugins/search/search.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\search;
|
||||
|
||||
use \Typemill\Plugin;
|
||||
use \Typemill\Models\Write;
|
||||
|
||||
class Search extends index
|
||||
{
|
||||
protected $item;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onSettingsLoaded' => 'onsettingsLoaded',
|
||||
'onContentArrayLoaded' => 'onContentArrayLoaded',
|
||||
'onPageReady' => 'onPageReady',
|
||||
'onPagePublished' => 'onPagePublished',
|
||||
'onPageUnpublished' => 'onPageUnpublished',
|
||||
'onPageSorted' => 'onPageSorted',
|
||||
'onPageDeleted' => 'onPageDeleted',
|
||||
);
|
||||
}
|
||||
|
||||
# get search.json with route
|
||||
# update search.json on publish
|
||||
|
||||
public static function addNewRoutes()
|
||||
{
|
||||
# the route for the api calls
|
||||
return array(
|
||||
array(
|
||||
'httpMethod' => 'get',
|
||||
'route' => '/indexrs51gfe2o2',
|
||||
'class' => 'Plugins\search\index:index'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function onSettingsLoaded($settings)
|
||||
{
|
||||
$this->settings = $settings->getData();
|
||||
}
|
||||
|
||||
# at any of theses events, delete the old search index
|
||||
public function onPagePublished($item)
|
||||
{
|
||||
$this->deleteSearchIndex();
|
||||
}
|
||||
public function onPageUnpublished($item)
|
||||
{
|
||||
$this->deleteSearchIndex();
|
||||
}
|
||||
public function onPageSorted($inputParams)
|
||||
{
|
||||
$this->deleteSearchIndex();
|
||||
}
|
||||
public function onPageDeleted($item)
|
||||
{
|
||||
$this->deleteSearchIndex();
|
||||
}
|
||||
|
||||
private function deleteSearchIndex()
|
||||
{
|
||||
$write = new Write();
|
||||
|
||||
# store the index file here
|
||||
$write->deleteFileWithPath('cache' . DIRECTORY_SEPARATOR . 'index.json');
|
||||
}
|
||||
|
||||
public function onContentArrayLoaded($contentArray)
|
||||
{
|
||||
# get content array
|
||||
$content = $contentArray->getData();
|
||||
$settings = $this->getPluginSettings('search');
|
||||
$salt = "asPx9Derf2";
|
||||
|
||||
# activate axios and vue in frontend
|
||||
$this->activateAxios();
|
||||
$this->activateVue();
|
||||
|
||||
# add the css and vue application
|
||||
$this->addCSS('/search/public/search.css');
|
||||
$this->addJS('/search/public/lunr.min.js');
|
||||
$this->addJS('/search/public/search.js');
|
||||
|
||||
# simple security for first request
|
||||
$secret = time();
|
||||
$secret = substr($secret,0,-1);
|
||||
$secret = md5($secret . $salt);
|
||||
|
||||
# simple csrf protection with a session for long following requests
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$length = 32;
|
||||
$token = substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
|
||||
$_SESSION['search'] = $token;
|
||||
$_SESSION['search-expire'] = time() + 1300; # 60 seconds * 30 minutes
|
||||
|
||||
# create div for vue app
|
||||
$search = '<div data-access="' . $secret . '" data-token="' . $token . '" id="searchresult"></div>';
|
||||
|
||||
# create content type
|
||||
$search = Array
|
||||
(
|
||||
'rawHtml' => $search,
|
||||
'allowRawHtmlInSafeMode' => true,
|
||||
'autobreak' => 1
|
||||
);
|
||||
|
||||
$content[] = $search;
|
||||
|
||||
$contentArray->setData($content);
|
||||
}
|
||||
|
||||
public function onPageReady($page)
|
||||
{
|
||||
$pageData = $page->getData($page);
|
||||
|
||||
$pageData['widgets']['search'] = '<div class="searchContainer" id="searchForm">'.
|
||||
'<input id="searchField" type="text" placeholder="search ..." />'.
|
||||
'<button id="searchButton" type="button">GO</button>'.
|
||||
'</div>';
|
||||
$page->setData($pageData);
|
||||
}
|
||||
}
|
6
plugins/search/search.yaml
Normal file
6
plugins/search/search.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
name: Search
|
||||
version: 1.0.0
|
||||
description: Adds a search to typemill with lunr.js.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: https://typemill.net
|
||||
licence: MIT
|
Reference in New Issue
Block a user