From 3522f0823c97da22449629bd2ac374bf7ad036e8 Mon Sep 17 00:00:00 2001 From: Ashley Stanley Date: Fri, 29 Sep 2023 12:32:06 -0400 Subject: [PATCH] Adding in the glossary --- dashboard/dashboard.php | 21 +- glossary/glossary.php | 168 ++- glossary/terms/above-the-fold.md | 22 + glossary/terms/accessibility.md | 22 + glossary/terms/admin.md | 22 + glossary/terms/advanced-custom-fields.md | 22 + glossary/terms/alt-text.md | 22 + glossary/terms/analytics.md | 22 + glossary/terms/api.md | 31 + settings/Parsedown.php | 1712 ++++++++++++++++++++++ settings/settings.php | 47 +- style.css | 33 + wds-site-documentation.php | 13 +- 13 files changed, 2077 insertions(+), 80 deletions(-) create mode 100644 glossary/terms/above-the-fold.md create mode 100644 glossary/terms/accessibility.md create mode 100644 glossary/terms/admin.md create mode 100644 glossary/terms/advanced-custom-fields.md create mode 100644 glossary/terms/alt-text.md create mode 100644 glossary/terms/analytics.md create mode 100644 glossary/terms/api.md create mode 100644 settings/Parsedown.php create mode 100644 style.css diff --git a/dashboard/dashboard.php b/dashboard/dashboard.php index 4cdd602..b674b78 100644 --- a/dashboard/dashboard.php +++ b/dashboard/dashboard.php @@ -1,25 +1,6 @@ - * @since 1.1.1 - */ \ No newline at end of file +## Create a glossary page that shows a list of terms and their definitions +function wds_documentation_glossary() { + ?> +
+ + + + + +
+ + '; + + // Create an instance of Parsedown + $parsedown = new \Parsedown(); + + foreach ($markdown_files as $markdown_file) { + $term_name = pathinfo($markdown_file, PATHINFO_FILENAME); + + // Replace hyphens with spaces and capitalize every word + $formatted_term_name = ucwords(str_replace('-', ' ', $term_name)); + + // Output a hidden div with the parsed HTML content + echo '' . esc_html($formatted_term_name) . '
'; + } + echo '
'; + echo '
'; + foreach ($markdown_files as $markdown_file) { + $term_name = pathinfo($markdown_file, PATHINFO_FILENAME); + + // Replace hyphens with spaces and capitalize every word + $formatted_term_name = ucwords(str_replace('-', ' ', $term_name)); + + // Get the content of the Markdown file + $term_file = plugin_dir_path(__FILE__) . 'terms/' . $term_name . '.md'; + $term_content = file_exists($term_file) ? file_get_contents($term_file) : 'The term does not exist.'; + + // Parse Markdown content to HTML using Parsedown + $html_content = $parsedown->text($term_content); + + // Output a hidden div with the parsed HTML content + echo ''; + } + echo '
'; + } else { + echo 'The "terms" folder does not exist.'; + } ?> +
+ + + + \ No newline at end of file diff --git a/glossary/terms/above-the-fold.md b/glossary/terms/above-the-fold.md new file mode 100644 index 0000000..94b1655 --- /dev/null +++ b/glossary/terms/above-the-fold.md @@ -0,0 +1,22 @@ +# Above the Fold +>Visible content without scrolling on a webpage. + +## Definition + +Above the Fold refers to the portion of a webpage that is immediately visible to users without the need for scrolling. It includes content and elements that users see when they first land on the page, typically impacting their initial impression and engagement. + +## Real Life Example + +On a news website, the above-the-fold area might display headline articles, images, and a navigation bar, giving users an immediate snapshot of the site's latest news offerings. + +## Why It’s Important + +1. First Impression: Above-the-fold content creates the first impression for users, influencing their decision to explore further or bounce from the website. +2. Content Prioritization: Vital information and key calls to action should be placed above the fold to ensure users engage with the most important elements. +3. User Engagement: Compelling content and clear navigation in the above-the-fold area encourage users to interact with the site and explore additional content. +4. [Mobile Experience](https://www.notion.so/Mobile-Experience-52b662b97cd44cf2964765ea865b1008?pvs=21): Given limited screen space on mobile devices, effective use of above-the-fold content becomes even more critical for user engagement. +5. Conversion Optimization: Placing relevant calls to action above the fold can enhance conversion rates by making them immediately visible to users. + +## Commonly Confused For + +Above the fold is sometimes confused with the main content area. While the main content area includes all content on a webpage, above the fold specifically refers to what is visible without scrolling. \ No newline at end of file diff --git a/glossary/terms/accessibility.md b/glossary/terms/accessibility.md new file mode 100644 index 0000000..716b544 --- /dev/null +++ b/glossary/terms/accessibility.md @@ -0,0 +1,22 @@ +# Accessibility +> Designing for equal digital access for all users. + +## Definition + +Accessibility refers to the design and development of digital content, websites, and applications that are usable by people with disabilities. It aims to provide equal access and a seamless user experience for individuals with various impairments, including visual, auditory, motor, and cognitive disabilities. + +## Real Life Example + +A website with accessibility features might include alternative text for images, keyboard navigation support, and subtitles for videos to accommodate users with diverse needs. + +## Why It’s Important + +1. Inclusivity: Accessibility ensures that digital content can be used by everyone, regardless of their disabilities or impairments. +2. Legal and Ethical Compliance: Many countries have accessibility laws that mandate equal access to digital content, emphasizing its ethical importance. +3. Enhanced User Experience: Accessibility improvements often benefit all users by making content more readable, navigable, and usable. +4. SEO Benefits: Search engines value accessible websites, potentially improving search engine rankings and visibility. +5. Reputation and Brand: Demonstrating commitment to accessibility enhances a brand's reputation and aligns with social responsibility. + +## Commonly Confused For + +Accessibility is sometimes confused with usability. While usability focuses on creating user-friendly designs, accessibility specifically targets making designs usable by individuals with disabilities. \ No newline at end of file diff --git a/glossary/terms/admin.md b/glossary/terms/admin.md new file mode 100644 index 0000000..dd0944a --- /dev/null +++ b/glossary/terms/admin.md @@ -0,0 +1,22 @@ +# Admin (Dashboard) +> Backend interface for managing and controlling a WordPress website. + +## Definition + +The WordPress Admin, commonly referred to as the Dashboard, is the backend interface of a WordPress website where site administrators and editors manage and control various aspects of the site. It provides tools for content creation, customization, settings configuration, user management, and more, making it a central hub for site administration. + +## Real Life Example + +Through the WordPress Admin, site administrators can create new posts, install plugins, and modify the site's appearance. + +## Why It’s Important + +1. Content Management: The Dashboard allows users to create, edit, and organize content such as posts and pages. +2. Customization: Users can customize the site's appearance, themes, and menus through the Dashboard. +3. Plugins and Extensions: The Dashboard facilitates the installation, activation, and management of plugins and extensions. +4. User Management: Administrators can manage user roles, permissions, and access through the Dashboard. +5. Settings Configuration: Site-wide settings, including permalinks, reading options, and discussion settings, are configured through the Dashboard. + +## Commonly Confused For + +The WordPress Admin (Dashboard) can be confused with the frontend of the website. While the Dashboard is the backend management interface, the frontend is what visitors see when accessing the actual website. \ No newline at end of file diff --git a/glossary/terms/advanced-custom-fields.md b/glossary/terms/advanced-custom-fields.md new file mode 100644 index 0000000..f07c48a --- /dev/null +++ b/glossary/terms/advanced-custom-fields.md @@ -0,0 +1,22 @@ +# Advanced Custom Fields (ACF) +>WordPress plugin allowing the addition of custom content fields for enhanced content editing. + +## Definition + +Advanced Custom Fields (ACF) is a WordPress plugin that enables developers to easily extend and enhance content editing capabilities by adding custom fields to posts, pages, and custom post types. ACF provides a user-friendly interface for creating fields like text, images, select boxes, and more, offering flexibility in tailoring content management to specific needs. + +## Real Life Example + +A website developer uses ACF to create custom fields like "Product Price" and "Release Date" for a product listing. + +## Why It’s Important + +1. Content Flexibility: ACF empowers users to create diverse content structures beyond default post fields. +2. Tailored Content Management: Custom fields are designed to match the unique requirements of each project. +3. Non-Technical Editing: ACF simplifies content editing, reducing the need for manual code adjustments. +4. Consistency: ACF enforces consistent content formatting and data input across the site. +5. Data Presentation: Custom fields provide structured data that can be utilized in various ways, including templates and custom queries. + +## Commonly Confused For + +Advanced Custom Fields might be confused with regular custom fields in WordPress. ACF, however, enhances custom fields by offering a more intuitive interface and extensive features. \ No newline at end of file diff --git a/glossary/terms/alt-text.md b/glossary/terms/alt-text.md new file mode 100644 index 0000000..f087997 --- /dev/null +++ b/glossary/terms/alt-text.md @@ -0,0 +1,22 @@ +# Alt Text +>Descriptive text for images to enhance accessibility. + +## Definition + +Alt Text, short for "alternative text," is a descriptive text attribute added to an image element in HTML code. It serves as a text-based alternative for users who cannot see images, providing context and accessibility by describing the content and purpose of the image. + +## Real Life Example + +In a blog post, an image of a mountain landscape might have alt text that reads, "Scenic mountain landscape with snow-capped peaks and clear blue sky.” + +## Why It’s Important + +1. [Accessibility](https://www.notion.so/Accessibility-4097a93f82384bb2b2acceabfb58d7bd?pvs=21): Alt text ensures that users with visual impairments using screen readers can understand the image's content and context. +2. [SEO](https://www.notion.so/SEO-Search-Engine-Optimization-bfaba8fa435944b88b2ed82748eba960?pvs=21) Benefits: Search engines use alt text to understand and index images, potentially improving a website's search engine visibility. +3. Contextual Information: Alt text provides valuable information about images, enhancing the overall comprehension and user experience of the content. +4. Legal Compliance: Many countries require websites to provide accessible content, including images with proper alt text, to comply with accessibility laws. +5. Image Failure Handling: When images fail to load due to slow connections or other issues, alt text offers a fallback description to convey the image's purpose. + +## Commonly Confused For + +Alt text is sometimes confused with captions. While alt text provides a concise description of an image's content, captions provide additional context or explanations, often appearing directly below the image. \ No newline at end of file diff --git a/glossary/terms/analytics.md b/glossary/terms/analytics.md new file mode 100644 index 0000000..cedfaef --- /dev/null +++ b/glossary/terms/analytics.md @@ -0,0 +1,22 @@ +# Analytics +>Data-driven insights for informed decision-making. + +## Definition + +Analytics refers to the systematic collection, measurement, analysis, and interpretation of data to gain insights and make informed decisions. In the context of websites and online platforms, analytics involves tracking and examining various metrics and user behavior to understand website performance, audience engagement, and marketing effectiveness. + +## Real Life Example + +Website analytics can provide information on the number of visitors, popular pages, referral sources, conversion rates, and user demographics. By analyzing this data, website owners can make data-driven decisions to improve user experience, optimize marketing strategies, and drive business growth. + +## Why It’s Important + +1. Performance Measurement: Analytics allows website owners to track and assess key performance metrics, such as website traffic, page views, bounce rates, and conversion rates. This helps in evaluating the success of marketing campaigns, content engagement, and overall website effectiveness. +2. Audience Understanding: By analyzing user behavior, demographics, and preferences, analytics helps in gaining insights into the target audience. This information enables website owners to tailor their content, products, and services to better meet the needs and preferences of their users. +3. Goal Tracking: Analytics allows the tracking of specific goals or actions on a website, such as form submissions, purchases, or newsletter sign-ups. This helps in measuring the effectiveness of marketing efforts and optimizing conversion funnels. +4. User Experience Optimization: By analyzing user interactions, navigation patterns, and feedback, analytics helps in identifying areas of improvement in the user experience. This enables website owners to make informed design and functionality decisions to enhance user satisfaction and engagement. +5. Data-Driven Decision-Making: Analytics provides actionable insights based on data, allowing website owners to make informed decisions rather than relying on assumptions or guesswork. This helps in optimizing marketing strategies, improving website performance, and driving business growth. + +## Commonly Confused For + +Analytics is sometimes confused with reporting. While reporting focuses on presenting data in a summarized and visual format, analytics involves the deeper analysis, interpretation, and extraction of insights from the data. \ No newline at end of file diff --git a/glossary/terms/api.md b/glossary/terms/api.md new file mode 100644 index 0000000..7294ec5 --- /dev/null +++ b/glossary/terms/api.md @@ -0,0 +1,31 @@ +# API (Application Programming Interface) +>Software communication bridge. + +## Definition + +An API, short for Application Programming Interface, acts as a bridge that allows different software applications to communicate and interact with each other. It specifies a set of rules and protocols that govern how different components of software systems should interact. Think of it as a waiter at a restaurant who takes your order and conveys it to the kitchen, bringing you back the requested dish. + +## Real Life Example + +Imagine you have a website that needs to display real-time weather information. Instead of manually collecting and updating the weather data yourself, you can use a weather API. By integrating the weather API into your website's code, you can automatically retrieve up-to-date weather information and display it to your visitors without having to manage the data yourself. + +In this example, the API acts as a messenger between your website and the weather data provider, allowing your website to access the requested information and provide a seamless user experience. + +Remember, an API enables different software components to work together, simplifying complex processes and enhancing functionality in a way that's both efficient and reliable. + +## Why you might need it + +1. Enhanced Functionality: APIs allow you to incorporate additional functionality into your website without having to build everything from scratch. By integrating APIs, you can leverage existing services and features, such as payment gateways, social media sharing, or mapping services, to enhance the capabilities of your website. +2. Real-Time Data Integration: APIs enable you to retrieve and display real-time data on your website. For example, you can integrate weather APIs to display current weather conditions, stock market APIs to show live stock prices, or news APIs to provide up-to-date news articles. This helps keep your website content fresh and relevant. +3. Streamlined Content Management: APIs can simplify content management by allowing you to connect your website with external platforms or content management systems. For instance, you can integrate APIs provided by popular social media platforms to automatically publish your website's content on social media channels, saving you time and effort. +4. Seamless Third-Party Service Integration: If you rely on third-party services, such as email marketing tools, customer relationship management (CRM) systems, or e-commerce platforms, APIs enable smooth integration between these services and your website. This integration facilitates data exchange, automates processes, and ensures a seamless user experience. +5. Custom Functionality: APIs provide you with the flexibility to create custom functionality tailored to your specific needs. You can use APIs to build custom features, such as custom search engines, data analytics, or custom integrations with specialized services that are not readily available as plugins or extensions. + +## Commonly Confused For + +1. SDK (Software Development Kit): An SDK is a collection of tools, libraries, and documentation that developers use to build software applications for a specific platform or framework. While APIs and SDKs are related, they serve different purposes. An API defines how different software components can interact, while an SDK provides developers with the tools and resources to build applications using a specific platform or framework, which may include APIs. +2. Framework: A framework is a set of pre-written code, libraries, and tools that provide a foundation for building software applications. While frameworks may include APIs, they encompass a broader scope. Frameworks typically provide a structure and guidelines for developing applications, including predefined functions and modules that developers can use to build upon. +3. Library: A library is a collection of pre-compiled code modules or functions that developers can use to perform specific tasks. Libraries often provide ready-made functions or classes that developers can call within their code to achieve certain functionalities. While libraries may utilize APIs internally, they are distinct from APIs themselves. +4. CMS (Content Management System): A CMS is a software application or platform used for managing digital content, such as websites, blogs, or online stores. While some CMSs may have APIs that allow developers to extend their functionality or integrate with external systems, the CMS itself is not an API. The API of a CMS would be a specific interface or set of endpoints that developers can use to interact with and manage the CMS's content. + +It's important to distinguish these terms to avoid confusion and ensure accurate communication when discussing development concepts and requirements. APIs, SDKs, frameworks, libraries, and CMSs each have distinct roles and functionalities in the development process. \ No newline at end of file diff --git a/settings/Parsedown.php b/settings/Parsedown.php new file mode 100644 index 0000000..1b9d6d5 --- /dev/null +++ b/settings/Parsedown.php @@ -0,0 +1,1712 @@ +DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + function setSafeMode($safeMode) + { + $this->safeMode = (bool) $safeMode; + + return $this; + } + + protected $safeMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) + { + foreach ($this->BlockTypes[$marker] as $blockType) + { + $blockTypes []= $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) + { + $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); + + if (isset($Block)) + { + $Block['type'] = $blockType; + + if ( ! isset($Block['identified'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block'.$Type.'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block'.$Type.'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + /** + * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes + * Every HTML element may have a class attribute specified. + * The attribute, if specified, must have a value that is a set + * of space-separated tokens representing the various classes + * that the element belongs to. + * [...] + * The space characters, for the purposes of this specification, + * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), + * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and + * U+000D CARRIAGE RETURN (CR). + */ + $language = substr($matches[1], 0, strcspn($matches[1], " \t\n\f\r")); + + $class = 'language-'.$language; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + if($name === 'ol') + { + $listStart = stristr($matches[0], '.', true); + + if($listStart !== '1') + { + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (chop($Line['text'], $Line['text'][0]) === '') + { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + if (isset($alignments[$index])) + { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => 'text-align: '.$alignment.';', + ); + } + + $HeaderElements []= $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables=array()) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) + { + # check to see if the current inline type is nestable in the current context + + if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + continue; + } + + $Inline = $this->{'inline'.$inlineType}($Excerpt); + + if ( ! isset($Inline)) + { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) + { + continue; + } + + # sets a default inline position + + if ( ! isset($Inline['position'])) + { + $Inline['position'] = $markerPosition; + } + + # cause the new element to 'inherit' our non nestables + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + if ( ! isset($matches[2])) + { + $url = 'mailto:' . $url; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'strong'; + } + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'em'; + } + else + { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $Excerpt['text'][1], + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') + { + return; + } + + $Excerpt['text']= substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) + { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + { + $Element['text'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) + { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) + { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + protected function inlineStrikethrough($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) + { + $url = $matches[0][0]; + + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + + $markup = '<'.$Element['name']; + + if (isset($Element['attributes'])) + { + foreach ($Element['attributes'] as $name => $value) + { + if ($value === null) + { + continue; + } + + $markup .= ' '.$name.'="'.self::escape($value).'"'; + } + } + + $permitRawHtml = false; + + if (isset($Element['text'])) + { + $text = $Element['text']; + } + // very strongly consider an alternative if you're writing an + // extension + elseif (isset($Element['rawHtml'])) + { + $text = $Element['rawHtml']; + $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; + $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; + } + + if (isset($text)) + { + $markup .= '>'; + + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($text, $Element['nonNestables']); + } + elseif (!$permitRawHtml) + { + $markup .= self::escape($text, true); + } + else + { + $markup .= $text; + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (isset($safeUrlNameToAtt[$Element['name']])) + { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if ( ! empty($Element['attributes'])) + { + foreach ($Element['attributes'] as $att => $val) + { + # filter out badly parsed attribute + if ( ! preg_match($goodAttribute, $att)) + { + unset($Element['attributes'][$att]); + } + # dump onevent attribute + elseif (self::striAtStart($att, 'on')) + { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) + { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) + { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + + # + # Static Methods + # + + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) + { + return false; + } + else + { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) + { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'kbd', 'mark', + 'u', 'xm', 'sub', 'nobr', + 'sup', 'ruby', + 'var', 'span', + 'wbr', 'time', + ); +} diff --git a/settings/settings.php b/settings/settings.php index 1641857..2224dd8 100644 --- a/settings/settings.php +++ b/settings/settings.php @@ -1,25 +1,6 @@ * @since 1.0.0 */ -function add_wds_documentation_dashboard_page() { - add_submenu_page( - 'options-general.php', - 'Site Documentation', - 'Documentation', +function add_wds_documentation_settings_page() { + add_menu_page( + __( 'Theme Help', 'textdomain' ), + 'Theme Help', 'manage_options', - 'wds_documentation', + 'wds_documentation', __NAMESPACE__ . '\wds_documentation_dashboard', - 100 + '', + 6 + ); + ## Add two submenu pages. One called Glossary and one called Settings + add_submenu_page( + 'wds_documentation', + __( 'Glossary', 'textdomain' ), + __( 'Glossary', 'textdomain' ), + 'manage_options', + 'wds_documentation_glossary', + __NAMESPACE__ . '\wds_documentation_glossary' ); } +add_action( 'admin_menu', __NAMESPACE__ . '\add_wds_documentation_settings_page' ); /** * Output the dashboard page for documentation @@ -96,8 +87,6 @@ function wds_documentation_dashboard() { * @since 1.1.1 @@ -91,8 +91,11 @@ function add_toolbar_items( $admin_bar ) { add_action( 'admin_bar_menu', __NAMESPACE__ . '\add_toolbar_items', 100 ); /** - * Create a Documentation navigation section. + * Enqueues the plugin styles. * - * @author Ashley Stanley - * @since 1.1.1 - */ \ No newline at end of file + * @throws Exception If the plugin styles cannot be enqueued. + */ +function enqueue_plugin_styles() { + wp_enqueue_style('plugin-style', plugin_dir_url(__FILE__) . 'style.css'); +} +add_action('admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_plugin_styles'); \ No newline at end of file