`, and ``.
+@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
+@font-family-base: @font-family-sans-serif;
+
+@font-size-base: 14px;
+@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
+@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
+
+@font-size-h1: floor((@font-size-base * 2.6)); // ~36px
+@font-size-h2: floor((@font-size-base * 2.15)); // ~30px
+@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px
+@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px
+@font-size-h5: @font-size-base;
+@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+@line-height-base: 1.428571429; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
+
+//** By default, this inherits from the ``.
+@headings-font-family: inherit;
+@headings-font-weight: 500;
+@headings-line-height: 1.1;
+@headings-color: inherit;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+@icon-font-path: "../fonts/";
+//** File name for all font files.
+@icon-font-name: "glyphicons-halflings-regular";
+//** Element ID within SVG icon file.
+@icon-font-svg-id: "glyphicons_halflingsregular";
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+@padding-base-vertical: 6px;
+@padding-base-horizontal: 12px;
+
+@padding-large-vertical: 10px;
+@padding-large-horizontal: 16px;
+
+@padding-small-vertical: 5px;
+@padding-small-horizontal: 10px;
+
+@padding-xs-vertical: 1px;
+@padding-xs-horizontal: 5px;
+
+@line-height-large: 1.33;
+@line-height-small: 1.5;
+
+@border-radius-base: 4px;
+@border-radius-large: 6px;
+@border-radius-small: 3px;
+
+//** Global color for active items (e.g., navs or dropdowns).
+@component-active-color: #fff;
+//** Global background color for active items (e.g., navs or dropdowns).
+@component-active-bg: @brand-primary;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+@caret-width-base: 4px;
+//** Carets increase slightly in size for larger components.
+@caret-width-large: 5px;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for ``s and ` `s.
+@table-cell-padding: 8px;
+//** Padding for cells in `.table-condensed`.
+@table-condensed-cell-padding: 5px;
+
+//** Default background color used for all tables.
+@table-bg: transparent;
+//** Background color used for `.table-striped`.
+@table-bg-accent: #f9f9f9;
+//** Background color used for `.table-hover`.
+@table-bg-hover: #f5f5f5;
+@table-bg-active: @table-bg-hover;
+
+//** Border color for table and cell borders.
+@table-border-color: #ddd;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+@btn-font-weight: normal;
+
+@btn-default-color: #333;
+@btn-default-bg: #fff;
+@btn-default-border: #ccc;
+
+@btn-primary-color: #fff;
+@btn-primary-bg: @brand-primary;
+@btn-primary-border: darken(@btn-primary-bg, 5%);
+
+@btn-success-color: #fff;
+@btn-success-bg: @brand-success;
+@btn-success-border: darken(@btn-success-bg, 5%);
+
+@btn-info-color: #fff;
+@btn-info-bg: @brand-info;
+@btn-info-border: darken(@btn-info-bg, 5%);
+
+@btn-warning-color: #fff;
+@btn-warning-bg: @brand-warning;
+@btn-warning-border: darken(@btn-warning-bg, 5%);
+
+@btn-danger-color: #fff;
+@btn-danger-bg: @brand-danger;
+@btn-danger-border: darken(@btn-danger-bg, 5%);
+
+@btn-link-disabled-color: @gray-light;
+
+
+//== Forms
+//
+//##
+
+//** ` ` background color
+@input-bg: #fff;
+//** ` ` background color
+@input-bg-disabled: @gray-lighter;
+
+//** Text color for ` `s
+@input-color: @gray;
+//** ` ` border color
+@input-border: #ccc;
+//** ` ` border radius
+@input-border-radius: @border-radius-base;
+//** Border color for inputs on focus
+@input-border-focus: #66afe9;
+
+//** Placeholder text color
+@input-color-placeholder: @gray-light;
+
+//** Default `.form-control` height
+@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
+//** Large `.form-control` height
+@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
+//** Small `.form-control` height
+@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
+
+@legend-color: @gray-dark;
+@legend-border-color: #e5e5e5;
+
+//** Background color for textual input addons
+@input-group-addon-bg: @gray-lighter;
+//** Border color for textual input addons
+@input-group-addon-border-color: @input-border;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+@dropdown-bg: #fff;
+//** Dropdown menu `border-color`.
+@dropdown-border: rgba(0,0,0,.15);
+//** Dropdown menu `border-color` **for IE8**.
+@dropdown-fallback-border: #ccc;
+//** Divider color for between dropdown items.
+@dropdown-divider-bg: #e5e5e5;
+
+//** Dropdown link text color.
+@dropdown-link-color: @gray-dark;
+//** Hover color for dropdown links.
+@dropdown-link-hover-color: darken(@gray-dark, 5%);
+//** Hover background for dropdown links.
+@dropdown-link-hover-bg: #f5f5f5;
+
+//** Active dropdown menu item text color.
+@dropdown-link-active-color: @component-active-color;
+//** Active dropdown menu item background color.
+@dropdown-link-active-bg: @component-active-bg;
+
+//** Disabled dropdown menu item background color.
+@dropdown-link-disabled-color: @gray-light;
+
+//** Text color for headers within dropdown menus.
+@dropdown-header-color: @gray-light;
+
+//** Deprecated `@dropdown-caret-color` as of v3.1.0
+@dropdown-caret-color: #000;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+@zindex-navbar: 1000;
+@zindex-dropdown: 1000;
+@zindex-popover: 1060;
+@zindex-tooltip: 1070;
+@zindex-navbar-fixed: 1030;
+@zindex-modal-background: 1040;
+@zindex-modal: 1050;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `@screen-xs` as of v3.0.1
+@screen-xs: 480px;
+//** Deprecated `@screen-xs-min` as of v3.2.0
+@screen-xs-min: @screen-xs;
+//** Deprecated `@screen-phone` as of v3.0.1
+@screen-phone: @screen-xs-min;
+
+// Small screen / tablet
+//** Deprecated `@screen-sm` as of v3.0.1
+@screen-sm: 768px;
+@screen-sm-min: @screen-sm;
+//** Deprecated `@screen-tablet` as of v3.0.1
+@screen-tablet: @screen-sm-min;
+
+// Medium screen / desktop
+//** Deprecated `@screen-md` as of v3.0.1
+@screen-md: 992px;
+@screen-md-min: @screen-md;
+//** Deprecated `@screen-desktop` as of v3.0.1
+@screen-desktop: @screen-md-min;
+
+// Large screen / wide desktop
+//** Deprecated `@screen-lg` as of v3.0.1
+@screen-lg: 1200px;
+@screen-lg-min: @screen-lg;
+//** Deprecated `@screen-lg-desktop` as of v3.0.1
+@screen-lg-desktop: @screen-lg-min;
+
+// So media queries don't overlap when required, provide a maximum
+@screen-xs-max: (@screen-sm-min - 1);
+@screen-sm-max: (@screen-md-min - 1);
+@screen-md-max: (@screen-lg-min - 1);
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+@grid-columns: 12;
+//** Padding between columns. Gets divided in half for the left and right.
+@grid-gutter-width: 30px;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+@grid-float-breakpoint: @screen-sm-min;
+//** Point at which the navbar begins collapsing.
+@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+@container-tablet: ((720px + @grid-gutter-width));
+//** For `@screen-sm-min` and up.
+@container-sm: @container-tablet;
+
+// Medium screen / desktop
+@container-desktop: ((940px + @grid-gutter-width));
+//** For `@screen-md-min` and up.
+@container-md: @container-desktop;
+
+// Large screen / wide desktop
+@container-large-desktop: ((1140px + @grid-gutter-width));
+//** For `@screen-lg-min` and up.
+@container-lg: @container-large-desktop;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+@navbar-height: 50px;
+@navbar-margin-bottom: @line-height-computed;
+@navbar-border-radius: @border-radius-base;
+@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
+@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
+@navbar-collapse-max-height: 340px;
+
+@navbar-default-color: #777;
+@navbar-default-bg: #f8f8f8;
+@navbar-default-border: darken(@navbar-default-bg, 6.5%);
+
+// Navbar links
+@navbar-default-link-color: #777;
+@navbar-default-link-hover-color: #333;
+@navbar-default-link-hover-bg: transparent;
+@navbar-default-link-active-color: #555;
+@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
+@navbar-default-link-disabled-color: #ccc;
+@navbar-default-link-disabled-bg: transparent;
+
+// Navbar brand label
+@navbar-default-brand-color: @navbar-default-link-color;
+@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);
+@navbar-default-brand-hover-bg: transparent;
+
+// Navbar toggle
+@navbar-default-toggle-hover-bg: #ddd;
+@navbar-default-toggle-icon-bar-bg: #888;
+@navbar-default-toggle-border-color: #ddd;
+
+
+// Inverted navbar
+// Reset inverted navbar basics
+@navbar-inverse-color: @gray-light;
+@navbar-inverse-bg: #222;
+@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
+
+// Inverted navbar links
+@navbar-inverse-link-color: @gray-light;
+@navbar-inverse-link-hover-color: #fff;
+@navbar-inverse-link-hover-bg: transparent;
+@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
+@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
+@navbar-inverse-link-disabled-color: #444;
+@navbar-inverse-link-disabled-bg: transparent;
+
+// Inverted navbar brand label
+@navbar-inverse-brand-color: @navbar-inverse-link-color;
+@navbar-inverse-brand-hover-color: #fff;
+@navbar-inverse-brand-hover-bg: transparent;
+
+// Inverted navbar toggle
+@navbar-inverse-toggle-hover-bg: #333;
+@navbar-inverse-toggle-icon-bar-bg: #fff;
+@navbar-inverse-toggle-border-color: #333;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+@nav-link-padding: 10px 15px;
+@nav-link-hover-bg: @gray-lighter;
+
+@nav-disabled-link-color: @gray-light;
+@nav-disabled-link-hover-color: @gray-light;
+
+@nav-open-link-hover-color: #fff;
+
+//== Tabs
+@nav-tabs-border-color: #ddd;
+
+@nav-tabs-link-hover-border-color: @gray-lighter;
+
+@nav-tabs-active-link-hover-bg: @body-bg;
+@nav-tabs-active-link-hover-color: @gray;
+@nav-tabs-active-link-hover-border-color: #ddd;
+
+@nav-tabs-justified-link-border-color: #ddd;
+@nav-tabs-justified-active-link-border-color: @body-bg;
+
+//== Pills
+@nav-pills-border-radius: @border-radius-base;
+@nav-pills-active-link-hover-bg: @component-active-bg;
+@nav-pills-active-link-hover-color: @component-active-color;
+
+
+//== Pagination
+//
+//##
+
+@pagination-color: @link-color;
+@pagination-bg: #fff;
+@pagination-border: #ddd;
+
+@pagination-hover-color: @link-hover-color;
+@pagination-hover-bg: @gray-lighter;
+@pagination-hover-border: #ddd;
+
+@pagination-active-color: #fff;
+@pagination-active-bg: @brand-primary;
+@pagination-active-border: @brand-primary;
+
+@pagination-disabled-color: @gray-light;
+@pagination-disabled-bg: #fff;
+@pagination-disabled-border: #ddd;
+
+
+//== Pager
+//
+//##
+
+@pager-bg: @pagination-bg;
+@pager-border: @pagination-border;
+@pager-border-radius: 15px;
+
+@pager-hover-bg: @pagination-hover-bg;
+
+@pager-active-bg: @pagination-active-bg;
+@pager-active-color: @pagination-active-color;
+
+@pager-disabled-color: @pagination-disabled-color;
+
+
+//== Jumbotron
+//
+//##
+
+@jumbotron-padding: 30px;
+@jumbotron-color: inherit;
+@jumbotron-bg: @gray-lighter;
+@jumbotron-heading-color: inherit;
+@jumbotron-font-size: ceil((@font-size-base * 1.5));
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+@state-success-text: #3c763d;
+@state-success-bg: #dff0d8;
+@state-success-border: darken(spin(@state-success-bg, -10), 5%);
+
+@state-info-text: #31708f;
+@state-info-bg: #d9edf7;
+@state-info-border: darken(spin(@state-info-bg, -10), 7%);
+
+@state-warning-text: #8a6d3b;
+@state-warning-bg: #fcf8e3;
+@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
+
+@state-danger-text: #a94442;
+@state-danger-bg: #f2dede;
+@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+@tooltip-max-width: 200px;
+//** Tooltip text color
+@tooltip-color: #fff;
+//** Tooltip background color
+@tooltip-bg: #000;
+@tooltip-opacity: .9;
+
+//** Tooltip arrow width
+@tooltip-arrow-width: 5px;
+//** Tooltip arrow color
+@tooltip-arrow-color: @tooltip-bg;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+@popover-bg: #fff;
+//** Popover maximum width
+@popover-max-width: 276px;
+//** Popover border color
+@popover-border-color: rgba(0,0,0,.2);
+//** Popover fallback border color
+@popover-fallback-border-color: #ccc;
+
+//** Popover title background color
+@popover-title-bg: darken(@popover-bg, 3%);
+
+//** Popover arrow width
+@popover-arrow-width: 10px;
+//** Popover arrow color
+@popover-arrow-color: #fff;
+
+//** Popover outer arrow width
+@popover-arrow-outer-width: (@popover-arrow-width + 1);
+//** Popover outer arrow color
+@popover-arrow-outer-color: fadein(@popover-border-color, 5%);
+//** Popover outer arrow fallback color
+@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+@label-default-bg: @gray-light;
+//** Primary label background color
+@label-primary-bg: @brand-primary;
+//** Success label background color
+@label-success-bg: @brand-success;
+//** Info label background color
+@label-info-bg: @brand-info;
+//** Warning label background color
+@label-warning-bg: @brand-warning;
+//** Danger label background color
+@label-danger-bg: @brand-danger;
+
+//** Default label text color
+@label-color: #fff;
+//** Default text color of a linked label
+@label-link-hover-color: #fff;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+@modal-inner-padding: 15px;
+
+//** Padding applied to the modal title
+@modal-title-padding: 15px;
+//** Modal title line-height
+@modal-title-line-height: @line-height-base;
+
+//** Background color of modal content area
+@modal-content-bg: #fff;
+//** Modal content border color
+@modal-content-border-color: rgba(0,0,0,.2);
+//** Modal content border color **for IE8**
+@modal-content-fallback-border-color: #999;
+
+//** Modal backdrop background color
+@modal-backdrop-bg: #000;
+//** Modal backdrop opacity
+@modal-backdrop-opacity: .5;
+//** Modal header border color
+@modal-header-border-color: #e5e5e5;
+//** Modal footer border color
+@modal-footer-border-color: @modal-header-border-color;
+
+@modal-lg: 900px;
+@modal-md: 600px;
+@modal-sm: 300px;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+@alert-padding: 15px;
+@alert-border-radius: @border-radius-base;
+@alert-link-font-weight: bold;
+
+@alert-success-bg: @state-success-bg;
+@alert-success-text: @state-success-text;
+@alert-success-border: @state-success-border;
+
+@alert-info-bg: @state-info-bg;
+@alert-info-text: @state-info-text;
+@alert-info-border: @state-info-border;
+
+@alert-warning-bg: @state-warning-bg;
+@alert-warning-text: @state-warning-text;
+@alert-warning-border: @state-warning-border;
+
+@alert-danger-bg: @state-danger-bg;
+@alert-danger-text: @state-danger-text;
+@alert-danger-border: @state-danger-border;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+@progress-bg: #f5f5f5;
+//** Progress bar text color
+@progress-bar-color: #fff;
+
+//** Default progress bar color
+@progress-bar-bg: @brand-primary;
+//** Success progress bar color
+@progress-bar-success-bg: @brand-success;
+//** Warning progress bar color
+@progress-bar-warning-bg: @brand-warning;
+//** Danger progress bar color
+@progress-bar-danger-bg: @brand-danger;
+//** Info progress bar color
+@progress-bar-info-bg: @brand-info;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+@list-group-bg: #fff;
+//** `.list-group-item` border color
+@list-group-border: #ddd;
+//** List group border radius
+@list-group-border-radius: @border-radius-base;
+
+//** Background color of single list items on hover
+@list-group-hover-bg: #f5f5f5;
+//** Text color of active list items
+@list-group-active-color: @component-active-color;
+//** Background color of active list items
+@list-group-active-bg: @component-active-bg;
+//** Border color of active list elements
+@list-group-active-border: @list-group-active-bg;
+//** Text color for content within active list items
+@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
+
+//** Text color of disabled list items
+@list-group-disabled-color: @gray-light;
+//** Background color of disabled list items
+@list-group-disabled-bg: @gray-lighter;
+//** Text color for content within disabled list items
+@list-group-disabled-text-color: @list-group-disabled-color;
+
+@list-group-link-color: #555;
+@list-group-link-hover-color: @list-group-link-color;
+@list-group-link-heading-color: #333;
+
+
+//== Panels
+//
+//##
+
+@panel-bg: #fff;
+@panel-body-padding: 15px;
+@panel-heading-padding: 10px 15px;
+@panel-footer-padding: @panel-heading-padding;
+@panel-border-radius: @border-radius-base;
+
+//** Border color for elements within panels
+@panel-inner-border: #ddd;
+@panel-footer-bg: #f5f5f5;
+
+@panel-default-text: @gray-dark;
+@panel-default-border: #ddd;
+@panel-default-heading-bg: #f5f5f5;
+
+@panel-primary-text: #fff;
+@panel-primary-border: @brand-primary;
+@panel-primary-heading-bg: @brand-primary;
+
+@panel-success-text: @state-success-text;
+@panel-success-border: @state-success-border;
+@panel-success-heading-bg: @state-success-bg;
+
+@panel-info-text: @state-info-text;
+@panel-info-border: @state-info-border;
+@panel-info-heading-bg: @state-info-bg;
+
+@panel-warning-text: @state-warning-text;
+@panel-warning-border: @state-warning-border;
+@panel-warning-heading-bg: @state-warning-bg;
+
+@panel-danger-text: @state-danger-text;
+@panel-danger-border: @state-danger-border;
+@panel-danger-heading-bg: @state-danger-bg;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+@thumbnail-padding: 4px;
+//** Thumbnail background color
+@thumbnail-bg: @body-bg;
+//** Thumbnail border color
+@thumbnail-border: #ddd;
+//** Thumbnail border radius
+@thumbnail-border-radius: @border-radius-base;
+
+//** Custom text color for thumbnail captions
+@thumbnail-caption-color: @text-color;
+//** Padding around the thumbnail caption
+@thumbnail-caption-padding: 9px;
+
+
+//== Wells
+//
+//##
+
+@well-bg: #f5f5f5;
+@well-border: darken(@well-bg, 7%);
+
+
+//== Badges
+//
+//##
+
+@badge-color: #fff;
+//** Linked badge text color on hover
+@badge-link-hover-color: #fff;
+@badge-bg: @gray-light;
+
+//** Badge text color in active nav link
+@badge-active-color: @link-color;
+//** Badge background color in active nav link
+@badge-active-bg: #fff;
+
+@badge-font-weight: bold;
+@badge-line-height: 1;
+@badge-border-radius: 10px;
+
+
+//== Breadcrumbs
+//
+//##
+
+@breadcrumb-padding-vertical: 8px;
+@breadcrumb-padding-horizontal: 15px;
+//** Breadcrumb background color
+@breadcrumb-bg: #f5f5f5;
+//** Breadcrumb text color
+@breadcrumb-color: #ccc;
+//** Text color of current page in the breadcrumb
+@breadcrumb-active-color: @gray-light;
+//** Textual separator for between breadcrumb elements
+@breadcrumb-separator: "/";
+
+
+//== Carousel
+//
+//##
+
+@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
+
+@carousel-control-color: #fff;
+@carousel-control-width: 15%;
+@carousel-control-opacity: .5;
+@carousel-control-font-size: 20px;
+
+@carousel-indicator-active-bg: #fff;
+@carousel-indicator-border-color: #fff;
+
+@carousel-caption-color: #fff;
+
+
+//== Close
+//
+//##
+
+@close-font-weight: bold;
+@close-color: #000;
+@close-text-shadow: 0 1px 0 #fff;
+
+
+//== Code
+//
+//##
+
+@code-color: #c7254e;
+@code-bg: #f9f2f4;
+
+@kbd-color: #fff;
+@kbd-bg: #333;
+
+@pre-bg: #f5f5f5;
+@pre-color: @gray-dark;
+@pre-border-color: #ccc;
+@pre-scrollable-max-height: 340px;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+@component-offset-horizontal: 180px;
+//** Text muted color
+@text-muted: @gray-light;
+//** Abbreviations and acronyms border color
+@abbr-border-color: @gray-light;
+//** Headings small color
+@headings-small-color: @gray-light;
+//** Blockquote small color
+@blockquote-small-color: @gray-light;
+//** Blockquote font size
+@blockquote-font-size: (@font-size-base * 1.25);
+//** Blockquote border color
+@blockquote-border-color: @gray-lighter;
+//** Page header border color
+@page-header-border-color: @gray-lighter;
+//** Width of horizontal description list titles
+@dl-horizontal-offset: @component-offset-horizontal;
+//** Horizontal line color.
+@hr-border: @gray-lighter;
+
+
diff --git a/plugins/system/t3/base-bs3/bootstrap/less/wells.less b/plugins/system/t3/base-bs3/bootstrap/less/wells.less
new file mode 100644
index 0000000..15d072b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/bootstrap/less/wells.less
@@ -0,0 +1,29 @@
+//
+// Wells
+// --------------------------------------------------
+
+
+// Base class
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: @well-bg;
+ border: 1px solid @well-border;
+ border-radius: @border-radius-base;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
+ blockquote {
+ border-color: #ddd;
+ border-color: rgba(0,0,0,.15);
+ }
+}
+
+// Sizes
+.well-lg {
+ padding: 24px;
+ border-radius: @border-radius-large;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: @border-radius-small;
+}
diff --git a/plugins/system/t3/base-bs3/component.php b/plugins/system/t3/base-bs3/component.php
new file mode 100644
index 0000000..1c7f1d4
--- /dev/null
+++ b/plugins/system/t3/base-bs3/component.php
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/css/layout-preview.css b/plugins/system/t3/base-bs3/css/layout-preview.css
new file mode 100644
index 0000000..4e2aa63
--- /dev/null
+++ b/plugins/system/t3/base-bs3/css/layout-preview.css
@@ -0,0 +1,835 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+.t3-admin-layout-preview {
+ width: 600px;
+ max-width: 100%;
+}
+.t3-admin-layout-preview *,
+.t3-admin-layout-preview *:before,
+.t3-admin-layout-preview *:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.t3-admin-layout-preview .wrap {
+ width: auto;
+ clear: both;
+}
+.t3-admin-layout-preview .container {
+ width: 100%;
+}
+.t3-admin-layout-preview .t3-admin-layout-section:before,
+.t3-admin-layout-preview header:before,
+.t3-admin-layout-preview footer:before,
+.t3-admin-layout-preview section:before,
+.t3-admin-layout-preview nav:before,
+.t3-admin-layout-preview .t3-spotlight:before,
+.t3-admin-layout-preview .t3-content:before,
+.t3-admin-layout-preview .t3-sidebar:before,
+.t3-admin-layout-preview .t3-mastcol:before,
+.t3-admin-layout-preview .t3-admin-layout-section:after,
+.t3-admin-layout-preview header:after,
+.t3-admin-layout-preview footer:after,
+.t3-admin-layout-preview section:after,
+.t3-admin-layout-preview nav:after,
+.t3-admin-layout-preview .t3-spotlight:after,
+.t3-admin-layout-preview .t3-content:after,
+.t3-admin-layout-preview .t3-sidebar:after,
+.t3-admin-layout-preview .t3-mastcol:after {
+ content: " ";
+ /* 1 */
+
+ display: table;
+ /* 2 */
+
+}
+.t3-admin-layout-preview .t3-admin-layout-section:after,
+.t3-admin-layout-preview header:after,
+.t3-admin-layout-preview footer:after,
+.t3-admin-layout-preview section:after,
+.t3-admin-layout-preview nav:after,
+.t3-admin-layout-preview .t3-spotlight:after,
+.t3-admin-layout-preview .t3-content:after,
+.t3-admin-layout-preview .t3-sidebar:after,
+.t3-admin-layout-preview .t3-mastcol:after {
+ clear: both;
+}
+.t3-admin-layout-preview .row {
+ margin-left: -6px;
+ margin-right: -6px;
+}
+.t3-admin-layout-preview .row:before,
+.t3-admin-layout-preview .row:after {
+ content: " ";
+ /* 1 */
+
+ display: table;
+ /* 2 */
+
+}
+.t3-admin-layout-preview .row:after {
+ clear: both;
+}
+.t3-admin-layout-preview .col-xs-1,
+.t3-admin-layout-preview .col-xs-2,
+.t3-admin-layout-preview .col-xs-3,
+.t3-admin-layout-preview .col-xs-4,
+.t3-admin-layout-preview .col-xs-5,
+.t3-admin-layout-preview .col-xs-6,
+.t3-admin-layout-preview .col-xs-7,
+.t3-admin-layout-preview .col-xs-8,
+.t3-admin-layout-preview .col-xs-9,
+.t3-admin-layout-preview .col-xs-10,
+.t3-admin-layout-preview .col-xs-11,
+.t3-admin-layout-preview .col-xs-12,
+.t3-admin-layout-preview .col-sm-1,
+.t3-admin-layout-preview .col-sm-2,
+.t3-admin-layout-preview .col-sm-3,
+.t3-admin-layout-preview .col-sm-4,
+.t3-admin-layout-preview .col-sm-5,
+.t3-admin-layout-preview .col-sm-6,
+.t3-admin-layout-preview .col-sm-7,
+.t3-admin-layout-preview .col-sm-8,
+.t3-admin-layout-preview .col-sm-9,
+.t3-admin-layout-preview .col-sm-10,
+.t3-admin-layout-preview .col-sm-11,
+.t3-admin-layout-preview .col-sm-12,
+.t3-admin-layout-preview .col-md-1,
+.t3-admin-layout-preview .col-md-2,
+.t3-admin-layout-preview .col-md-3,
+.t3-admin-layout-preview .col-md-4,
+.t3-admin-layout-preview .col-md-5,
+.t3-admin-layout-preview .col-md-6,
+.t3-admin-layout-preview .col-md-7,
+.t3-admin-layout-preview .col-md-8,
+.t3-admin-layout-preview .col-md-9,
+.t3-admin-layout-preview .col-md-10,
+.t3-admin-layout-preview .col-md-11,
+.t3-admin-layout-preview .col-md-12,
+.t3-admin-layout-preview .col-lg-1,
+.t3-admin-layout-preview .col-lg-2,
+.t3-admin-layout-preview .col-lg-3,
+.t3-admin-layout-preview .col-lg-4,
+.t3-admin-layout-preview .col-lg-5,
+.t3-admin-layout-preview .col-lg-6,
+.t3-admin-layout-preview .col-lg-7,
+.t3-admin-layout-preview .col-lg-8,
+.t3-admin-layout-preview .col-lg-9,
+.t3-admin-layout-preview .col-lg-10,
+.t3-admin-layout-preview .col-lg-11,
+.t3-admin-layout-preview .col-lg-12 {
+ position: relative;
+ min-height: 1px;
+ padding-left: 6px;
+ padding-right: 6px;
+ float: left;
+}
+.t3-admin-layout-preview.xs {
+ width: 450px;
+}
+.t3-admin-layout-preview .col-xs-1 {
+ width: 8.333333333333332%;
+}
+.t3-admin-layout-preview .col-xs-2 {
+ width: 16.666666666666664%;
+}
+.t3-admin-layout-preview .col-xs-3 {
+ width: 25%;
+}
+.t3-admin-layout-preview .col-xs-4 {
+ width: 33.33333333333333%;
+}
+.t3-admin-layout-preview .col-xs-5 {
+ width: 41.66666666666667%;
+}
+.t3-admin-layout-preview .col-xs-6 {
+ width: 50%;
+}
+.t3-admin-layout-preview .col-xs-7 {
+ width: 58.333333333333336%;
+}
+.t3-admin-layout-preview .col-xs-8 {
+ width: 66.66666666666666%;
+}
+.t3-admin-layout-preview .col-xs-9 {
+ width: 75%;
+}
+.t3-admin-layout-preview .col-xs-10 {
+ width: 83.33333333333334%;
+}
+.t3-admin-layout-preview .col-xs-11 {
+ width: 91.66666666666666%;
+}
+.t3-admin-layout-preview .col-xs-12 {
+ width: 100%;
+}
+.t3-admin-layout-preview.sm,
+.t3-admin-layout-preview.md,
+.t3-admin-layout-preview.lg {
+ width: 500px;
+}
+.t3-admin-layout-preview.sm .col-sm-1,
+.t3-admin-layout-preview.md .col-sm-1,
+.t3-admin-layout-preview.lg .col-sm-1,
+.t3-admin-layout-preview.sm .col-sm-2,
+.t3-admin-layout-preview.md .col-sm-2,
+.t3-admin-layout-preview.lg .col-sm-2,
+.t3-admin-layout-preview.sm .col-sm-3,
+.t3-admin-layout-preview.md .col-sm-3,
+.t3-admin-layout-preview.lg .col-sm-3,
+.t3-admin-layout-preview.sm .col-sm-4,
+.t3-admin-layout-preview.md .col-sm-4,
+.t3-admin-layout-preview.lg .col-sm-4,
+.t3-admin-layout-preview.sm .col-sm-5,
+.t3-admin-layout-preview.md .col-sm-5,
+.t3-admin-layout-preview.lg .col-sm-5,
+.t3-admin-layout-preview.sm .col-sm-6,
+.t3-admin-layout-preview.md .col-sm-6,
+.t3-admin-layout-preview.lg .col-sm-6,
+.t3-admin-layout-preview.sm .col-sm-7,
+.t3-admin-layout-preview.md .col-sm-7,
+.t3-admin-layout-preview.lg .col-sm-7,
+.t3-admin-layout-preview.sm .col-sm-8,
+.t3-admin-layout-preview.md .col-sm-8,
+.t3-admin-layout-preview.lg .col-sm-8,
+.t3-admin-layout-preview.sm .col-sm-9,
+.t3-admin-layout-preview.md .col-sm-9,
+.t3-admin-layout-preview.lg .col-sm-9,
+.t3-admin-layout-preview.sm .col-sm-10,
+.t3-admin-layout-preview.md .col-sm-10,
+.t3-admin-layout-preview.lg .col-sm-10,
+.t3-admin-layout-preview.sm .col-sm-11,
+.t3-admin-layout-preview.md .col-sm-11,
+.t3-admin-layout-preview.lg .col-sm-11 {
+ float: left;
+}
+.t3-admin-layout-preview.sm .col-sm-1,
+.t3-admin-layout-preview.md .col-sm-1,
+.t3-admin-layout-preview.lg .col-sm-1 {
+ width: 8.333333333333332%;
+}
+.t3-admin-layout-preview.sm .col-sm-2,
+.t3-admin-layout-preview.md .col-sm-2,
+.t3-admin-layout-preview.lg .col-sm-2 {
+ width: 16.666666666666664%;
+}
+.t3-admin-layout-preview.sm .col-sm-3,
+.t3-admin-layout-preview.md .col-sm-3,
+.t3-admin-layout-preview.lg .col-sm-3 {
+ width: 25%;
+}
+.t3-admin-layout-preview.sm .col-sm-4,
+.t3-admin-layout-preview.md .col-sm-4,
+.t3-admin-layout-preview.lg .col-sm-4 {
+ width: 33.33333333333333%;
+}
+.t3-admin-layout-preview.sm .col-sm-5,
+.t3-admin-layout-preview.md .col-sm-5,
+.t3-admin-layout-preview.lg .col-sm-5 {
+ width: 41.66666666666667%;
+}
+.t3-admin-layout-preview.sm .col-sm-6,
+.t3-admin-layout-preview.md .col-sm-6,
+.t3-admin-layout-preview.lg .col-sm-6 {
+ width: 50%;
+}
+.t3-admin-layout-preview.sm .col-sm-7,
+.t3-admin-layout-preview.md .col-sm-7,
+.t3-admin-layout-preview.lg .col-sm-7 {
+ width: 58.333333333333336%;
+}
+.t3-admin-layout-preview.sm .col-sm-8,
+.t3-admin-layout-preview.md .col-sm-8,
+.t3-admin-layout-preview.lg .col-sm-8 {
+ width: 66.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-9,
+.t3-admin-layout-preview.md .col-sm-9,
+.t3-admin-layout-preview.lg .col-sm-9 {
+ width: 75%;
+}
+.t3-admin-layout-preview.sm .col-sm-10,
+.t3-admin-layout-preview.md .col-sm-10,
+.t3-admin-layout-preview.lg .col-sm-10 {
+ width: 83.33333333333334%;
+}
+.t3-admin-layout-preview.sm .col-sm-11,
+.t3-admin-layout-preview.md .col-sm-11,
+.t3-admin-layout-preview.lg .col-sm-11 {
+ width: 91.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-12,
+.t3-admin-layout-preview.md .col-sm-12,
+.t3-admin-layout-preview.lg .col-sm-12 {
+ width: 100%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-1,
+.t3-admin-layout-preview.md .col-sm-push-1,
+.t3-admin-layout-preview.lg .col-sm-push-1 {
+ left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-2,
+.t3-admin-layout-preview.md .col-sm-push-2,
+.t3-admin-layout-preview.lg .col-sm-push-2 {
+ left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-3,
+.t3-admin-layout-preview.md .col-sm-push-3,
+.t3-admin-layout-preview.lg .col-sm-push-3 {
+ left: 25%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-4,
+.t3-admin-layout-preview.md .col-sm-push-4,
+.t3-admin-layout-preview.lg .col-sm-push-4 {
+ left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-5,
+.t3-admin-layout-preview.md .col-sm-push-5,
+.t3-admin-layout-preview.lg .col-sm-push-5 {
+ left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-6,
+.t3-admin-layout-preview.md .col-sm-push-6,
+.t3-admin-layout-preview.lg .col-sm-push-6 {
+ left: 50%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-7,
+.t3-admin-layout-preview.md .col-sm-push-7,
+.t3-admin-layout-preview.lg .col-sm-push-7 {
+ left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-8,
+.t3-admin-layout-preview.md .col-sm-push-8,
+.t3-admin-layout-preview.lg .col-sm-push-8 {
+ left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-9,
+.t3-admin-layout-preview.md .col-sm-push-9,
+.t3-admin-layout-preview.lg .col-sm-push-9 {
+ left: 75%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-10,
+.t3-admin-layout-preview.md .col-sm-push-10,
+.t3-admin-layout-preview.lg .col-sm-push-10 {
+ left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.sm .col-sm-push-11,
+.t3-admin-layout-preview.md .col-sm-push-11,
+.t3-admin-layout-preview.lg .col-sm-push-11 {
+ left: 91.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-1,
+.t3-admin-layout-preview.md .col-sm-pull-1,
+.t3-admin-layout-preview.lg .col-sm-pull-1 {
+ right: 8.333333333333332%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-2,
+.t3-admin-layout-preview.md .col-sm-pull-2,
+.t3-admin-layout-preview.lg .col-sm-pull-2 {
+ right: 16.666666666666664%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-3,
+.t3-admin-layout-preview.md .col-sm-pull-3,
+.t3-admin-layout-preview.lg .col-sm-pull-3 {
+ right: 25%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-4,
+.t3-admin-layout-preview.md .col-sm-pull-4,
+.t3-admin-layout-preview.lg .col-sm-pull-4 {
+ right: 33.33333333333333%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-5,
+.t3-admin-layout-preview.md .col-sm-pull-5,
+.t3-admin-layout-preview.lg .col-sm-pull-5 {
+ right: 41.66666666666667%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-6,
+.t3-admin-layout-preview.md .col-sm-pull-6,
+.t3-admin-layout-preview.lg .col-sm-pull-6 {
+ right: 50%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-7,
+.t3-admin-layout-preview.md .col-sm-pull-7,
+.t3-admin-layout-preview.lg .col-sm-pull-7 {
+ right: 58.333333333333336%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-8,
+.t3-admin-layout-preview.md .col-sm-pull-8,
+.t3-admin-layout-preview.lg .col-sm-pull-8 {
+ right: 66.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-9,
+.t3-admin-layout-preview.md .col-sm-pull-9,
+.t3-admin-layout-preview.lg .col-sm-pull-9 {
+ right: 75%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-10,
+.t3-admin-layout-preview.md .col-sm-pull-10,
+.t3-admin-layout-preview.lg .col-sm-pull-10 {
+ right: 83.33333333333334%;
+}
+.t3-admin-layout-preview.sm .col-sm-pull-11,
+.t3-admin-layout-preview.md .col-sm-pull-11,
+.t3-admin-layout-preview.lg .col-sm-pull-11 {
+ right: 91.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-1,
+.t3-admin-layout-preview.md .col-sm-offset-1,
+.t3-admin-layout-preview.lg .col-sm-offset-1 {
+ margin-left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-2,
+.t3-admin-layout-preview.md .col-sm-offset-2,
+.t3-admin-layout-preview.lg .col-sm-offset-2 {
+ margin-left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-3,
+.t3-admin-layout-preview.md .col-sm-offset-3,
+.t3-admin-layout-preview.lg .col-sm-offset-3 {
+ margin-left: 25%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-4,
+.t3-admin-layout-preview.md .col-sm-offset-4,
+.t3-admin-layout-preview.lg .col-sm-offset-4 {
+ margin-left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-5,
+.t3-admin-layout-preview.md .col-sm-offset-5,
+.t3-admin-layout-preview.lg .col-sm-offset-5 {
+ margin-left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-6,
+.t3-admin-layout-preview.md .col-sm-offset-6,
+.t3-admin-layout-preview.lg .col-sm-offset-6 {
+ margin-left: 50%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-7,
+.t3-admin-layout-preview.md .col-sm-offset-7,
+.t3-admin-layout-preview.lg .col-sm-offset-7 {
+ margin-left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-8,
+.t3-admin-layout-preview.md .col-sm-offset-8,
+.t3-admin-layout-preview.lg .col-sm-offset-8 {
+ margin-left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-9,
+.t3-admin-layout-preview.md .col-sm-offset-9,
+.t3-admin-layout-preview.lg .col-sm-offset-9 {
+ margin-left: 75%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-10,
+.t3-admin-layout-preview.md .col-sm-offset-10,
+.t3-admin-layout-preview.lg .col-sm-offset-10 {
+ margin-left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.sm .col-sm-offset-11,
+.t3-admin-layout-preview.md .col-sm-offset-11,
+.t3-admin-layout-preview.lg .col-sm-offset-11 {
+ margin-left: 91.66666666666666%;
+}
+.t3-admin-layout-preview.md,
+.t3-admin-layout-preview.lg {
+ width: 600px;
+}
+.t3-admin-layout-preview.md .col-md-1,
+.t3-admin-layout-preview.lg .col-md-1,
+.t3-admin-layout-preview.md .col-md-2,
+.t3-admin-layout-preview.lg .col-md-2,
+.t3-admin-layout-preview.md .col-md-3,
+.t3-admin-layout-preview.lg .col-md-3,
+.t3-admin-layout-preview.md .col-md-4,
+.t3-admin-layout-preview.lg .col-md-4,
+.t3-admin-layout-preview.md .col-md-5,
+.t3-admin-layout-preview.lg .col-md-5,
+.t3-admin-layout-preview.md .col-md-6,
+.t3-admin-layout-preview.lg .col-md-6,
+.t3-admin-layout-preview.md .col-md-7,
+.t3-admin-layout-preview.lg .col-md-7,
+.t3-admin-layout-preview.md .col-md-8,
+.t3-admin-layout-preview.lg .col-md-8,
+.t3-admin-layout-preview.md .col-md-9,
+.t3-admin-layout-preview.lg .col-md-9,
+.t3-admin-layout-preview.md .col-md-10,
+.t3-admin-layout-preview.lg .col-md-10,
+.t3-admin-layout-preview.md .col-md-11,
+.t3-admin-layout-preview.lg .col-md-11 {
+ float: left;
+}
+.t3-admin-layout-preview.md .col-md-1,
+.t3-admin-layout-preview.lg .col-md-1 {
+ width: 8.333333333333332%;
+}
+.t3-admin-layout-preview.md .col-md-2,
+.t3-admin-layout-preview.lg .col-md-2 {
+ width: 16.666666666666664%;
+}
+.t3-admin-layout-preview.md .col-md-3,
+.t3-admin-layout-preview.lg .col-md-3 {
+ width: 25%;
+}
+.t3-admin-layout-preview.md .col-md-4,
+.t3-admin-layout-preview.lg .col-md-4 {
+ width: 33.33333333333333%;
+}
+.t3-admin-layout-preview.md .col-md-5,
+.t3-admin-layout-preview.lg .col-md-5 {
+ width: 41.66666666666667%;
+}
+.t3-admin-layout-preview.md .col-md-6,
+.t3-admin-layout-preview.lg .col-md-6 {
+ width: 50%;
+}
+.t3-admin-layout-preview.md .col-md-7,
+.t3-admin-layout-preview.lg .col-md-7 {
+ width: 58.333333333333336%;
+}
+.t3-admin-layout-preview.md .col-md-8,
+.t3-admin-layout-preview.lg .col-md-8 {
+ width: 66.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-9,
+.t3-admin-layout-preview.lg .col-md-9 {
+ width: 75%;
+}
+.t3-admin-layout-preview.md .col-md-10,
+.t3-admin-layout-preview.lg .col-md-10 {
+ width: 83.33333333333334%;
+}
+.t3-admin-layout-preview.md .col-md-11,
+.t3-admin-layout-preview.lg .col-md-11 {
+ width: 91.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-12,
+.t3-admin-layout-preview.lg .col-md-12 {
+ width: 100%;
+}
+.t3-admin-layout-preview.md .col-md-push-0,
+.t3-admin-layout-preview.lg .col-md-push-0 {
+ left: auto;
+}
+.t3-admin-layout-preview.md .col-md-push-1,
+.t3-admin-layout-preview.lg .col-md-push-1 {
+ left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.md .col-md-push-2,
+.t3-admin-layout-preview.lg .col-md-push-2 {
+ left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.md .col-md-push-3,
+.t3-admin-layout-preview.lg .col-md-push-3 {
+ left: 25%;
+}
+.t3-admin-layout-preview.md .col-md-push-4,
+.t3-admin-layout-preview.lg .col-md-push-4 {
+ left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.md .col-md-push-5,
+.t3-admin-layout-preview.lg .col-md-push-5 {
+ left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.md .col-md-push-6,
+.t3-admin-layout-preview.lg .col-md-push-6 {
+ left: 50%;
+}
+.t3-admin-layout-preview.md .col-md-push-7,
+.t3-admin-layout-preview.lg .col-md-push-7 {
+ left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.md .col-md-push-8,
+.t3-admin-layout-preview.lg .col-md-push-8 {
+ left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-push-9,
+.t3-admin-layout-preview.lg .col-md-push-9 {
+ left: 75%;
+}
+.t3-admin-layout-preview.md .col-md-push-10,
+.t3-admin-layout-preview.lg .col-md-push-10 {
+ left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.md .col-md-push-11,
+.t3-admin-layout-preview.lg .col-md-push-11 {
+ left: 91.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-pull-0,
+.t3-admin-layout-preview.lg .col-md-pull-0 {
+ right: auto;
+}
+.t3-admin-layout-preview.md .col-md-pull-1,
+.t3-admin-layout-preview.lg .col-md-pull-1 {
+ right: 8.333333333333332%;
+}
+.t3-admin-layout-preview.md .col-md-pull-2,
+.t3-admin-layout-preview.lg .col-md-pull-2 {
+ right: 16.666666666666664%;
+}
+.t3-admin-layout-preview.md .col-md-pull-3,
+.t3-admin-layout-preview.lg .col-md-pull-3 {
+ right: 25%;
+}
+.t3-admin-layout-preview.md .col-md-pull-4,
+.t3-admin-layout-preview.lg .col-md-pull-4 {
+ right: 33.33333333333333%;
+}
+.t3-admin-layout-preview.md .col-md-pull-5,
+.t3-admin-layout-preview.lg .col-md-pull-5 {
+ right: 41.66666666666667%;
+}
+.t3-admin-layout-preview.md .col-md-pull-6,
+.t3-admin-layout-preview.lg .col-md-pull-6 {
+ right: 50%;
+}
+.t3-admin-layout-preview.md .col-md-pull-7,
+.t3-admin-layout-preview.lg .col-md-pull-7 {
+ right: 58.333333333333336%;
+}
+.t3-admin-layout-preview.md .col-md-pull-8,
+.t3-admin-layout-preview.lg .col-md-pull-8 {
+ right: 66.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-pull-9,
+.t3-admin-layout-preview.lg .col-md-pull-9 {
+ right: 75%;
+}
+.t3-admin-layout-preview.md .col-md-pull-10,
+.t3-admin-layout-preview.lg .col-md-pull-10 {
+ right: 83.33333333333334%;
+}
+.t3-admin-layout-preview.md .col-md-pull-11,
+.t3-admin-layout-preview.lg .col-md-pull-11 {
+ right: 91.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-offset-0,
+.t3-admin-layout-preview.lg .col-md-offset-0 {
+ margin-left: 0;
+}
+.t3-admin-layout-preview.md .col-md-offset-1,
+.t3-admin-layout-preview.lg .col-md-offset-1 {
+ margin-left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.md .col-md-offset-2,
+.t3-admin-layout-preview.lg .col-md-offset-2 {
+ margin-left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.md .col-md-offset-3,
+.t3-admin-layout-preview.lg .col-md-offset-3 {
+ margin-left: 25%;
+}
+.t3-admin-layout-preview.md .col-md-offset-4,
+.t3-admin-layout-preview.lg .col-md-offset-4 {
+ margin-left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.md .col-md-offset-5,
+.t3-admin-layout-preview.lg .col-md-offset-5 {
+ margin-left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.md .col-md-offset-6,
+.t3-admin-layout-preview.lg .col-md-offset-6 {
+ margin-left: 50%;
+}
+.t3-admin-layout-preview.md .col-md-offset-7,
+.t3-admin-layout-preview.lg .col-md-offset-7 {
+ margin-left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.md .col-md-offset-8,
+.t3-admin-layout-preview.lg .col-md-offset-8 {
+ margin-left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.md .col-md-offset-9,
+.t3-admin-layout-preview.lg .col-md-offset-9 {
+ margin-left: 75%;
+}
+.t3-admin-layout-preview.md .col-md-offset-10,
+.t3-admin-layout-preview.lg .col-md-offset-10 {
+ margin-left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.md .col-md-offset-11,
+.t3-admin-layout-preview.lg .col-md-offset-11 {
+ margin-left: 91.66666666666666%;
+}
+.t3-admin-layout-preview.lg {
+ width: 720px;
+}
+.t3-admin-layout-preview.lg .col-lg-1,
+.t3-admin-layout-preview.lg .col-lg-2,
+.t3-admin-layout-preview.lg .col-lg-3,
+.t3-admin-layout-preview.lg .col-lg-4,
+.t3-admin-layout-preview.lg .col-lg-5,
+.t3-admin-layout-preview.lg .col-lg-6,
+.t3-admin-layout-preview.lg .col-lg-7,
+.t3-admin-layout-preview.lg .col-lg-8,
+.t3-admin-layout-preview.lg .col-lg-9,
+.t3-admin-layout-preview.lg .col-lg-10,
+.t3-admin-layout-preview.lg .col-lg-11 {
+ float: left;
+}
+.t3-admin-layout-preview.lg .col-lg-1 {
+ width: 8.333333333333332%;
+}
+.t3-admin-layout-preview.lg .col-lg-2 {
+ width: 16.666666666666664%;
+}
+.t3-admin-layout-preview.lg .col-lg-3 {
+ width: 25%;
+}
+.t3-admin-layout-preview.lg .col-lg-4 {
+ width: 33.33333333333333%;
+}
+.t3-admin-layout-preview.lg .col-lg-5 {
+ width: 41.66666666666667%;
+}
+.t3-admin-layout-preview.lg .col-lg-6 {
+ width: 50%;
+}
+.t3-admin-layout-preview.lg .col-lg-7 {
+ width: 58.333333333333336%;
+}
+.t3-admin-layout-preview.lg .col-lg-8 {
+ width: 66.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-9 {
+ width: 75%;
+}
+.t3-admin-layout-preview.lg .col-lg-10 {
+ width: 83.33333333333334%;
+}
+.t3-admin-layout-preview.lg .col-lg-11 {
+ width: 91.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-12 {
+ width: 100%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-0 {
+ left: auto;
+}
+.t3-admin-layout-preview.lg .col-lg-push-1 {
+ left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-2 {
+ left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-3 {
+ left: 25%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-4 {
+ left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-5 {
+ left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-6 {
+ left: 50%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-7 {
+ left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-8 {
+ left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-9 {
+ left: 75%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-10 {
+ left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.lg .col-lg-push-11 {
+ left: 91.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-0 {
+ right: auto;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-1 {
+ right: 8.333333333333332%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-2 {
+ right: 16.666666666666664%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-3 {
+ right: 25%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-4 {
+ right: 33.33333333333333%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-5 {
+ right: 41.66666666666667%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-6 {
+ right: 50%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-7 {
+ right: 58.333333333333336%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-8 {
+ right: 66.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-9 {
+ right: 75%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-10 {
+ right: 83.33333333333334%;
+}
+.t3-admin-layout-preview.lg .col-lg-pull-11 {
+ right: 91.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-0 {
+ margin-left: 0;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-1 {
+ margin-left: 8.333333333333332%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-2 {
+ margin-left: 16.666666666666664%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-3 {
+ margin-left: 25%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-4 {
+ margin-left: 33.33333333333333%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-5 {
+ margin-left: 41.66666666666667%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-6 {
+ margin-left: 50%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-7 {
+ margin-left: 58.333333333333336%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-8 {
+ margin-left: 66.66666666666666%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-9 {
+ margin-left: 75%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-10 {
+ margin-left: 83.33333333333334%;
+}
+.t3-admin-layout-preview.lg .col-lg-offset-11 {
+ margin-left: 91.66666666666666%;
+}
+.t3-admin-layout-preview .navbar-collapse.collapse {
+ height: auto !important;
+ overflow: visible !important;
+}
+
+/* Override css for dropdown menu */
+.t3-admin-layout-preview .t3-admin-layout-section .dropdown-menu {
+ display: block;
+ padding: 0;
+ min-width: 0;
+ border: 0;
+ position: static;
+ box-shadow: none;
+ background: none;
+}
diff --git a/plugins/system/t3/base-bs3/css/megamenu-responsive.css b/plugins/system/t3/base-bs3/css/megamenu-responsive.css
new file mode 100644
index 0000000..606aaba
--- /dev/null
+++ b/plugins/system/t3/base-bs3/css/megamenu-responsive.css
@@ -0,0 +1,51 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: https://github.com/t3framework/
+ *------------------------------------------------------------------------------
+*/
+@media (max-width: 767px) {
+ .t3-megamenu .mega-inner {
+ padding: 10px 20px;
+ }
+ .t3-megamenu .row-fluid,
+ .t3-megamenu .mega-dropdown-menu,
+ .t3-megamenu .row-fluid [class*="span"] {
+ width: 100% !important;
+ min-width: 100% !important;
+ left: 0 !important;
+ margin-left: 0 !important;
+ transform: none !important;
+ -webkit-transform: none !important;
+ -moz-transform: none !important;
+ -ms-transform: none !important;
+ -o-transform: none !important;
+ }
+ .t3-megamenu .row-fluid + .row-fluid {
+ padding-top: 10px;
+ border-top: 1px solid #eeeeee;
+ }
+ .t3-megamenu .hidden-collapse,
+ .t3-megamenu .always-show .caret,
+ .t3-megamenu .sub-hidden-collapse > .nav-child,
+ .t3-megamenu .sub-hidden-collapse .caret,
+ .t3-megamenu .sub-hidden-collapse > a:after,
+ .t3-megamenu .always-show .dropdown-submenu > a:after {
+ display: none !important;
+ }
+ .t3-megamenu .mega-caption {
+ display: none !important;
+ }
+ html[dir="rtl"] .t3-megamenu .row-fluid,
+ html[dir="rtl"] .t3-megamenu .mega-dropdown-menu,
+ html[dir="rtl"] .t3-megamenu .row-fluid [class*="span"] {
+ right: 0 !important;
+ margin-right: 0 !important;
+ }
+}
diff --git a/plugins/system/t3/base-bs3/css/megamenu.css b/plugins/system/t3/base-bs3/css/megamenu.css
new file mode 100644
index 0000000..26bf65d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/css/megamenu.css
@@ -0,0 +1,292 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: https://github.com/t3framework/
+ *------------------------------------------------------------------------------
+*/
+.t3-megamenu .mega-inner {
+ padding: 10px;
+ *zoom: 1;
+}
+.t3-megamenu .mega-inner:before,
+.t3-megamenu .mega-inner:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.t3-megamenu .mega-inner:after {
+ clear: both;
+}
+.t3-megamenu .row-fluid + .row-fluid {
+ padding-top: 10px;
+ border-top: 1px solid #eeeeee;
+}
+.t3-megamenu .mega > .mega-dropdown-menu {
+ min-width: 200px;
+ display: none;
+}
+.t3-megamenu .mega.open > .mega-dropdown-menu,
+.t3-megamenu .mega.dropdown-submenu:hover > .mega-dropdown-menu {
+ display: block;
+}
+.t3-megamenu .mega-group {
+ *zoom: 1;
+}
+.t3-megamenu .mega-group:before,
+.t3-megamenu .mega-group:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.t3-megamenu .mega-group:after {
+ clear: both;
+}
+.t3-megamenu .mega-nav .mega-group > .mega-group-title,
+.t3-megamenu .dropdown-menu .mega-nav .mega-group > .mega-group-title,
+.t3-megamenu .dropdown-menu .active .mega-nav .mega-group > .mega-group-title {
+ background: inherit;
+ color: inherit;
+ font-weight: bold;
+ padding: 0;
+ margin: 0;
+}
+.t3-megamenu .mega-nav .mega-group > .mega-group-title:hover,
+.t3-megamenu .dropdown-menu .mega-nav .mega-group > .mega-group-title:hover,
+.t3-megamenu .dropdown-menu .active .mega-nav .mega-group > .mega-group-title:hover,
+.t3-megamenu .mega-nav .mega-group > .mega-group-title:active,
+.t3-megamenu .dropdown-menu .mega-nav .mega-group > .mega-group-title:active,
+.t3-megamenu .dropdown-menu .active .mega-nav .mega-group > .mega-group-title:active,
+.t3-megamenu .mega-nav .mega-group > .mega-group-title:focus,
+.t3-megamenu .dropdown-menu .mega-nav .mega-group > .mega-group-title:focus,
+.t3-megamenu .dropdown-menu .active .mega-nav .mega-group > .mega-group-title:focus {
+ background: inherit;
+ color: inherit;
+}
+.t3-megamenu .mega-group-ct {
+ margin: 0;
+ padding: 0;
+ *zoom: 1;
+}
+.t3-megamenu .mega-group-ct:before,
+.t3-megamenu .mega-group-ct:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.t3-megamenu .mega-group-ct:after {
+ clear: both;
+}
+.t3-megamenu .span12.mega-col-nav .mega-inner {
+ padding: 5px;
+}
+.t3-megamenu .mega-group .span12.mega-col-nav .mega-inner {
+ padding: 0;
+}
+.t3-megamenu .mega-nav,
+.t3-megamenu .dropdown-menu .mega-nav {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.t3-megamenu .mega-nav > li,
+.t3-megamenu .dropdown-menu .mega-nav > li {
+ list-style: none;
+ margin-left: 0;
+}
+.t3-megamenu .mega-nav > li a,
+.t3-megamenu .dropdown-menu .mega-nav > li a {
+ white-space: normal;
+}
+.t3-megamenu .mega-group > .mega-nav,
+.t3-megamenu .dropdown-menu .mega-group > .mega-nav {
+ margin-left: -5px;
+ margin-right: -5px;
+}
+.t3-megamenu .mega-nav .dropdown-submenu > a::after {
+ margin-right: 5px;
+}
+.t3-megamenu .t3-module {
+ margin-bottom: 10px;
+}
+.t3-megamenu .t3-module .module-title {
+ margin-bottom: 0;
+}
+.t3-megamenu .t3-module .module-ct {
+ margin: 0;
+ padding: 0;
+}
+.t3-megamenu .mega-align-left > .dropdown-menu {
+ left: 0;
+}
+.t3-megamenu .mega-align-right > .dropdown-menu {
+ left: auto;
+ right: 0;
+}
+.t3-megamenu .mega-align-center > .dropdown-menu {
+ left: 50%;
+ transform: translate(-50%);
+ -webkit-transform: translate(-50%);
+ -moz-transform: translate(-50%);
+ -ms-transform: translate(-50%);
+ -o-transform: translate(-50%);
+}
+.t3-megamenu .dropdown-submenu.mega-align-left > .dropdown-menu {
+ left: 100%;
+}
+.t3-megamenu .dropdown-submenu.mega-align-right > .dropdown-menu {
+ left: auto;
+ right: 100%;
+}
+.t3-megamenu .mega-align-justify {
+ position: static;
+}
+.t3-megamenu .mega-align-justify > .dropdown-menu {
+ left: 0;
+ margin-left: 0;
+ top: auto;
+}
+.t3-megamenu .mega-caption {
+ display: block;
+ white-space: nowrap;
+}
+.t3-megamenu .nav .caret,
+.t3-megamenu .dropdown-submenu .caret,
+.t3-megamenu .mega-menu .caret {
+ display: none;
+}
+.t3-megamenu .nav > .dropdown > .dropdown-toggle .caret {
+ display: inline-block;
+}
+.t3-megamenu .nav [class^="icon-"],
+.t3-megamenu .nav [class*=" icon-"],
+.t3-megamenu .nav .fa {
+ margin-right: 5px;
+}
+@media (min-width: 768px) {
+ .t3-megamenu.animate .mega > .mega-dropdown-menu {
+ transition: all 400ms;
+ -webkit-transition: all 400ms;
+ -ms-transition: all 400ms;
+ -o-transition: all 400ms;
+ -webkit-backface-visibility: hidden;
+ -moz-backface-visibility: hidden;
+ -o-backface-visibility: hidden;
+ backface-visibility: hidden;
+ opacity: 0;
+ }
+ .t3-megamenu.animate .mega.animating > .mega-dropdown-menu {
+ display: block;
+ }
+ .t3-megamenu.animate .mega.open > .mega-dropdown-menu,
+ .t3-megamenu.animate .mega.animating.open > .mega-dropdown-menu {
+ opacity: 1;
+ }
+ .t3-megamenu.animate.zoom .mega > .mega-dropdown-menu {
+ transform: scale(0, 0);
+ transform-origin: 20% 20%;
+ -webkit-transform: scale(0, 0);
+ -webkit-transform-origin: 20% 20%;
+ -ms-transform: scale(0, 0);
+ -ms-transform-origin: 20% 20%;
+ -o-transform: scale(0, 0);
+ -o-transform-origin: 20% 20%;
+ }
+ .t3-megamenu.animate.zoom .mega.open > .mega-dropdown-menu {
+ transform: scale(1, 1);
+ -webkit-transform: scale(1, 1);
+ -ms-transform: scale(1, 1);
+ -o-transform: scale(1, 1);
+ }
+ .t3-megamenu.animate.elastic .level0 > .mega > .mega-dropdown-menu {
+ transform: scale(1, 0);
+ -webkit-transform: scale(1, 0);
+ -ms-transform: scale(1, 0);
+ -o-transform: scale(1, 0);
+ }
+ .t3-megamenu.animate.elastic .mega > .mega-dropdown-menu {
+ transform: scale(0, 1);
+ transform-origin: 10% 0;
+ -webkit-transform: scale(0, 1);
+ -webkit-transform-origin: 10% 0;
+ -ms-transform: scale(0, 1);
+ -ms-transform-origin: 10% 0;
+ -o-transform: scale(0, 1);
+ -o-transform-origin: 10% 0;
+ }
+ .t3-megamenu.animate.elastic .mega.open > .mega-dropdown-menu {
+ transform: scale(1, 1);
+ -webkit-transform: scale(1, 1);
+ -ms-transform: scale(1, 1);
+ -o-transform: scale(1, 1);
+ }
+ .t3-megamenu.animate.slide .mega {
+ /* Level 0 */
+
+ /* Level > 0 */
+
+ }
+ .t3-megamenu.animate.slide .mega.animating > .mega-dropdown-menu {
+ overflow: hidden;
+ }
+ .t3-megamenu.animate.slide .mega > .mega-dropdown-menu > div {
+ transition: all 400ms;
+ -webkit-transition: all 400ms;
+ -ms-transition: all 400ms;
+ -o-transition: all 400ms;
+ -webkit-backface-visibility: hidden;
+ -moz-backface-visibility: hidden;
+ -o-backface-visibility: hidden;
+ backface-visibility: hidden;
+ margin-top: -100%;
+ }
+ .t3-megamenu.animate.slide .mega.open > .mega-dropdown-menu > div {
+ margin-top: 0%;
+ }
+ .t3-megamenu.animate.slide .mega .mega > .mega-dropdown-menu {
+ min-width: 0;
+ }
+ .t3-megamenu.animate.slide .mega .mega > .mega-dropdown-menu > div {
+ min-width: 200px;
+ margin-top: 0;
+ margin-left: -500px;
+ }
+ .t3-megamenu.animate.slide .mega .mega.open > .mega-dropdown-menu > div {
+ margin-left: 0;
+ }
+}
+html[dir="rtl"] .t3-megamenu .mega-align-left > .dropdown-menu {
+ right: 0;
+}
+html[dir="rtl"] .t3-megamenu .mega-align-right > .dropdown-menu {
+ right: auto;
+ left: 0;
+}
+html[dir="rtl"] .t3-megamenu .mega-align-center > .dropdown-menu {
+ right: 50%;
+ transform: translate(50%);
+ -webkit-transform: translate(50%);
+ -moz-transform: translate(50%);
+ -ms-transform: translate(50%);
+ -o-transform: translate(50%);
+}
+html[dir="rtl"] .t3-megamenu .dropdown-submenu.mega-align-left > .dropdown-menu {
+ right: 100%;
+}
+html[dir="rtl"] .t3-megamenu .dropdown-submenu.mega-align-right > .dropdown-menu {
+ right: auto;
+ left: 100%;
+}
+html[dir="rtl"] .t3-megamenu .mega-align-justify > .dropdown-menu {
+ right: 0;
+ margin-right: 0;
+ top: auto;
+}
+html[dir="rtl"] .t3-megamenu .mega-nav .dropdown-submenu > a:after {
+ direction: ltr;
+}
diff --git a/plugins/system/t3/base-bs3/css/off-canvas.css b/plugins/system/t3/base-bs3/css/off-canvas.css
new file mode 100644
index 0000000..47caf3e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/css/off-canvas.css
@@ -0,0 +1,83 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+
+#off-canvas-nav {
+ display: none;
+}
+@media (max-width: 767px) {
+ .off-canvas {
+ width: 100%;
+ overflow-x: hidden;
+ position: relative;
+ }
+ .off-canvas body {
+ width: 100%;
+ overflow-x: hidden;
+ -o-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ }
+ .off-canvas body > * {
+ left: 0;
+ -webkit-transform: translateX(0);
+ -moz-transform: translateX(0);
+ -o-transform: translateX(0);
+ transform: translateX(0);
+ -webkit-transition: -webkit-transform 500ms ease;
+ -moz-transition: -moz-transform 500ms ease;
+ -o-transition: -o-transform 500ms ease;
+ transition: transform 500ms ease;
+ -webkit-backface-visibility: hidden;
+ -moz-backface-visibility: hidden;
+ -o-backface-visibility: hidden;
+ backface-visibility: hidden;
+ }
+ .off-canvas #t3-mainnav .nav-collapse,
+ .off-canvas #ja-mainnav .nav-collapse {
+ display: none;
+ }
+ .off-canvas #off-canvas-nav {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 0;
+ z-index: 1;
+ background: none;
+ }
+ .off-canvas #off-canvas-nav .t3-mainnav {
+ margin: 0;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 250px;
+ -webkit-transform: translateX(-100%);
+ -moz-transform: translateX(-100%);
+ -o-transform: translateX(-100%);
+ transform: translateX(-100%);
+ }
+ .off-canvas #off-canvas-nav .t3-mainnav .nav-collapse {
+ height: auto;
+ background: none;
+ }
+ .off-canvas-enabled body > * {
+ -webkit-transform: translateX(250px);
+ -moz-transform: translateX(250px);
+ -o-transform: translateX(250px);
+ transform: translateX(250px);
+ }
+ .off-canvas-enabled #t3-mainnav {
+ display: block;
+ }
+}
diff --git a/plugins/system/t3/base-bs3/css/thememagic.css b/plugins/system/t3/base-bs3/css/thememagic.css
new file mode 100644
index 0000000..31378a2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/css/thememagic.css
@@ -0,0 +1,22 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+
+body {
+ visibility: hidden;
+ cursor: pointer;
+}
+
+body.ready {
+ visibility: visible;
+ cursor: auto;
+}
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/define.php b/plugins/system/t3/base-bs3/define.php
new file mode 100644
index 0000000..fd880e6
--- /dev/null
+++ b/plugins/system/t3/base-bs3/define.php
@@ -0,0 +1,44 @@
+ 6, 'md' => 6, 'sm' => 4, 'xs' => 2)));
+define('T3_BASE_DV_MINWIDTH', json_encode(array('lg' => 2, 'md' => 2, 'sm' => 3, 'xs' => 6)));
+define('T3_BASE_DV_UNITSPAN', json_encode(array('lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1)));
+define('T3_BASE_DV_PREFIX', json_encode(array('col-md-', 'col-lg-', 'col-sm-', 'col-xs-'))); /* priority order */
+define('T3_BASE_LESS_COMPILER', 'less');
diff --git a/plugins/system/t3/base-bs3/error.php b/plugins/system/t3/base-bs3/error.php
new file mode 100644
index 0000000..b74b3a0
--- /dev/null
+++ b/plugins/system/t3/base-bs3/error.php
@@ -0,0 +1,69 @@
+error)) {
+ $this->error = JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
+ $this->debug = false;
+}
+//get language and direction
+$doc = JFactory::getDocument();
+$this->language = $doc->language;
+$this->direction = $doc->direction;
+?>
+
+
+
+ error->getCode(); ?> - title; ?>
+
+ direction == 'rtl') : ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
.
+
+
error->getMessage(); ?>
+
+ debug) :
+ echo $this->renderBacktrace();
+ endif; ?>
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/etc/assets.xml b/plugins/system/t3/base-bs3/etc/assets.xml
new file mode 100644
index 0000000..83941b2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/etc/assets.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ fonts/font-awesome/css/font-awesome.min.css
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.css b/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.css
new file mode 100644
index 0000000..c42e924
--- /dev/null
+++ b/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.css
@@ -0,0 +1,1740 @@
+/*!
+ * Font Awesome 3.2.1
+ * the iconic font designed for Bootstrap
+ * ------------------------------------------------------------------------------
+ * The full suite of pictographic icons, examples, and documentation can be
+ * found at http://fontawesome.io. Stay up to date on Twitter at
+ * http://twitter.com/fontawesome.
+ *
+ * License
+ * ------------------------------------------------------------------------------
+ * - The Font Awesome font is licensed under SIL OFL 1.1 -
+ * http://scripts.sil.org/OFL
+ * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -
+ * http://opensource.org/licenses/mit-license.html
+ * - Font Awesome documentation licensed under CC BY 3.0 -
+ * http://creativecommons.org/licenses/by/3.0/
+ * - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
+ * "Font Awesome by Dave Gandy - http://fontawesome.io"
+ *
+ * Author - Dave Gandy
+ * ------------------------------------------------------------------------------
+ * Email: dave@fontawesome.io
+ * Twitter: http://twitter.com/davegandy
+ * Work: Lead Product Designer @ Kyruus - http://kyruus.com
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+ font-family: 'FontAwesome3';
+ src: url('../font/fontawesome-webfont.eot?v=3.2.1');
+ src: url('../font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+/* FONT AWESOME CORE
+ * -------------------------- */
+[class^="icon-"],
+[class*=" icon-"] {
+ font-family: FontAwesome3;
+ font-weight: normal;
+ font-style: normal;
+ text-decoration: inherit;
+ -webkit-font-smoothing: antialiased;
+ *margin-right: .3em;
+}
+[class^="icon-"]:before,
+[class*=" icon-"]:before {
+ text-decoration: inherit;
+ display: inline-block;
+ speak: none;
+}
+/* makes the font 33% larger relative to the icon container */
+.icon-large:before {
+ vertical-align: -10%;
+ font-size: 1.3333333333333333em;
+}
+/* makes sure icons active on rollover in links */
+a [class^="icon-"],
+a [class*=" icon-"] {
+ display: inline;
+}
+/* increased font size for icon-large */
+[class^="icon-"].icon-fixed-width,
+[class*=" icon-"].icon-fixed-width {
+ display: inline-block;
+ width: 1.1428571428571428em;
+ text-align: right;
+ padding-right: 0.2857142857142857em;
+}
+[class^="icon-"].icon-fixed-width.icon-large,
+[class*=" icon-"].icon-fixed-width.icon-large {
+ width: 1.4285714285714286em;
+}
+.icons-ul {
+ margin-left: 2.142857142857143em;
+ list-style-type: none;
+}
+.icons-ul > li {
+ position: relative;
+}
+.icons-ul .icon-li {
+ position: absolute;
+ left: -2.142857142857143em;
+ width: 2.142857142857143em;
+ text-align: center;
+ line-height: inherit;
+}
+[class^="icon-"].hide,
+[class*=" icon-"].hide {
+ display: none;
+}
+.icon-muted {
+ color: #eeeeee;
+}
+.icon-light {
+ color: #ffffff;
+}
+.icon-dark {
+ color: #333333;
+}
+.icon-border {
+ border: solid 1px #eeeeee;
+ padding: .2em .25em .15em;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.icon-2x {
+ font-size: 2em;
+}
+.icon-2x.icon-border {
+ border-width: 2px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.icon-3x {
+ font-size: 3em;
+}
+.icon-3x.icon-border {
+ border-width: 3px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+.icon-4x {
+ font-size: 4em;
+}
+.icon-4x.icon-border {
+ border-width: 4px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+.icon-5x {
+ font-size: 5em;
+}
+.icon-5x.icon-border {
+ border-width: 5px;
+ -webkit-border-radius: 7px;
+ -moz-border-radius: 7px;
+ border-radius: 7px;
+}
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+[class^="icon-"].pull-left,
+[class*=" icon-"].pull-left {
+ margin-right: .3em;
+}
+[class^="icon-"].pull-right,
+[class*=" icon-"].pull-right {
+ margin-left: .3em;
+}
+/* BOOTSTRAP SPECIFIC CLASSES
+ * -------------------------- */
+/* Bootstrap 2.0 sprites.less reset */
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline;
+ width: auto;
+ height: auto;
+ line-height: normal;
+ vertical-align: baseline;
+ background-image: none;
+ background-position: 0% 0%;
+ background-repeat: repeat;
+ margin-top: 0;
+}
+/* more sprites.less reset */
+.icon-white,
+.nav-pills > .active > a > [class^="icon-"],
+.nav-pills > .active > a > [class*=" icon-"],
+.nav-list > .active > a > [class^="icon-"],
+.nav-list > .active > a > [class*=" icon-"],
+.navbar-inverse .nav > .active > a > [class^="icon-"],
+.navbar-inverse .nav > .active > a > [class*=" icon-"],
+.dropdown-menu > li > a:hover > [class^="icon-"],
+.dropdown-menu > li > a:hover > [class*=" icon-"],
+.dropdown-menu > .active > a > [class^="icon-"],
+.dropdown-menu > .active > a > [class*=" icon-"],
+.dropdown-submenu:hover > a > [class^="icon-"],
+.dropdown-submenu:hover > a > [class*=" icon-"] {
+ background-image: none;
+}
+/* keeps Bootstrap styles with and without icons the same */
+.btn [class^="icon-"].icon-large,
+.nav [class^="icon-"].icon-large,
+.btn [class*=" icon-"].icon-large,
+.nav [class*=" icon-"].icon-large {
+ line-height: .9em;
+}
+.btn [class^="icon-"].icon-spin,
+.nav [class^="icon-"].icon-spin,
+.btn [class*=" icon-"].icon-spin,
+.nav [class*=" icon-"].icon-spin {
+ display: inline-block;
+}
+.nav-tabs [class^="icon-"],
+.nav-pills [class^="icon-"],
+.nav-tabs [class*=" icon-"],
+.nav-pills [class*=" icon-"],
+.nav-tabs [class^="icon-"].icon-large,
+.nav-pills [class^="icon-"].icon-large,
+.nav-tabs [class*=" icon-"].icon-large,
+.nav-pills [class*=" icon-"].icon-large {
+ line-height: .9em;
+}
+.btn [class^="icon-"].pull-left.icon-2x,
+.btn [class*=" icon-"].pull-left.icon-2x,
+.btn [class^="icon-"].pull-right.icon-2x,
+.btn [class*=" icon-"].pull-right.icon-2x {
+ margin-top: .18em;
+}
+.btn [class^="icon-"].icon-spin.icon-large,
+.btn [class*=" icon-"].icon-spin.icon-large {
+ line-height: .8em;
+}
+.btn.btn-small [class^="icon-"].pull-left.icon-2x,
+.btn.btn-small [class*=" icon-"].pull-left.icon-2x,
+.btn.btn-small [class^="icon-"].pull-right.icon-2x,
+.btn.btn-small [class*=" icon-"].pull-right.icon-2x {
+ margin-top: .25em;
+}
+.btn.btn-large [class^="icon-"],
+.btn.btn-large [class*=" icon-"] {
+ margin-top: 0;
+}
+.btn.btn-large [class^="icon-"].pull-left.icon-2x,
+.btn.btn-large [class*=" icon-"].pull-left.icon-2x,
+.btn.btn-large [class^="icon-"].pull-right.icon-2x,
+.btn.btn-large [class*=" icon-"].pull-right.icon-2x {
+ margin-top: .05em;
+}
+.btn.btn-large [class^="icon-"].pull-left.icon-2x,
+.btn.btn-large [class*=" icon-"].pull-left.icon-2x {
+ margin-right: .2em;
+}
+.btn.btn-large [class^="icon-"].pull-right.icon-2x,
+.btn.btn-large [class*=" icon-"].pull-right.icon-2x {
+ margin-left: .2em;
+}
+/* Fixes alignment in nav lists */
+.nav-list [class^="icon-"],
+.nav-list [class*=" icon-"] {
+ line-height: inherit;
+}
+/* EXTRAS
+ * -------------------------- */
+/* Stacked and layered icon */
+.icon-stack {
+ position: relative;
+ display: inline-block;
+ width: 2em;
+ height: 2em;
+ line-height: 2em;
+ vertical-align: -35%;
+}
+.icon-stack [class^="icon-"],
+.icon-stack [class*=" icon-"] {
+ display: block;
+ text-align: center;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ font-size: 1em;
+ line-height: inherit;
+ *line-height: 2em;
+}
+.icon-stack .icon-stack-base {
+ font-size: 2em;
+ *line-height: 1em;
+}
+/* Animated rotating icon */
+.icon-spin {
+ display: inline-block;
+ -moz-animation: spin 2s infinite linear;
+ -o-animation: spin 2s infinite linear;
+ -webkit-animation: spin 2s infinite linear;
+ animation: spin 2s infinite linear;
+}
+/* Prevent stack and spinners from being taken inline when inside a link */
+a .icon-stack,
+a .icon-spin {
+ display: inline-block;
+ text-decoration: none;
+}
+@-moz-keyframes spin {
+ 0% {
+ -moz-transform: rotate(0deg);
+ }
+ 100% {
+ -moz-transform: rotate(359deg);
+ }
+}
+@-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ }
+}
+@-o-keyframes spin {
+ 0% {
+ -o-transform: rotate(0deg);
+ }
+ 100% {
+ -o-transform: rotate(359deg);
+ }
+}
+@-ms-keyframes spin {
+ 0% {
+ -ms-transform: rotate(0deg);
+ }
+ 100% {
+ -ms-transform: rotate(359deg);
+ }
+}
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(359deg);
+ }
+}
+/* Icon rotations and mirroring */
+.icon-rotate-90:before {
+ -webkit-transform: rotate(90deg);
+ -moz-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ -o-transform: rotate(90deg);
+ transform: rotate(90deg);
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+}
+.icon-rotate-180:before {
+ -webkit-transform: rotate(180deg);
+ -moz-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ -o-transform: rotate(180deg);
+ transform: rotate(180deg);
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+}
+.icon-rotate-270:before {
+ -webkit-transform: rotate(270deg);
+ -moz-transform: rotate(270deg);
+ -ms-transform: rotate(270deg);
+ -o-transform: rotate(270deg);
+ transform: rotate(270deg);
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+}
+.icon-flip-horizontal:before {
+ -webkit-transform: scale(-1, 1);
+ -moz-transform: scale(-1, 1);
+ -ms-transform: scale(-1, 1);
+ -o-transform: scale(-1, 1);
+ transform: scale(-1, 1);
+}
+.icon-flip-vertical:before {
+ -webkit-transform: scale(1, -1);
+ -moz-transform: scale(1, -1);
+ -ms-transform: scale(1, -1);
+ -o-transform: scale(1, -1);
+ transform: scale(1, -1);
+}
+/* ensure rotation occurs inside anchor tags */
+a .icon-rotate-90:before,
+a .icon-rotate-180:before,
+a .icon-rotate-270:before,
+a .icon-flip-horizontal:before,
+a .icon-flip-vertical:before {
+ display: inline-block;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+ readers do not read off random characters that represent icons */
+.icon-glass:before {
+ content: "\f000";
+}
+.icon-music:before {
+ content: "\f001";
+}
+.icon-search:before {
+ content: "\f002";
+}
+.icon-envelope-alt:before {
+ content: "\f003";
+}
+.icon-heart:before {
+ content: "\f004";
+}
+.icon-star:before {
+ content: "\f005";
+}
+.icon-star-empty:before {
+ content: "\f006";
+}
+.icon-user:before {
+ content: "\f007";
+}
+.icon-film:before {
+ content: "\f008";
+}
+.icon-th-large:before {
+ content: "\f009";
+}
+.icon-th:before {
+ content: "\f00a";
+}
+.icon-th-list:before {
+ content: "\f00b";
+}
+.icon-ok:before {
+ content: "\f00c";
+}
+.icon-remove:before {
+ content: "\f00d";
+}
+.icon-zoom-in:before {
+ content: "\f00e";
+}
+.icon-zoom-out:before {
+ content: "\f010";
+}
+.icon-power-off:before,
+.icon-off:before {
+ content: "\f011";
+}
+.icon-signal:before {
+ content: "\f012";
+}
+.icon-gear:before,
+.icon-cog:before {
+ content: "\f013";
+}
+.icon-trash:before {
+ content: "\f014";
+}
+.icon-home:before {
+ content: "\f015";
+}
+.icon-file-alt:before {
+ content: "\f016";
+}
+.icon-time:before {
+ content: "\f017";
+}
+.icon-road:before {
+ content: "\f018";
+}
+.icon-download-alt:before {
+ content: "\f019";
+}
+.icon-download:before {
+ content: "\f01a";
+}
+.icon-upload:before {
+ content: "\f01b";
+}
+.icon-inbox:before {
+ content: "\f01c";
+}
+.icon-play-circle:before {
+ content: "\f01d";
+}
+.icon-rotate-right:before,
+.icon-repeat:before {
+ content: "\f01e";
+}
+.icon-refresh:before {
+ content: "\f021";
+}
+.icon-list-alt:before {
+ content: "\f022";
+}
+.icon-lock:before {
+ content: "\f023";
+}
+.icon-flag:before {
+ content: "\f024";
+}
+.icon-headphones:before {
+ content: "\f025";
+}
+.icon-volume-off:before {
+ content: "\f026";
+}
+.icon-volume-down:before {
+ content: "\f027";
+}
+.icon-volume-up:before {
+ content: "\f028";
+}
+.icon-qrcode:before {
+ content: "\f029";
+}
+.icon-barcode:before {
+ content: "\f02a";
+}
+.icon-tag:before {
+ content: "\f02b";
+}
+.icon-tags:before {
+ content: "\f02c";
+}
+.icon-book:before {
+ content: "\f02d";
+}
+.icon-bookmark:before {
+ content: "\f02e";
+}
+.icon-print:before {
+ content: "\f02f";
+}
+.icon-camera:before {
+ content: "\f030";
+}
+.icon-font:before {
+ content: "\f031";
+}
+.icon-bold:before {
+ content: "\f032";
+}
+.icon-italic:before {
+ content: "\f033";
+}
+.icon-text-height:before {
+ content: "\f034";
+}
+.icon-text-width:before {
+ content: "\f035";
+}
+.icon-align-left:before {
+ content: "\f036";
+}
+.icon-align-center:before {
+ content: "\f037";
+}
+.icon-align-right:before {
+ content: "\f038";
+}
+.icon-align-justify:before {
+ content: "\f039";
+}
+.icon-list:before {
+ content: "\f03a";
+}
+.icon-indent-left:before {
+ content: "\f03b";
+}
+.icon-indent-right:before {
+ content: "\f03c";
+}
+.icon-facetime-video:before {
+ content: "\f03d";
+}
+.icon-picture:before {
+ content: "\f03e";
+}
+.icon-pencil:before {
+ content: "\f040";
+}
+.icon-map-marker:before {
+ content: "\f041";
+}
+.icon-adjust:before {
+ content: "\f042";
+}
+.icon-tint:before {
+ content: "\f043";
+}
+.icon-edit:before {
+ content: "\f044";
+}
+.icon-share:before {
+ content: "\f045";
+}
+.icon-check:before {
+ content: "\f046";
+}
+.icon-move:before {
+ content: "\f047";
+}
+.icon-step-backward:before {
+ content: "\f048";
+}
+.icon-fast-backward:before {
+ content: "\f049";
+}
+.icon-backward:before {
+ content: "\f04a";
+}
+.icon-play:before {
+ content: "\f04b";
+}
+.icon-pause:before {
+ content: "\f04c";
+}
+.icon-stop:before {
+ content: "\f04d";
+}
+.icon-forward:before {
+ content: "\f04e";
+}
+.icon-fast-forward:before {
+ content: "\f050";
+}
+.icon-step-forward:before {
+ content: "\f051";
+}
+.icon-eject:before {
+ content: "\f052";
+}
+.icon-chevron-left:before {
+ content: "\f053";
+}
+.icon-chevron-right:before {
+ content: "\f054";
+}
+.icon-plus-sign:before {
+ content: "\f055";
+}
+.icon-minus-sign:before {
+ content: "\f056";
+}
+.icon-remove-sign:before {
+ content: "\f057";
+}
+.icon-ok-sign:before {
+ content: "\f058";
+}
+.icon-question-sign:before {
+ content: "\f059";
+}
+.icon-info-sign:before {
+ content: "\f05a";
+}
+.icon-screenshot:before {
+ content: "\f05b";
+}
+.icon-remove-circle:before {
+ content: "\f05c";
+}
+.icon-ok-circle:before {
+ content: "\f05d";
+}
+.icon-ban-circle:before {
+ content: "\f05e";
+}
+.icon-arrow-left:before {
+ content: "\f060";
+}
+.icon-arrow-right:before {
+ content: "\f061";
+}
+.icon-arrow-up:before {
+ content: "\f062";
+}
+.icon-arrow-down:before {
+ content: "\f063";
+}
+.icon-mail-forward:before,
+.icon-share-alt:before {
+ content: "\f064";
+}
+.icon-resize-full:before {
+ content: "\f065";
+}
+.icon-resize-small:before {
+ content: "\f066";
+}
+.icon-plus:before {
+ content: "\f067";
+}
+.icon-minus:before {
+ content: "\f068";
+}
+.icon-asterisk:before {
+ content: "\f069";
+}
+.icon-exclamation-sign:before {
+ content: "\f06a";
+}
+.icon-gift:before {
+ content: "\f06b";
+}
+.icon-leaf:before {
+ content: "\f06c";
+}
+.icon-fire:before {
+ content: "\f06d";
+}
+.icon-eye-open:before {
+ content: "\f06e";
+}
+.icon-eye-close:before {
+ content: "\f070";
+}
+.icon-warning-sign:before {
+ content: "\f071";
+}
+.icon-plane:before {
+ content: "\f072";
+}
+.icon-calendar:before {
+ content: "\f073";
+}
+.icon-random:before {
+ content: "\f074";
+}
+.icon-comment:before {
+ content: "\f075";
+}
+.icon-magnet:before {
+ content: "\f076";
+}
+.icon-chevron-up:before {
+ content: "\f077";
+}
+.icon-chevron-down:before {
+ content: "\f078";
+}
+.icon-retweet:before {
+ content: "\f079";
+}
+.icon-shopping-cart:before {
+ content: "\f07a";
+}
+.icon-folder-close:before {
+ content: "\f07b";
+}
+.icon-folder-open:before {
+ content: "\f07c";
+}
+.icon-resize-vertical:before {
+ content: "\f07d";
+}
+.icon-resize-horizontal:before {
+ content: "\f07e";
+}
+.icon-bar-chart:before {
+ content: "\f080";
+}
+.icon-twitter-sign:before {
+ content: "\f081";
+}
+.icon-facebook-sign:before {
+ content: "\f082";
+}
+.icon-camera-retro:before {
+ content: "\f083";
+}
+.icon-key:before {
+ content: "\f084";
+}
+.icon-gears:before,
+.icon-cogs:before {
+ content: "\f085";
+}
+.icon-comments:before {
+ content: "\f086";
+}
+.icon-thumbs-up-alt:before {
+ content: "\f087";
+}
+.icon-thumbs-down-alt:before {
+ content: "\f088";
+}
+.icon-star-half:before {
+ content: "\f089";
+}
+.icon-heart-empty:before {
+ content: "\f08a";
+}
+.icon-signout:before {
+ content: "\f08b";
+}
+.icon-linkedin-sign:before {
+ content: "\f08c";
+}
+.icon-pushpin:before {
+ content: "\f08d";
+}
+.icon-external-link:before {
+ content: "\f08e";
+}
+.icon-signin:before {
+ content: "\f090";
+}
+.icon-trophy:before {
+ content: "\f091";
+}
+.icon-github-sign:before {
+ content: "\f092";
+}
+.icon-upload-alt:before {
+ content: "\f093";
+}
+.icon-lemon:before {
+ content: "\f094";
+}
+.icon-phone:before {
+ content: "\f095";
+}
+.icon-unchecked:before,
+.icon-check-empty:before {
+ content: "\f096";
+}
+.icon-bookmark-empty:before {
+ content: "\f097";
+}
+.icon-phone-sign:before {
+ content: "\f098";
+}
+.icon-twitter:before {
+ content: "\f099";
+}
+.icon-facebook:before {
+ content: "\f09a";
+}
+.icon-github:before {
+ content: "\f09b";
+}
+.icon-unlock:before {
+ content: "\f09c";
+}
+.icon-credit-card:before {
+ content: "\f09d";
+}
+.icon-rss:before {
+ content: "\f09e";
+}
+.icon-hdd:before {
+ content: "\f0a0";
+}
+.icon-bullhorn:before {
+ content: "\f0a1";
+}
+.icon-bell:before {
+ content: "\f0a2";
+}
+.icon-certificate:before {
+ content: "\f0a3";
+}
+.icon-hand-right:before {
+ content: "\f0a4";
+}
+.icon-hand-left:before {
+ content: "\f0a5";
+}
+.icon-hand-up:before {
+ content: "\f0a6";
+}
+.icon-hand-down:before {
+ content: "\f0a7";
+}
+.icon-circle-arrow-left:before {
+ content: "\f0a8";
+}
+.icon-circle-arrow-right:before {
+ content: "\f0a9";
+}
+.icon-circle-arrow-up:before {
+ content: "\f0aa";
+}
+.icon-circle-arrow-down:before {
+ content: "\f0ab";
+}
+.icon-globe:before {
+ content: "\f0ac";
+}
+.icon-wrench:before {
+ content: "\f0ad";
+}
+.icon-tasks:before {
+ content: "\f0ae";
+}
+.icon-filter:before {
+ content: "\f0b0";
+}
+.icon-briefcase:before {
+ content: "\f0b1";
+}
+.icon-fullscreen:before {
+ content: "\f0b2";
+}
+.icon-group:before {
+ content: "\f0c0";
+}
+.icon-link:before {
+ content: "\f0c1";
+}
+.icon-cloud:before {
+ content: "\f0c2";
+}
+.icon-beaker:before {
+ content: "\f0c3";
+}
+.icon-cut:before {
+ content: "\f0c4";
+}
+.icon-copy:before {
+ content: "\f0c5";
+}
+.icon-paperclip:before,
+.icon-paper-clip:before {
+ content: "\f0c6";
+}
+.icon-save:before {
+ content: "\f0c7";
+}
+.icon-sign-blank:before {
+ content: "\f0c8";
+}
+.icon-reorder:before {
+ content: "\f0c9";
+}
+.icon-list-ul:before {
+ content: "\f0ca";
+}
+.icon-list-ol:before {
+ content: "\f0cb";
+}
+.icon-strikethrough:before {
+ content: "\f0cc";
+}
+.icon-underline:before {
+ content: "\f0cd";
+}
+.icon-table:before {
+ content: "\f0ce";
+}
+.icon-magic:before {
+ content: "\f0d0";
+}
+.icon-truck:before {
+ content: "\f0d1";
+}
+.icon-pinterest:before {
+ content: "\f0d2";
+}
+.icon-pinterest-sign:before {
+ content: "\f0d3";
+}
+.icon-google-plus-sign:before {
+ content: "\f0d4";
+}
+.icon-google-plus:before {
+ content: "\f0d5";
+}
+.icon-money:before {
+ content: "\f0d6";
+}
+.icon-caret-down:before {
+ content: "\f0d7";
+}
+.icon-caret-up:before {
+ content: "\f0d8";
+}
+.icon-caret-left:before {
+ content: "\f0d9";
+}
+.icon-caret-right:before {
+ content: "\f0da";
+}
+.icon-columns:before {
+ content: "\f0db";
+}
+.icon-sort:before {
+ content: "\f0dc";
+}
+.icon-sort-down:before {
+ content: "\f0dd";
+}
+.icon-sort-up:before {
+ content: "\f0de";
+}
+.icon-envelope:before {
+ content: "\f0e0";
+}
+.icon-linkedin:before {
+ content: "\f0e1";
+}
+.icon-rotate-left:before,
+.icon-undo:before {
+ content: "\f0e2";
+}
+.icon-legal:before {
+ content: "\f0e3";
+}
+.icon-dashboard:before {
+ content: "\f0e4";
+}
+.icon-comment-alt:before {
+ content: "\f0e5";
+}
+.icon-comments-alt:before {
+ content: "\f0e6";
+}
+.icon-bolt:before {
+ content: "\f0e7";
+}
+.icon-sitemap:before {
+ content: "\f0e8";
+}
+.icon-umbrella:before {
+ content: "\f0e9";
+}
+.icon-paste:before {
+ content: "\f0ea";
+}
+.icon-lightbulb:before {
+ content: "\f0eb";
+}
+.icon-exchange:before {
+ content: "\f0ec";
+}
+.icon-cloud-download:before {
+ content: "\f0ed";
+}
+.icon-cloud-upload:before {
+ content: "\f0ee";
+}
+.icon-user-md:before {
+ content: "\f0f0";
+}
+.icon-stethoscope:before {
+ content: "\f0f1";
+}
+.icon-suitcase:before {
+ content: "\f0f2";
+}
+.icon-bell-alt:before {
+ content: "\f0f3";
+}
+.icon-coffee:before {
+ content: "\f0f4";
+}
+.icon-food:before {
+ content: "\f0f5";
+}
+.icon-file-text-alt:before {
+ content: "\f0f6";
+}
+.icon-building:before {
+ content: "\f0f7";
+}
+.icon-hospital:before {
+ content: "\f0f8";
+}
+.icon-ambulance:before {
+ content: "\f0f9";
+}
+.icon-medkit:before {
+ content: "\f0fa";
+}
+.icon-fighter-jet:before {
+ content: "\f0fb";
+}
+.icon-beer:before {
+ content: "\f0fc";
+}
+.icon-h-sign:before {
+ content: "\f0fd";
+}
+.icon-plus-sign-alt:before {
+ content: "\f0fe";
+}
+.icon-double-angle-left:before {
+ content: "\f100";
+}
+.icon-double-angle-right:before {
+ content: "\f101";
+}
+.icon-double-angle-up:before {
+ content: "\f102";
+}
+.icon-double-angle-down:before {
+ content: "\f103";
+}
+.icon-angle-left:before {
+ content: "\f104";
+}
+.icon-angle-right:before {
+ content: "\f105";
+}
+.icon-angle-up:before {
+ content: "\f106";
+}
+.icon-angle-down:before {
+ content: "\f107";
+}
+.icon-desktop:before {
+ content: "\f108";
+}
+.icon-laptop:before {
+ content: "\f109";
+}
+.icon-tablet:before {
+ content: "\f10a";
+}
+.icon-mobile-phone:before {
+ content: "\f10b";
+}
+.icon-circle-blank:before {
+ content: "\f10c";
+}
+.icon-quote-left:before {
+ content: "\f10d";
+}
+.icon-quote-right:before {
+ content: "\f10e";
+}
+.icon-spinner:before {
+ content: "\f110";
+}
+.icon-circle:before {
+ content: "\f111";
+}
+.icon-mail-reply:before,
+.icon-reply:before {
+ content: "\f112";
+}
+.icon-github-alt:before {
+ content: "\f113";
+}
+.icon-folder-close-alt:before {
+ content: "\f114";
+}
+.icon-folder-open-alt:before {
+ content: "\f115";
+}
+.icon-expand-alt:before {
+ content: "\f116";
+}
+.icon-collapse-alt:before {
+ content: "\f117";
+}
+.icon-smile:before {
+ content: "\f118";
+}
+.icon-frown:before {
+ content: "\f119";
+}
+.icon-meh:before {
+ content: "\f11a";
+}
+.icon-gamepad:before {
+ content: "\f11b";
+}
+.icon-keyboard:before {
+ content: "\f11c";
+}
+.icon-flag-alt:before {
+ content: "\f11d";
+}
+.icon-flag-checkered:before {
+ content: "\f11e";
+}
+.icon-terminal:before {
+ content: "\f120";
+}
+.icon-code:before {
+ content: "\f121";
+}
+.icon-reply-all:before {
+ content: "\f122";
+}
+.icon-mail-reply-all:before {
+ content: "\f122";
+}
+.icon-star-half-full:before,
+.icon-star-half-empty:before {
+ content: "\f123";
+}
+.icon-location-arrow:before {
+ content: "\f124";
+}
+.icon-crop:before {
+ content: "\f125";
+}
+.icon-code-fork:before {
+ content: "\f126";
+}
+.icon-unlink:before {
+ content: "\f127";
+}
+.icon-question:before {
+ content: "\f128";
+}
+.icon-info:before {
+ content: "\f129";
+}
+.icon-exclamation:before {
+ content: "\f12a";
+}
+.icon-superscript:before {
+ content: "\f12b";
+}
+.icon-subscript:before {
+ content: "\f12c";
+}
+.icon-eraser:before {
+ content: "\f12d";
+}
+.icon-puzzle-piece:before {
+ content: "\f12e";
+}
+.icon-microphone:before {
+ content: "\f130";
+}
+.icon-microphone-off:before {
+ content: "\f131";
+}
+.icon-shield:before {
+ content: "\f132";
+}
+.icon-calendar-empty:before {
+ content: "\f133";
+}
+.icon-fire-extinguisher:before {
+ content: "\f134";
+}
+.icon-rocket:before {
+ content: "\f135";
+}
+.icon-maxcdn:before {
+ content: "\f136";
+}
+.icon-chevron-sign-left:before {
+ content: "\f137";
+}
+.icon-chevron-sign-right:before {
+ content: "\f138";
+}
+.icon-chevron-sign-up:before {
+ content: "\f139";
+}
+.icon-chevron-sign-down:before {
+ content: "\f13a";
+}
+.icon-html5:before {
+ content: "\f13b";
+}
+.icon-css3:before {
+ content: "\f13c";
+}
+.icon-anchor:before {
+ content: "\f13d";
+}
+.icon-unlock-alt:before {
+ content: "\f13e";
+}
+.icon-bullseye:before {
+ content: "\f140";
+}
+.icon-ellipsis-horizontal:before {
+ content: "\f141";
+}
+.icon-ellipsis-vertical:before {
+ content: "\f142";
+}
+.icon-rss-sign:before {
+ content: "\f143";
+}
+.icon-play-sign:before {
+ content: "\f144";
+}
+.icon-ticket:before {
+ content: "\f145";
+}
+.icon-minus-sign-alt:before {
+ content: "\f146";
+}
+.icon-check-minus:before {
+ content: "\f147";
+}
+.icon-level-up:before {
+ content: "\f148";
+}
+.icon-level-down:before {
+ content: "\f149";
+}
+.icon-check-sign:before {
+ content: "\f14a";
+}
+.icon-edit-sign:before {
+ content: "\f14b";
+}
+.icon-external-link-sign:before {
+ content: "\f14c";
+}
+.icon-share-sign:before {
+ content: "\f14d";
+}
+.icon-compass:before {
+ content: "\f14e";
+}
+.icon-collapse:before {
+ content: "\f150";
+}
+.icon-collapse-top:before {
+ content: "\f151";
+}
+.icon-expand:before {
+ content: "\f152";
+}
+.icon-euro:before,
+.icon-eur:before {
+ content: "\f153";
+}
+.icon-gbp:before {
+ content: "\f154";
+}
+.icon-dollar:before,
+.icon-usd:before {
+ content: "\f155";
+}
+.icon-rupee:before,
+.icon-inr:before {
+ content: "\f156";
+}
+.icon-yen:before,
+.icon-jpy:before {
+ content: "\f157";
+}
+.icon-renminbi:before,
+.icon-cny:before {
+ content: "\f158";
+}
+.icon-won:before,
+.icon-krw:before {
+ content: "\f159";
+}
+.icon-bitcoin:before,
+.icon-btc:before {
+ content: "\f15a";
+}
+.icon-file:before {
+ content: "\f15b";
+}
+.icon-file-text:before {
+ content: "\f15c";
+}
+.icon-sort-by-alphabet:before {
+ content: "\f15d";
+}
+.icon-sort-by-alphabet-alt:before {
+ content: "\f15e";
+}
+.icon-sort-by-attributes:before {
+ content: "\f160";
+}
+.icon-sort-by-attributes-alt:before {
+ content: "\f161";
+}
+.icon-sort-by-order:before {
+ content: "\f162";
+}
+.icon-sort-by-order-alt:before {
+ content: "\f163";
+}
+.icon-thumbs-up:before {
+ content: "\f164";
+}
+.icon-thumbs-down:before {
+ content: "\f165";
+}
+.icon-youtube-sign:before {
+ content: "\f166";
+}
+.icon-youtube:before {
+ content: "\f167";
+}
+.icon-xing:before {
+ content: "\f168";
+}
+.icon-xing-sign:before {
+ content: "\f169";
+}
+.icon-youtube-play:before {
+ content: "\f16a";
+}
+.icon-dropbox:before {
+ content: "\f16b";
+}
+.icon-stackexchange:before {
+ content: "\f16c";
+}
+.icon-instagram:before {
+ content: "\f16d";
+}
+.icon-flickr:before {
+ content: "\f16e";
+}
+.icon-adn:before {
+ content: "\f170";
+}
+.icon-bitbucket:before {
+ content: "\f171";
+}
+.icon-bitbucket-sign:before {
+ content: "\f172";
+}
+.icon-tumblr:before {
+ content: "\f173";
+}
+.icon-tumblr-sign:before {
+ content: "\f174";
+}
+.icon-long-arrow-down:before {
+ content: "\f175";
+}
+.icon-long-arrow-up:before {
+ content: "\f176";
+}
+.icon-long-arrow-left:before {
+ content: "\f177";
+}
+.icon-long-arrow-right:before {
+ content: "\f178";
+}
+.icon-apple:before {
+ content: "\f179";
+}
+.icon-windows:before {
+ content: "\f17a";
+}
+.icon-android:before {
+ content: "\f17b";
+}
+.icon-linux:before {
+ content: "\f17c";
+}
+.icon-dribbble:before {
+ content: "\f17d";
+}
+.icon-skype:before {
+ content: "\f17e";
+}
+.icon-foursquare:before {
+ content: "\f180";
+}
+.icon-trello:before {
+ content: "\f181";
+}
+.icon-female:before {
+ content: "\f182";
+}
+.icon-male:before {
+ content: "\f183";
+}
+.icon-gittip:before {
+ content: "\f184";
+}
+.icon-sun:before {
+ content: "\f185";
+}
+.icon-moon:before {
+ content: "\f186";
+}
+.icon-archive:before {
+ content: "\f187";
+}
+.icon-bug:before {
+ content: "\f188";
+}
+.icon-vk:before {
+ content: "\f189";
+}
+.icon-weibo:before {
+ content: "\f18a";
+}
+.icon-renren:before {
+ content: "\f18b";
+}
+.icon-address:before {
+ content: "\f02d";
+}
+.icon-arrow-down-2:before {
+ content: "\f0ab";
+}
+.icon-arrow-down-3:before {
+ content: "\f0d7";
+}
+.icon-arrow-first:before {
+ content: "\f048";
+}
+.icon-arrow-last:before {
+ content: "\f051";
+}
+.icon-arrow-left-2:before {
+ content: "\f0a8";
+}
+.icon-arrow-left-3:before {
+ content: "\f0d9";
+}
+.icon-arrow-right-2:before {
+ content: "\f0a9";
+}
+.icon-arrow-right-3:before {
+ content: "\f0da";
+}
+.icon-arrow-up-2:before {
+ content: "\f0aa";
+}
+.icon-arrow-up-3:before {
+ content: "\f0d8";
+}
+.icon-bars:before {
+ content: "\f080";
+}
+.icon-basket:before {
+ content: "\f07a";
+}
+.icon-box-add:before {
+ content: "\f019";
+}
+.icon-box-remove:before {
+ content: "\f093";
+}
+.icon-broadcast:before {
+ content: "\f012";
+}
+.icon-brush:before {
+ content: "\f043";
+}
+.icon-calendar-2:before {
+ content: "\f073";
+}
+.icon-camera-2:before {
+ content: "\f03d";
+}
+.icon-cancel:before {
+ content: "\f057";
+}
+.icon-cancel-2:before {
+ content: "\f00d";
+}
+.icon-cart:before {
+ content: "\f07a";
+}
+.icon-chart:before {
+ content: "\f080";
+}
+.icon-checkbox:before {
+ content: "\f046";
+}
+.icon-checkbox-partial:before {
+ content: "\f147";
+}
+.icon-checkbox-unchecked:before {
+ content: "\f096";
+}
+.icon-checkmark:before {
+ content: "\f00c";
+}
+.icon-clock:before {
+ content: "\f017";
+}
+.icon-color-palette:before {
+ content: "\f0e4";
+}
+.icon-comments-2:before {
+ content: "\f086";
+}
+.icon-contract:before {
+ content: "\f066";
+}
+.icon-contract-2:before {
+ content: "\f066";
+}
+.icon-cube:before {
+ content: "\f01c";
+}
+.icon-database:before {
+ content: "\f0a0";
+}
+.icon-drawer:before {
+ content: "\f01c";
+}
+.icon-drawer-2:before {
+ content: "\f01c";
+}
+.icon-expand:before {
+ content: "\f065";
+}
+.icon-expand-2:before {
+ content: "\f0b2";
+}
+.icon-eye:before {
+ content: "\f06e";
+}
+.icon-feed:before {
+ content: "\f143";
+}
+.icon-file-add:before {
+ content: "\f116";
+}
+.icon-file-remove:before {
+ content: "\f117";
+}
+.icon-first:before {
+ content: "\f049";
+}
+.icon-flag-2:before {
+ content: "\f0c6";
+}
+.icon-folder:before {
+ content: "\f07c";
+}
+.icon-folder-2:before {
+ content: "\f07b";
+}
+.icon-grid-view:before {
+ content: "\f0db";
+}
+.icon-grid-view-2:before {
+ content: "\f00a";
+}
+.icon-health:before {
+ content: "\f0f1";
+}
+.icon-help:before {
+ content: "\f059";
+}
+.icon-lamp:before {
+ content: "\f0eb";
+}
+.icon-last:before {
+ content: "\f050";
+}
+.icon-lightning:before {
+ content: "\f0e7";
+}
+.icon-list-view:before {
+ content: "\f0ca";
+}
+.icon-location:before {
+ content: "\f041";
+}
+.icon-locked:before {
+ content: "\f023";
+}
+.icon-loop:before {
+ content: "\f021";
+}
+.icon-mail:before {
+ content: "\f0e0";
+}
+.icon-mail-2:before {
+ content: "\f003";
+}
+.icon-menu:before {
+ content: "\f142";
+}
+.icon-menu-2:before {
+ content: "\f0dc";
+}
+.icon-minus-2:before {
+ content: "\f068";
+}
+.icon-mobile:before {
+ content: "\f10b";
+}
+.icon-next:before {
+ content: "\f04e";
+}
+.icon-out:before {
+ content: "\f045";
+}
+.icon-out-2:before {
+ content: "\f08b";
+}
+.icon-pencil-2:before {
+ content: "\f040";
+}
+.icon-pictures:before {
+ content: "\f03e";
+}
+.icon-pin:before {
+ content: "\f08d";
+}
+.icon-play-2:before {
+ content: "\f01d";
+}
+.icon-plus-2:before {
+ content: "\f067";
+}
+.icon-power-cord:before {
+ content: "\f076";
+}
+.icon-previous:before {
+ content: "\f04a";
+}
+.icon-printer:before {
+ content: "\f02f";
+}
+.icon-puzzle:before {
+ content: "\f12e";
+}
+.icon-quote:before {
+ content: "\f10d";
+}
+.icon-quote-2:before {
+ content: "\f10e";
+}
+.icon-redo:before {
+ content: "\f064";
+}
+.icon-screen:before {
+ content: "\f108";
+}
+.icon-shuffle:before {
+ content: "\f074";
+}
+.icon-star-2:before {
+ content: "\f123";
+}
+.icon-support:before {
+ content: "\f05b";
+}
+.icon-tools:before {
+ content: "\f0ad";
+}
+.icon-users:before {
+ content: "\f0c0";
+}
+.icon-vcard:before {
+ content: "\f18b";
+}
+.icon-wand:before {
+ content: "\f0d0";
+}
+.icon-warning:before {
+ content: "\f071";
+}
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.min.css b/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.min.css
new file mode 100644
index 0000000..65a2996
--- /dev/null
+++ b/plugins/system/t3/base-bs3/fonts/font-awesome/css/font-awesome.min.css
@@ -0,0 +1,25 @@
+/*!
+ * Font Awesome 3.2.1
+ * the iconic font designed for Bootstrap
+ * ------------------------------------------------------------------------------
+ * The full suite of pictographic icons, examples, and documentation can be
+ * found at http://fontawesome.io. Stay up to date on Twitter at
+ * http://twitter.com/fontawesome.
+ *
+ * License
+ * ------------------------------------------------------------------------------
+ * - The Font Awesome font is licensed under SIL OFL 1.1 -
+ * http://scripts.sil.org/OFL
+ * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -
+ * http://opensource.org/licenses/mit-license.html
+ * - Font Awesome documentation licensed under CC BY 3.0 -
+ * http://creativecommons.org/licenses/by/3.0/
+ * - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
+ * "Font Awesome by Dave Gandy - http://fontawesome.io"
+ *
+ * Author - Dave Gandy
+ * ------------------------------------------------------------------------------
+ * Email: dave@fontawesome.io
+ * Twitter: http://twitter.com/davegandy
+ * Work: Lead Product Designer @ Kyruus - http://kyruus.com
+ */@font-face{font-family:'FontAwesome3';src:url('../font/fontawesome-webfont.eot?v=3.2.1');src:url('../font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome3;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}[class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}.icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}a [class^="icon-"],a [class*=" icon-"]{display:inline}[class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}.icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}.icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}[class^="icon-"].hide,[class*=" icon-"].hide{display:none}.icon-muted{color:#eee}.icon-light{color:#fff}.icon-dark{color:#333}.icon-border{border:solid 1px #eee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.pull-right{float:right}.pull-left{float:left}[class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}[class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}[class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}.btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}.nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}.btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}.btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}.btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}.icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}.icon-stack .icon-stack-base{font-size:2em;*line-height:1em}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}.icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}.icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}.icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}.icon-glass:before{content:"\f000"}.icon-music:before{content:"\f001"}.icon-search:before{content:"\f002"}.icon-envelope-alt:before{content:"\f003"}.icon-heart:before{content:"\f004"}.icon-star:before{content:"\f005"}.icon-star-empty:before{content:"\f006"}.icon-user:before{content:"\f007"}.icon-film:before{content:"\f008"}.icon-th-large:before{content:"\f009"}.icon-th:before{content:"\f00a"}.icon-th-list:before{content:"\f00b"}.icon-ok:before{content:"\f00c"}.icon-remove:before{content:"\f00d"}.icon-zoom-in:before{content:"\f00e"}.icon-zoom-out:before{content:"\f010"}.icon-power-off:before,.icon-off:before{content:"\f011"}.icon-signal:before{content:"\f012"}.icon-gear:before,.icon-cog:before{content:"\f013"}.icon-trash:before{content:"\f014"}.icon-home:before{content:"\f015"}.icon-file-alt:before{content:"\f016"}.icon-time:before{content:"\f017"}.icon-road:before{content:"\f018"}.icon-download-alt:before{content:"\f019"}.icon-download:before{content:"\f01a"}.icon-upload:before{content:"\f01b"}.icon-inbox:before{content:"\f01c"}.icon-play-circle:before{content:"\f01d"}.icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}.icon-refresh:before{content:"\f021"}.icon-list-alt:before{content:"\f022"}.icon-lock:before{content:"\f023"}.icon-flag:before{content:"\f024"}.icon-headphones:before{content:"\f025"}.icon-volume-off:before{content:"\f026"}.icon-volume-down:before{content:"\f027"}.icon-volume-up:before{content:"\f028"}.icon-qrcode:before{content:"\f029"}.icon-barcode:before{content:"\f02a"}.icon-tag:before{content:"\f02b"}.icon-tags:before{content:"\f02c"}.icon-book:before{content:"\f02d"}.icon-bookmark:before{content:"\f02e"}.icon-print:before{content:"\f02f"}.icon-camera:before{content:"\f030"}.icon-font:before{content:"\f031"}.icon-bold:before{content:"\f032"}.icon-italic:before{content:"\f033"}.icon-text-height:before{content:"\f034"}.icon-text-width:before{content:"\f035"}.icon-align-left:before{content:"\f036"}.icon-align-center:before{content:"\f037"}.icon-align-right:before{content:"\f038"}.icon-align-justify:before{content:"\f039"}.icon-list:before{content:"\f03a"}.icon-indent-left:before{content:"\f03b"}.icon-indent-right:before{content:"\f03c"}.icon-facetime-video:before{content:"\f03d"}.icon-picture:before{content:"\f03e"}.icon-pencil:before{content:"\f040"}.icon-map-marker:before{content:"\f041"}.icon-adjust:before{content:"\f042"}.icon-tint:before{content:"\f043"}.icon-edit:before{content:"\f044"}.icon-share:before{content:"\f045"}.icon-check:before{content:"\f046"}.icon-move:before{content:"\f047"}.icon-step-backward:before{content:"\f048"}.icon-fast-backward:before{content:"\f049"}.icon-backward:before{content:"\f04a"}.icon-play:before{content:"\f04b"}.icon-pause:before{content:"\f04c"}.icon-stop:before{content:"\f04d"}.icon-forward:before{content:"\f04e"}.icon-fast-forward:before{content:"\f050"}.icon-step-forward:before{content:"\f051"}.icon-eject:before{content:"\f052"}.icon-chevron-left:before{content:"\f053"}.icon-chevron-right:before{content:"\f054"}.icon-plus-sign:before{content:"\f055"}.icon-minus-sign:before{content:"\f056"}.icon-remove-sign:before{content:"\f057"}.icon-ok-sign:before{content:"\f058"}.icon-question-sign:before{content:"\f059"}.icon-info-sign:before{content:"\f05a"}.icon-screenshot:before{content:"\f05b"}.icon-remove-circle:before{content:"\f05c"}.icon-ok-circle:before{content:"\f05d"}.icon-ban-circle:before{content:"\f05e"}.icon-arrow-left:before{content:"\f060"}.icon-arrow-right:before{content:"\f061"}.icon-arrow-up:before{content:"\f062"}.icon-arrow-down:before{content:"\f063"}.icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}.icon-resize-full:before{content:"\f065"}.icon-resize-small:before{content:"\f066"}.icon-plus:before{content:"\f067"}.icon-minus:before{content:"\f068"}.icon-asterisk:before{content:"\f069"}.icon-exclamation-sign:before{content:"\f06a"}.icon-gift:before{content:"\f06b"}.icon-leaf:before{content:"\f06c"}.icon-fire:before{content:"\f06d"}.icon-eye-open:before{content:"\f06e"}.icon-eye-close:before{content:"\f070"}.icon-warning-sign:before{content:"\f071"}.icon-plane:before{content:"\f072"}.icon-calendar:before{content:"\f073"}.icon-random:before{content:"\f074"}.icon-comment:before{content:"\f075"}.icon-magnet:before{content:"\f076"}.icon-chevron-up:before{content:"\f077"}.icon-chevron-down:before{content:"\f078"}.icon-retweet:before{content:"\f079"}.icon-shopping-cart:before{content:"\f07a"}.icon-folder-close:before{content:"\f07b"}.icon-folder-open:before{content:"\f07c"}.icon-resize-vertical:before{content:"\f07d"}.icon-resize-horizontal:before{content:"\f07e"}.icon-bar-chart:before{content:"\f080"}.icon-twitter-sign:before{content:"\f081"}.icon-facebook-sign:before{content:"\f082"}.icon-camera-retro:before{content:"\f083"}.icon-key:before{content:"\f084"}.icon-gears:before,.icon-cogs:before{content:"\f085"}.icon-comments:before{content:"\f086"}.icon-thumbs-up-alt:before{content:"\f087"}.icon-thumbs-down-alt:before{content:"\f088"}.icon-star-half:before{content:"\f089"}.icon-heart-empty:before{content:"\f08a"}.icon-signout:before{content:"\f08b"}.icon-linkedin-sign:before{content:"\f08c"}.icon-pushpin:before{content:"\f08d"}.icon-external-link:before{content:"\f08e"}.icon-signin:before{content:"\f090"}.icon-trophy:before{content:"\f091"}.icon-github-sign:before{content:"\f092"}.icon-upload-alt:before{content:"\f093"}.icon-lemon:before{content:"\f094"}.icon-phone:before{content:"\f095"}.icon-unchecked:before,.icon-check-empty:before{content:"\f096"}.icon-bookmark-empty:before{content:"\f097"}.icon-phone-sign:before{content:"\f098"}.icon-twitter:before{content:"\f099"}.icon-facebook:before{content:"\f09a"}.icon-github:before{content:"\f09b"}.icon-unlock:before{content:"\f09c"}.icon-credit-card:before{content:"\f09d"}.icon-rss:before{content:"\f09e"}.icon-hdd:before{content:"\f0a0"}.icon-bullhorn:before{content:"\f0a1"}.icon-bell:before{content:"\f0a2"}.icon-certificate:before{content:"\f0a3"}.icon-hand-right:before{content:"\f0a4"}.icon-hand-left:before{content:"\f0a5"}.icon-hand-up:before{content:"\f0a6"}.icon-hand-down:before{content:"\f0a7"}.icon-circle-arrow-left:before{content:"\f0a8"}.icon-circle-arrow-right:before{content:"\f0a9"}.icon-circle-arrow-up:before{content:"\f0aa"}.icon-circle-arrow-down:before{content:"\f0ab"}.icon-globe:before{content:"\f0ac"}.icon-wrench:before{content:"\f0ad"}.icon-tasks:before{content:"\f0ae"}.icon-filter:before{content:"\f0b0"}.icon-briefcase:before{content:"\f0b1"}.icon-fullscreen:before{content:"\f0b2"}.icon-group:before{content:"\f0c0"}.icon-link:before{content:"\f0c1"}.icon-cloud:before{content:"\f0c2"}.icon-beaker:before{content:"\f0c3"}.icon-cut:before{content:"\f0c4"}.icon-copy:before{content:"\f0c5"}.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}.icon-save:before{content:"\f0c7"}.icon-sign-blank:before{content:"\f0c8"}.icon-reorder:before{content:"\f0c9"}.icon-list-ul:before{content:"\f0ca"}.icon-list-ol:before{content:"\f0cb"}.icon-strikethrough:before{content:"\f0cc"}.icon-underline:before{content:"\f0cd"}.icon-table:before{content:"\f0ce"}.icon-magic:before{content:"\f0d0"}.icon-truck:before{content:"\f0d1"}.icon-pinterest:before{content:"\f0d2"}.icon-pinterest-sign:before{content:"\f0d3"}.icon-google-plus-sign:before{content:"\f0d4"}.icon-google-plus:before{content:"\f0d5"}.icon-money:before{content:"\f0d6"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-columns:before{content:"\f0db"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-envelope:before{content:"\f0e0"}.icon-linkedin:before{content:"\f0e1"}.icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}.icon-legal:before{content:"\f0e3"}.icon-dashboard:before{content:"\f0e4"}.icon-comment-alt:before{content:"\f0e5"}.icon-comments-alt:before{content:"\f0e6"}.icon-bolt:before{content:"\f0e7"}.icon-sitemap:before{content:"\f0e8"}.icon-umbrella:before{content:"\f0e9"}.icon-paste:before{content:"\f0ea"}.icon-lightbulb:before{content:"\f0eb"}.icon-exchange:before{content:"\f0ec"}.icon-cloud-download:before{content:"\f0ed"}.icon-cloud-upload:before{content:"\f0ee"}.icon-user-md:before{content:"\f0f0"}.icon-stethoscope:before{content:"\f0f1"}.icon-suitcase:before{content:"\f0f2"}.icon-bell-alt:before{content:"\f0f3"}.icon-coffee:before{content:"\f0f4"}.icon-food:before{content:"\f0f5"}.icon-file-text-alt:before{content:"\f0f6"}.icon-building:before{content:"\f0f7"}.icon-hospital:before{content:"\f0f8"}.icon-ambulance:before{content:"\f0f9"}.icon-medkit:before{content:"\f0fa"}.icon-fighter-jet:before{content:"\f0fb"}.icon-beer:before{content:"\f0fc"}.icon-h-sign:before{content:"\f0fd"}.icon-plus-sign-alt:before{content:"\f0fe"}.icon-double-angle-left:before{content:"\f100"}.icon-double-angle-right:before{content:"\f101"}.icon-double-angle-up:before{content:"\f102"}.icon-double-angle-down:before{content:"\f103"}.icon-angle-left:before{content:"\f104"}.icon-angle-right:before{content:"\f105"}.icon-angle-up:before{content:"\f106"}.icon-angle-down:before{content:"\f107"}.icon-desktop:before{content:"\f108"}.icon-laptop:before{content:"\f109"}.icon-tablet:before{content:"\f10a"}.icon-mobile-phone:before{content:"\f10b"}.icon-circle-blank:before{content:"\f10c"}.icon-quote-left:before{content:"\f10d"}.icon-quote-right:before{content:"\f10e"}.icon-spinner:before{content:"\f110"}.icon-circle:before{content:"\f111"}.icon-mail-reply:before,.icon-reply:before{content:"\f112"}.icon-github-alt:before{content:"\f113"}.icon-folder-close-alt:before{content:"\f114"}.icon-folder-open-alt:before{content:"\f115"}.icon-expand-alt:before{content:"\f116"}.icon-collapse-alt:before{content:"\f117"}.icon-smile:before{content:"\f118"}.icon-frown:before{content:"\f119"}.icon-meh:before{content:"\f11a"}.icon-gamepad:before{content:"\f11b"}.icon-keyboard:before{content:"\f11c"}.icon-flag-alt:before{content:"\f11d"}.icon-flag-checkered:before{content:"\f11e"}.icon-terminal:before{content:"\f120"}.icon-code:before{content:"\f121"}.icon-reply-all:before{content:"\f122"}.icon-mail-reply-all:before{content:"\f122"}.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}.icon-location-arrow:before{content:"\f124"}.icon-crop:before{content:"\f125"}.icon-code-fork:before{content:"\f126"}.icon-unlink:before{content:"\f127"}.icon-question:before{content:"\f128"}.icon-info:before{content:"\f129"}.icon-exclamation:before{content:"\f12a"}.icon-superscript:before{content:"\f12b"}.icon-subscript:before{content:"\f12c"}.icon-eraser:before{content:"\f12d"}.icon-puzzle-piece:before{content:"\f12e"}.icon-microphone:before{content:"\f130"}.icon-microphone-off:before{content:"\f131"}.icon-shield:before{content:"\f132"}.icon-calendar-empty:before{content:"\f133"}.icon-fire-extinguisher:before{content:"\f134"}.icon-rocket:before{content:"\f135"}.icon-maxcdn:before{content:"\f136"}.icon-chevron-sign-left:before{content:"\f137"}.icon-chevron-sign-right:before{content:"\f138"}.icon-chevron-sign-up:before{content:"\f139"}.icon-chevron-sign-down:before{content:"\f13a"}.icon-html5:before{content:"\f13b"}.icon-css3:before{content:"\f13c"}.icon-anchor:before{content:"\f13d"}.icon-unlock-alt:before{content:"\f13e"}.icon-bullseye:before{content:"\f140"}.icon-ellipsis-horizontal:before{content:"\f141"}.icon-ellipsis-vertical:before{content:"\f142"}.icon-rss-sign:before{content:"\f143"}.icon-play-sign:before{content:"\f144"}.icon-ticket:before{content:"\f145"}.icon-minus-sign-alt:before{content:"\f146"}.icon-check-minus:before{content:"\f147"}.icon-level-up:before{content:"\f148"}.icon-level-down:before{content:"\f149"}.icon-check-sign:before{content:"\f14a"}.icon-edit-sign:before{content:"\f14b"}.icon-external-link-sign:before{content:"\f14c"}.icon-share-sign:before{content:"\f14d"}.icon-compass:before{content:"\f14e"}.icon-collapse:before{content:"\f150"}.icon-collapse-top:before{content:"\f151"}.icon-expand:before{content:"\f152"}.icon-euro:before,.icon-eur:before{content:"\f153"}.icon-gbp:before{content:"\f154"}.icon-dollar:before,.icon-usd:before{content:"\f155"}.icon-rupee:before,.icon-inr:before{content:"\f156"}.icon-yen:before,.icon-jpy:before{content:"\f157"}.icon-renminbi:before,.icon-cny:before{content:"\f158"}.icon-won:before,.icon-krw:before{content:"\f159"}.icon-bitcoin:before,.icon-btc:before{content:"\f15a"}.icon-file:before{content:"\f15b"}.icon-file-text:before{content:"\f15c"}.icon-sort-by-alphabet:before{content:"\f15d"}.icon-sort-by-alphabet-alt:before{content:"\f15e"}.icon-sort-by-attributes:before{content:"\f160"}.icon-sort-by-attributes-alt:before{content:"\f161"}.icon-sort-by-order:before{content:"\f162"}.icon-sort-by-order-alt:before{content:"\f163"}.icon-thumbs-up:before{content:"\f164"}.icon-thumbs-down:before{content:"\f165"}.icon-youtube-sign:before{content:"\f166"}.icon-youtube:before{content:"\f167"}.icon-xing:before{content:"\f168"}.icon-xing-sign:before{content:"\f169"}.icon-youtube-play:before{content:"\f16a"}.icon-dropbox:before{content:"\f16b"}.icon-stackexchange:before{content:"\f16c"}.icon-instagram:before{content:"\f16d"}.icon-flickr:before{content:"\f16e"}.icon-adn:before{content:"\f170"}.icon-bitbucket:before{content:"\f171"}.icon-bitbucket-sign:before{content:"\f172"}.icon-tumblr:before{content:"\f173"}.icon-tumblr-sign:before{content:"\f174"}.icon-long-arrow-down:before{content:"\f175"}.icon-long-arrow-up:before{content:"\f176"}.icon-long-arrow-left:before{content:"\f177"}.icon-long-arrow-right:before{content:"\f178"}.icon-apple:before{content:"\f179"}.icon-windows:before{content:"\f17a"}.icon-android:before{content:"\f17b"}.icon-linux:before{content:"\f17c"}.icon-dribbble:before{content:"\f17d"}.icon-skype:before{content:"\f17e"}.icon-foursquare:before{content:"\f180"}.icon-trello:before{content:"\f181"}.icon-female:before{content:"\f182"}.icon-male:before{content:"\f183"}.icon-gittip:before{content:"\f184"}.icon-sun:before{content:"\f185"}.icon-moon:before{content:"\f186"}.icon-archive:before{content:"\f187"}.icon-bug:before{content:"\f188"}.icon-vk:before{content:"\f189"}.icon-weibo:before{content:"\f18a"}.icon-renren:before{content:"\f18b"}.icon-address:before{content:"\f02d"}.icon-arrow-down-2:before{content:"\f0ab"}.icon-arrow-down-3:before{content:"\f0d7"}.icon-arrow-first:before{content:"\f048"}.icon-arrow-last:before{content:"\f051"}.icon-arrow-left-2:before{content:"\f0a8"}.icon-arrow-left-3:before{content:"\f0d9"}.icon-arrow-right-2:before{content:"\f0a9"}.icon-arrow-right-3:before{content:"\f0da"}.icon-arrow-up-2:before{content:"\f0aa"}.icon-arrow-up-3:before{content:"\f0d8"}.icon-bars:before{content:"\f080"}.icon-basket:before{content:"\f07a"}.icon-box-add:before{content:"\f019"}.icon-box-remove:before{content:"\f093"}.icon-broadcast:before{content:"\f012"}.icon-brush:before{content:"\f043"}.icon-calendar-2:before{content:"\f073"}.icon-camera-2:before{content:"\f03d"}.icon-cancel:before{content:"\f057"}.icon-cancel-2:before{content:"\f00d"}.icon-cart:before{content:"\f07a"}.icon-chart:before{content:"\f080"}.icon-checkbox:before{content:"\f046"}.icon-checkbox-partial:before{content:"\f147"}.icon-checkbox-unchecked:before{content:"\f096"}.icon-checkmark:before{content:"\f00c"}.icon-clock:before{content:"\f017"}.icon-color-palette:before{content:"\f0e4"}.icon-comments-2:before{content:"\f086"}.icon-contract:before{content:"\f066"}.icon-contract-2:before{content:"\f066"}.icon-cube:before{content:"\f01c"}.icon-database:before{content:"\f0a0"}.icon-drawer:before{content:"\f01c"}.icon-drawer-2:before{content:"\f01c"}.icon-expand:before{content:"\f065"}.icon-expand-2:before{content:"\f0b2"}.icon-eye:before{content:"\f06e"}.icon-feed:before{content:"\f143"}.icon-file-add:before{content:"\f116"}.icon-file-remove:before{content:"\f117"}.icon-first:before{content:"\f049"}.icon-flag-2:before{content:"\f0c6"}.icon-folder:before{content:"\f07c"}.icon-folder-2:before{content:"\f07b"}.icon-grid-view:before{content:"\f0db"}.icon-grid-view-2:before{content:"\f00a"}.icon-health:before{content:"\f0f1"}.icon-help:before{content:"\f059"}.icon-lamp:before{content:"\f0eb"}.icon-last:before{content:"\f050"}.icon-lightning:before{content:"\f0e7"}.icon-list-view:before{content:"\f0ca"}.icon-location:before{content:"\f041"}.icon-locked:before{content:"\f023"}.icon-loop:before{content:"\f021"}.icon-mail:before{content:"\f0e0"}.icon-mail-2:before{content:"\f003"}.icon-menu:before{content:"\f142"}.icon-menu-2:before{content:"\f0dc"}.icon-minus-2:before{content:"\f068"}.icon-mobile:before{content:"\f10b"}.icon-next:before{content:"\f04e"}.icon-out:before{content:"\f045"}.icon-out-2:before{content:"\f08b"}.icon-pencil-2:before{content:"\f040"}.icon-pictures:before{content:"\f03e"}.icon-pin:before{content:"\f08d"}.icon-play-2:before{content:"\f01d"}.icon-plus-2:before{content:"\f067"}.icon-power-cord:before{content:"\f076"}.icon-previous:before{content:"\f04a"}.icon-printer:before{content:"\f02f"}.icon-puzzle:before{content:"\f12e"}.icon-quote:before{content:"\f10d"}.icon-quote-2:before{content:"\f10e"}.icon-redo:before{content:"\f064"}.icon-screen:before{content:"\f108"}.icon-shuffle:before{content:"\f074"}.icon-star-2:before{content:"\f123"}.icon-support:before{content:"\f05b"}.icon-tools:before{content:"\f0ad"}.icon-users:before{content:"\f0c0"}.icon-vcard:before{content:"\f18b"}.icon-wand:before{content:"\f0d0"}.icon-warning:before{content:"\f071"}
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/font/FontAwesome.otf b/plugins/system/t3/base-bs3/fonts/font-awesome/font/FontAwesome.otf
new file mode 100644
index 0000000..7012545
Binary files /dev/null and b/plugins/system/t3/base-bs3/fonts/font-awesome/font/FontAwesome.otf differ
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.eot b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.eot
new file mode 100644
index 0000000..0662cb9
Binary files /dev/null and b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.eot differ
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.svg b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.svg
new file mode 100644
index 0000000..2edb4ec
--- /dev/null
+++ b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.svg
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.ttf b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.ttf
new file mode 100644
index 0000000..d365924
Binary files /dev/null and b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.ttf differ
diff --git a/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.woff b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.woff
new file mode 100644
index 0000000..b9bd17e
Binary files /dev/null and b/plugins/system/t3/base-bs3/fonts/font-awesome/font/fontawesome-webfont.woff differ
diff --git a/plugins/system/t3/base-bs3/html/com_contact/categories/default.php b/plugins/system/t3/base-bs3/html/com_contact/categories/default.php
new file mode 100644
index 0000000..84ff476
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/categories/default.php
@@ -0,0 +1,40 @@
+
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+ params->get('show_base_description')) : ?>
+
+ params->get('categories_description')) : ?>
+
+ params->get('categories_description'), '', 'com_contact.categories'); ?>
+
+
+
+ parent->description) : ?>
+
+ parent->description, '', 'com_contact.categories'); ?>
+
+
+
+
+
+ loadTemplate('items'); ?>
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/categories/default_items.php b/plugins/system/t3/base-bs3/html/com_contact/categories/default_items.php
new file mode 100644
index 0000000..0e4e5d1
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/categories/default_items.php
@@ -0,0 +1,63 @@
+items[$this->parent->id]) > 0 && $this->maxLevelcat != 0) : ?>
+items[$this->parent->id] as $id => $item) : ?>
+ params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) :
+ if(!isset($this->items[$this->parent->id][$id + 1]))
+ {
+ $class = ' class="category-item last"';
+ }
+ ?>
+ >
+
+
+ params->get('show_subcat_desc_cat') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_contact.categories'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ items[$item->id] = $item->getChildren();
+ $this->parent = $item;
+ $this->maxLevelcat--;
+ echo $this->loadTemplate('items');
+ $this->parent = $item->getParent();
+ $this->maxLevelcat++;
+ ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/categories/index.html b/plugins/system/t3/base-bs3/html/com_contact/categories/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/categories/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/category/default.php b/plugins/system/t3/base-bs3/html/com_contact/category/default.php
new file mode 100644
index 0000000..25c8174
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/category/default.php
@@ -0,0 +1,44 @@
+
+
+params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+params->get('show_category_title', 1)) : ?>
+
+ category->title, '', 'com_contact.category'); ?>
+
+
+params->def('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
+
+ params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
+
+
+ params->get('show_description') && $this->category->description) : ?>
+ category->description, '', 'com_contact.category'); ?>
+
+
+
+
+
+loadTemplate('items'); ?>
+
+children[$this->category->id])&& $this->maxLevel != 0) : ?>
+
+
+ loadTemplate('children'); ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/category/default_children.php b/plugins/system/t3/base-bs3/html/com_contact/category/default_children.php
new file mode 100644
index 0000000..0d2456e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/category/default_children.php
@@ -0,0 +1,55 @@
+children[$this->category->id]) > 0 && $this->maxLevel != 0) :
+?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/category/default_items.php b/plugins/system/t3/base-bs3/html/com_contact/category/default_items.php
new file mode 100644
index 0000000..d28f1df
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/category/default_items.php
@@ -0,0 +1,127 @@
+escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+?>
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/category/index.html b/plugins/system/t3/base-bs3/html/com_contact/category/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/category/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default.php
new file mode 100644
index 0000000..3c3edcb
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default.php
@@ -0,0 +1,261 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+ contact->name && $this->params->get('show_name')) : ?>
+
+
+ params->get('show_contact_category') == 'show_no_link') : ?>
+
+ contact->category_title; ?>
+
+
+ params->get('show_contact_category') == 'show_with_link') : ?>
+ contact->catid); ?>
+
+
+ params->get('show_contact_list') && count($this->contacts) > 1) : ?>
+
+
+
+ params->get('show_tags', 1) && !empty($this->item->tags)) : ?>
+ item->tagLayout = new JLayoutFile('joomla.content.tags'); ?>
+ item->tagLayout->render($this->item->tags->itemTags); ?>
+
+
+ params->get('presentation_style') == 'sliders') : ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default_address.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default_address.php
new file mode 100644
index 0000000..1abfe4d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default_address.php
@@ -0,0 +1,126 @@
+
+
+ params->get('address_check') > 0) &&
+ ($this->contact->address || $this->contact->suburb || $this->contact->state || $this->contact->country || $this->contact->postcode)) : ?>
+ params->get('address_check') > 0) : ?>
+
+
+ params->get('marker_address'); ?>
+
+
+
+
+ contact->address && $this->params->get('show_street_address')) : ?>
+
+
+ contact->address .' '; ?>
+
+
+
+
+ contact->suburb && $this->params->get('show_suburb')) : ?>
+
+
+ contact->suburb .' '; ?>
+
+
+
+ contact->state && $this->params->get('show_state')) : ?>
+
+
+ contact->state . ' '; ?>
+
+
+
+ contact->postcode && $this->params->get('show_postcode')) : ?>
+
+
+ contact->postcode .' '; ?>
+
+
+
+ contact->country && $this->params->get('show_country')) : ?>
+
+
+ contact->country .' '; ?>
+
+
+
+
+
+contact->email_to && $this->params->get('show_email')) : ?>
+
+
+ params->get('marker_email')); ?>
+
+
+
+
+ contact->email_to; ?>
+
+
+
+
+contact->telephone && $this->params->get('show_telephone')) : ?>
+
+
+ params->get('marker_telephone'); ?>
+
+
+
+
+ contact->telephone); ?>
+
+
+
+contact->fax && $this->params->get('show_fax')) : ?>
+
+
+ params->get('marker_fax'); ?>
+
+
+
+
+ contact->fax); ?>
+
+
+
+contact->mobile && $this->params->get('show_mobile')) :?>
+
+
+ params->get('marker_mobile'); ?>
+
+
+
+
+ contact->mobile); ?>
+
+
+
+contact->webpage && $this->params->get('show_webpage')) : ?>
+
+
+
+
+
+
+
+ contact->webpage; ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default_articles.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default_articles.php
new file mode 100644
index 0000000..55c6000
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default_articles.php
@@ -0,0 +1,25 @@
+
+params->get('show_articles')) : ?>
+
+
+ item->articles as $article) : ?>
+
+ slug, $article->catslug)), htmlspecialchars($article->title, ENT_COMPAT, 'UTF-8')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default_form.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default_form.php
new file mode 100644
index 0000000..799c7e2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default_form.php
@@ -0,0 +1,98 @@
+error)) : ?>
+
+ error; ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default_links.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default_links.php
new file mode 100644
index 0000000..1420711
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default_links.php
@@ -0,0 +1,64 @@
+params->get('presentation_style')=='sliders'):?>
+
+
+
+
+
+params->get('presentation_style') == 'tabs') : ?>
+
+
+params->get('presentation_style')=='plain'):?>
+'. JText::_('COM_CONTACT_LINKS').''; ?>
+
+
+
+
+params->get('presentation_style')=='sliders'):?>
+
+
+
+
+params->get('presentation_style') == 'tabs') : ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/default_profile.php b/plugins/system/t3/base-bs3/html/com_contact/contact/default_profile.php
new file mode 100644
index 0000000..f07c9b2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/default_profile.php
@@ -0,0 +1,40 @@
+
+item->profile->getFieldset('profile'); ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/contact/index.html b/plugins/system/t3/base-bs3/html/com_contact/contact/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/contact/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/featured/default.php b/plugins/system/t3/base-bs3/html/com_contact/featured/default.php
new file mode 100644
index 0000000..84cdf9b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/featured/default.php
@@ -0,0 +1,39 @@
+
+
+params->get('show_page_heading') != 0 ) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+loadTemplate('items'); ?>
+pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+if ($this->params->def('show_pagination', 2) == 1 || ($this->params->get('show_pagination') == 2 && $pagesTotal > 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/featured/default_items.php b/plugins/system/t3/base-bs3/html/com_contact/featured/default_items.php
new file mode 100644
index 0000000..f27f65e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/featured/default_items.php
@@ -0,0 +1,166 @@
+escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+
+// Create a shortcut for params.
+$params = &$this->item->params;
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/featured/index.html b/plugins/system/t3/base-bs3/html/com_contact/featured/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/featured/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_contact/index.html b/plugins/system/t3/base-bs3/html/com_contact/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_contact/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/archive/default.php b/plugins/system/t3/base-bs3/html/com_content/archive/default.php
new file mode 100644
index 0000000..1ff8754
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/archive/default.php
@@ -0,0 +1,51 @@
+
+
+ params->get('show_page_heading', 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/archive/default_items.php b/plugins/system/t3/base-bs3/html/com_content/archive/default_items.php
new file mode 100644
index 0000000..99d71a3
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/archive/default_items.php
@@ -0,0 +1,72 @@
+params;
+
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+?>
+
+
+ items as $i => $item) : ?>
+
+
+ $item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+ $item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $item, 'params' => $params)); ?>
+
+
+
+
+
+ get('show_intro')) :?>
+ introtext, $params->get('introtext_limit')); ?>
+
+
+
+
+
+ $item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+
+
+
+
+pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+if ($this->params->def('show_pagination', 2) == 1 || ($this->params->get('show_pagination') == 2 && $pagesTotal > 1)) : ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/archive/index.html b/plugins/system/t3/base-bs3/html/com_content/archive/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/archive/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/article/default.php b/plugins/system/t3/base-bs3/html/com_content/article/default.php
new file mode 100644
index 0000000..b6577b0
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/article/default.php
@@ -0,0 +1,159 @@
+item->params;
+$images = json_decode($this->item->images);
+$urls = json_decode($this->item->urls);
+$canEdit = $params->get('access-edit');
+$user = JFactory::getUser();
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = !empty($this->print) || $canEdit || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+JHtml::_('behavior.caption');
+JHtml::_('bootstrap.tooltip');
+?>
+
+params->get('show_page_heading', 1)) : ?>
+
+
+
+
+
+item->pagination) && $this->item->pagination && !$this->item->paginationposition && $this->item->paginationrelative) : ?>
+ item->pagination; ?>
+
+
+
+
+
+
+get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h1')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params, 'print' => $this->print)); ?>
+
+
+
+
+
+
+item->toc)) : ?>
+ item->toc; ?>
+
+
+get('show_tags', 1) && !empty($this->item->tags)) : ?>
+ item->tags->itemTags); ?>
+
+
+get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+item->event->beforeDisplayContent; ?>
+
+urls_position) && ($urls->urls_position == '0')) || ($params->get('urls_position') == '0' && empty($urls->urls_position))) || (empty($urls->urls_position) && (!$params->get('urls_position')))): ?>
+ loadTemplate('links'); ?>
+
+
+get('access-view')): ?>
+
+ $this->item, 'params' => $params)); ?>
+
+ item->pagination) AND $this->item->pagination AND !$this->item->paginationposition AND !$this->item->paginationrelative):
+ echo $this->item->pagination;
+ endif; ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+ item->pagination) && $this->item->pagination && $this->item->paginationposition && !$this->item->paginationrelative): ?>
+ ';
+ echo $this->item->pagination;
+ ?>
+
+
+ urls_position) && ($urls->urls_position == '1')) || ($params->get('urls_position') == '1'))): ?>
+ loadTemplate('links'); ?>
+
+
+
+get('show_noauth') == true and $user->get('guest')) : ?>
+
+ item->introtext; ?>
+
+ get('show_readmore') && $this->item->fulltext != null) :
+ $link1 = JRoute::_('index.php?option=com_users&view=login');
+ $link = new JURI($link1);
+ ?>
+
+
+
+
+
+
+
+item->pagination) && $this->item->pagination && $this->item->paginationposition && $this->item->paginationrelative): ?>
+ item->pagination; ?>
+
+
+item->event->afterDisplayContent; ?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/article/default_links.php b/plugins/system/t3/base-bs3/html/com_content/article/default_links.php
new file mode 100644
index 0000000..76131c9
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/article/default_links.php
@@ -0,0 +1,79 @@
+item->urls);
+
+// Create shortcuts to some parameters.
+$params = $this->item->params;
+if ($urls && (!empty($urls->urla) || !empty($urls->urlb) || !empty($urls->urlc))) :
+?>
+
+
+ urla, $urls->urlatext, $urls->targeta, 'a'),
+ array($urls->urlb, $urls->urlbtext, $urls->targetb, 'b'),
+ array($urls->urlc, $urls->urlctext, $urls->targetc, 'c')
+ );
+ foreach ($urlarray as $url) :
+ $link = $url[0];
+ $label = $url[1];
+ $target = $url[2];
+ $id = $url[3];
+
+ if ( ! $link) :
+ continue;
+ endif;
+
+ // If no label is present, take the link
+ $label = ($label) ? $label : $link;
+
+ // If no target is present, use the default
+ $target = $target ? $target : $params->get('target'.$id);
+ ?>
+
+ '.
+ htmlspecialchars($label) .'';
+ break;
+
+ case 2:
+ // open in a popup window
+ $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=600';
+ echo "".
+ htmlspecialchars($label).' ';
+ break;
+ case 3:
+ // open in a modal window
+ JHtml::_('behavior.modal', 'a.modal');
+ echo ''.
+ htmlspecialchars($label) . ' ';
+ break;
+
+ default:
+ // open in parent window
+ echo ''.
+ htmlspecialchars($label) . ' ';
+ break;
+ }
+ ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/article/index.html b/plugins/system/t3/base-bs3/html/com_content/article/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/article/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/categories/default.php b/plugins/system/t3/base-bs3/html/com_content/categories/default.php
new file mode 100644
index 0000000..12be1ea
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/categories/default.php
@@ -0,0 +1,20 @@
+
+
+loadTemplate('items');
+?>
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/categories/default_items.php b/plugins/system/t3/base-bs3/html/com_content/categories/default_items.php
new file mode 100644
index 0000000..328c20b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/categories/default_items.php
@@ -0,0 +1,68 @@
+items[$this->parent->id]) > 0 && $this->maxLevelcat != 0) :
+?>
+ items[$this->parent->id] as $id => $item) : ?>
+ params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) :
+ if (!isset($this->items[$this->parent->id][$id + 1]))
+ {
+ $class = ' last';
+ }
+ ?>
+
+
+
+ params->get('show_description_image') && $item->getParams()->get('image')) : ?>
+
+
+ params->get('show_subcat_desc_cat') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.categories'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ items[$item->id] = $item->getChildren();
+ $this->parent = $item;
+ $this->maxLevelcat--;
+ echo $this->loadTemplate('items');
+ $this->parent = $item->getParent();
+ $this->maxLevelcat++;
+ ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/categories/index.html b/plugins/system/t3/base-bs3/html/com_content/categories/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/categories/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/blog.php b/plugins/system/t3/base-bs3/html/com_content/category/blog.php
new file mode 100644
index 0000000..005ec47
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/blog.php
@@ -0,0 +1,121 @@
+
+
+ params->get('show_page_heading', 1)) : ?>
+
+
+ params->get('show_category_title', 1) or $this->params->get('page_subheading')) : ?>
+
+
+
+ params->get('show_tags', 1) && !empty($this->category->tags->itemTags)) : ?>
+ category->tags->itemTags); ?>
+
+
+ params->get('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
+
+ params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
+
+
+ params->get('show_description') && $this->category->description) : ?>
+ category->description, '', 'com_content.category'); ?>
+
+
+
+
+ lead_items) && empty($this->link_items) && empty($this->intro_items)) : ?>
+ params->get('show_no_articles', 1)) : ?>
+
+
+
+
+
+ lead_items)) : ?>
+
+ lead_items as &$item) : ?>
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+
+
+
+ intro_items));
+ $counter = 0;
+ ?>
+
+ intro_items)) : ?>
+ intro_items as $key => &$item) : ?>
+ columns) + 1; ?>
+
+ columns; ?>
+
+
+
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+ columns) or ($counter == $introcount)) : ?>
+
+
+
+
+
+ link_items)) : ?>
+
+ loadTemplate('links'); ?>
+
+
+
+ children[$this->category->id])&& $this->maxLevel != 0) : ?>
+
+ params->get('show_category_heading_title_text', 1) == 1) : ?>
+
+
+ loadTemplate('children'); ?>
+
+
+ pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+ if (($this->params->def('show_pagination', 1) == 1 || ($this->params->get('show_pagination') == 2)) && ($pagesTotal > 1)) : ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/blog_children.php b/plugins/system/t3/base-bs3/html/com_content/category/blog_children.php
new file mode 100644
index 0000000..b81a07e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/blog_children.php
@@ -0,0 +1,82 @@
+children[$this->category->id]) > 0 && $this->maxLevel != 0) : ?>
+
+ children[$this->category->id] as $id => $child) : ?>
+ params->get('show_empty_categories') || $child->numitems || count($child->getChildren())) :
+ if (!isset($this->children[$this->category->id][$id + 1])) :
+ $class = ' class="last"';
+ endif;
+ ?>
+ >
+
+ isRTL()) : ?>
+
+
+
+
+ params->get('show_subcat_desc') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.category'); ?>
+
+
+
+
+ getChildren()) > 0) : ?>
+
+ children[$child->id] = $child->getChildren();
+ $this->category = $child;
+ $this->maxLevel--;
+ if ($this->maxLevel != 0) :
+ echo $this->loadTemplate('children');
+ endif;
+ $this->category = $child->getParent();
+ $this->maxLevel++;
+ ?>
+
+
+
+
+
+
+item->params;
+$images = json_decode($this->item->images);
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+// update catslug if not exists - compatible with 2.5
+if (empty ($this->item->catslug)) {
+ $this->item->catslug = $this->item->category_alias ? ($this->item->catid.':'.$this->item->category_alias) : $this->item->catid;
+}
+?>
+
+item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+|| ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+
+
+
+ get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params)); ?>
+
+
+
+
+
+
+ get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+ item->event->beforeDisplayContent; ?>
+
+ item); ?>
+
+ item->introtext; ?>
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+
+ get('show_readmore') && $this->item->readmore) :
+ if ($params->get('access-view')) :
+ $link = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ else :
+ $menu = JFactory::getApplication()->getMenu();
+ $active = $menu->getActive();
+ $itemId = $active->id;
+ $link1 = JRoute::_('index.php?option=com_users&view=login&Itemid=' . $itemId);
+ $returnURL = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ $link = new JURI($link1);
+ $link->setVar('return', base64_encode($returnURL));
+ endif;
+ ?>
+
+
+
+
+
+
+item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+|| ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+item->event->afterDisplayContent; ?>
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/blog_links.php b/plugins/system/t3/base-bs3/html/com_content/category/blog_links.php
new file mode 100644
index 0000000..7a83a06
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/blog_links.php
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ link_items as &$item) :
+ ?>
+
+
+ title; ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/default.php b/plugins/system/t3/base-bs3/html/com_content/category/default.php
new file mode 100644
index 0000000..39ebf1a
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/default.php
@@ -0,0 +1,23 @@
+
+
+
+subtemplatename = 'articles';
+echo JLayoutHelper::render('joomla.content.category_default', $this);
+?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/default_articles.php b/plugins/system/t3/base-bs3/html/com_content/category/default_articles.php
new file mode 100644
index 0000000..37e5bac
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/default_articles.php
@@ -0,0 +1,214 @@
+item->params;
+$n = count($this->items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+
+// Check for at least one editable article
+$isEditable = false;
+
+if (!empty($this->items))
+{
+ foreach ($this->items as $article)
+ {
+ if ($article->params->get('access-edit'))
+ {
+ $isEditable = true;
+ break;
+ }
+ }
+}
+?>
+
+items)) : ?>
+
+ params->get('show_no_articles', 1)) : ?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/default_children.php b/plugins/system/t3/base-bs3/html/com_content/category/default_children.php
new file mode 100644
index 0000000..6c9a6dd
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/default_children.php
@@ -0,0 +1,83 @@
+
+
+children[$this->category->id]) > 0) : ?>
+ children[$this->category->id] as $id => $child) : ?>
+ params->get('show_empty_categories') || $child->getNumItems(true) || count($child->getChildren())) :
+ if (!isset($this->children[$this->category->id][$id + 1])) :
+ $class = ' class="last"';
+ endif;
+ ?>
+
+ >
+
+ isRTL()) : ?>
+
+
+
+ params->get('show_subcat_desc') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.category'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ children[$child->id] = $child->getChildren();
+ $this->category = $child;
+ $this->maxLevel--;
+ if ($this->maxLevel != 0) :
+ echo $this->loadTemplate('children');
+ endif;
+ $this->category = $child->getParent();
+ $this->maxLevel++;
+ ?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/category/index.html b/plugins/system/t3/base-bs3/html/com_content/category/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/category/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/featured/default.php b/plugins/system/t3/base-bs3/html/com_content/featured/default.php
new file mode 100644
index 0000000..12d7903
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/featured/default.php
@@ -0,0 +1,100 @@
+
+
+params->get('show_page_heading') != 0) : ?>
+
+
+
+
+lead_items)) : ?>
+
+ lead_items as &$item) : ?>
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+
+
+intro_items));
+ $counter = 0;
+?>
+intro_items)) : ?>
+ intro_items as $key => &$item) : ?>
+
+ columns) + 1;
+ $row = $counter / $this->columns;
+
+ if ($rowcount == 1) : ?>
+
+
+
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+ columns) or ($counter == $introcount)) : ?>
+
+
+
+
+
+
+
+link_items)) : ?>
+
+
+ loadTemplate('links'); ?>
+
+
+
+params->def('show_pagination', 2) == 1 || ($this->params->get('show_pagination') == 2 && $this->pagination->get('pages.total') > 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/featured/default_item.php b/plugins/system/t3/base-bs3/html/com_content/featured/default_item.php
new file mode 100644
index 0000000..f1d4157
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/featured/default_item.php
@@ -0,0 +1,115 @@
+item->params;
+$images = json_decode($this->item->images);
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+?>
+
+ item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+
+
+
+ get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params)); ?>
+
+
+
+
+
+
+
+ get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+ item->event->beforeDisplayContent; ?>
+
+ item); ?>
+
+ item->introtext; ?>
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+ get('show_tags', 1) && !empty($this->item->tags)) : ?>
+ item->tags->itemTags); ?>
+
+
+ get('show_readmore') && $this->item->readmore) :
+ if ($params->get('access-view')) :
+ $link = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ else :
+ $menu = JFactory::getApplication()->getMenu();
+ $active = $menu->getActive();
+ $itemId = $active->id;
+ $link1 = JRoute::_('index.php?option=com_users&view=login&Itemid=' . $itemId);
+ $returnURL = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ $link = new JURI($link1);
+ $link->setVar('return', base64_encode($returnURL));
+ endif;
+ ?>
+
+
+
+
+
+ item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+item->event->afterDisplayContent; ?>
diff --git a/plugins/system/t3/base-bs3/html/com_content/featured/default_links.php b/plugins/system/t3/base-bs3/html/com_content/featured/default_links.php
new file mode 100644
index 0000000..4af0b18
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/featured/default_links.php
@@ -0,0 +1,19 @@
+
+
+link_items as &$item) : ?>
+
+
+ title; ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/featured/index.html b/plugins/system/t3/base-bs3/html/com_content/featured/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/featured/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_content/form/edit.php b/plugins/system/t3/base-bs3/html/com_content/form/edit.php
new file mode 100644
index 0000000..6eae236
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/form/edit.php
@@ -0,0 +1,316 @@
+state->get('params');
+//$images = json_decode($this->item->images);
+//$urls = json_decode($this->item->urls);
+
+// This checks if the editor config options have ever been saved. If they haven't they will fall back to the original settings.
+$editoroptions = isset($params->show_publishing_options);
+if (!$editoroptions)
+{
+ $params->show_urls_images_frontend = '0';
+}
+
+//T3: customize
+$fieldsets = $this->form->getFieldsets('attribs');
+$extrafields = array();
+
+foreach ($fieldsets as $fieldset) {
+ if(isset($fieldset->group) && $fieldset->group == 'extrafields'){
+ $extrafields[] = $fieldset;
+ }
+}
+
+if(count($extrafields)){
+ if(is_string($this->item->attribs)){
+ $this->item->attribs = json_decode($this->item->attribs);
+ }
+ $tmp = new stdClass;
+ $tmp->attribs = $this->item->attribs;
+ $this->form->bind($tmp);
+}
+//T3: customize
+?>
+
+
+
+ get('show_page_heading', 1)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_content/icon.php b/plugins/system/t3/base-bs3/html/com_content/icon.php
new file mode 100644
index 0000000..f744482
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/icon.php
@@ -0,0 +1,284 @@
+id;
+
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/new.png', JText::_('JNEW'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JNEW') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JNEW') . ' ';
+ }
+
+ // Add the button classes to the attribs array
+ if (isset($attribs['class']))
+ {
+ $attribs['class'] = $attribs['class'] . ' btn btn-primary';
+ }
+ else
+ {
+ $attribs['class'] = 'btn btn-primary';
+ }
+
+ $button = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ $output = '' . $button . ' ';
+
+ return $output;
+ }
+
+ /**
+ * Method to generate a link to the email item page for the given article
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the email item link
+ */
+ public static function email($article, $params, $attribs = array(), $legacy = false)
+ {
+ require_once JPATH_SITE . '/components/com_mailto/helpers/mailto.php';
+
+ $uri = JUri::getInstance();
+ $base = $uri->toString(array('scheme', 'host', 'port'));
+ $template = JFactory::getApplication()->getTemplate();
+ $link = $base . JRoute::_(ContentHelperRoute::getArticleRoute($article->slug, $article->catid), false);
+ $url = 'index.php?option=com_mailto&tmpl=component&template=' . $template . '&link=' . MailToHelper::addLink($link);
+
+ $status = 'width=400,height=350,menubar=yes,resizable=yes';
+
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/emailButton.png', JText::_('JGLOBAL_EMAIL'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_EMAIL');
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_EMAIL');
+ }
+
+ $attribs['title'] = JText::_('JGLOBAL_EMAIL');
+ $attribs['onclick'] = "window.open(this.href,'win2','" . $status . "'); return false;";
+
+ $output = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ return $output;
+ }
+
+ /**
+ * Display an edit icon for the article.
+ *
+ * This icon will not display in a popup window, nor if the article is trashed.
+ * Edit access checks must be performed in the calling code.
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML for the article edit icon.
+ * @since 1.6
+ */
+ public static function edit($article, $params, $attribs = array(), $legacy = false)
+ {
+ $user = JFactory::getUser();
+ $uri = JUri::getInstance();
+
+ // Ignore if in a popup window.
+ if ($params && $params->get('popup'))
+ {
+ return;
+ }
+
+ // Ignore if the state is negative (trashed).
+ if ($article->state < 0)
+ {
+ return;
+ }
+
+ JHtml::_('bootstrap.tooltip');
+
+ // Show checked_out icon if the article is checked out by a different user
+ if (property_exists($article, 'checked_out') && property_exists($article, 'checked_out_time') && $article->checked_out > 0 && $article->checked_out != $user->get('id'))
+ {
+ $checkoutUser = JFactory::getUser($article->checked_out);
+ $button = JHtml::_('image', 'system/checked_out.png', null, null, true);
+ $date = JHtml::_('date', $article->checked_out_time);
+ $tooltip = JText::_('JLIB_HTML_CHECKED_OUT') . ' :: ' . JText::sprintf('COM_CONTENT_CHECKED_OUT_BY', $checkoutUser->name) . ' ' . $date;
+
+ return '' . $button . ' ';
+ }
+
+ $url = 'index.php?option=com_content&task=article.edit&a_id=' . $article->id . '&return=' . base64_encode($uri);
+
+ if ($article->state == 0)
+ {
+ $overlib = JText::_('JUNPUBLISHED');
+ }
+ else
+ {
+ $overlib = JText::_('JPUBLISHED');
+ }
+
+ $date = JHtml::_('date', $article->created);
+ $author = $article->created_by_alias ? $article->created_by_alias : $article->author;
+
+ $overlib .= '<br />';
+ $overlib .= $date;
+ $overlib .= '<br />';
+ $overlib .= JText::sprintf('COM_CONTENT_WRITTEN_BY', htmlspecialchars($author, ENT_COMPAT, 'UTF-8'));
+
+ if ($legacy)
+ {
+ $icon = $article->state ? 'edit.png' : 'edit_unpublished.png';
+ if (strtotime($article->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($article->publish_down) < strtotime(JFactory::getDate())) && $article->publish_down != '0000-00-00 00:00:00'))
+ {
+ $icon = 'edit_unpublished.png';
+ }
+ $text = JHtml::_('image', 'system/' . $icon, JText::_('JGLOBAL_EDIT'), null, true);
+ }
+ else
+ {
+ $icon = $article->state ? 'edit' : 'eye-close';
+ if (strtotime($article->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($article->publish_down) < strtotime(JFactory::getDate())) && $article->publish_down != '0000-00-00 00:00:00'))
+ {
+ $icon = 'eye-close';
+ }
+ $text = ' ' . JText::_('JGLOBAL_EDIT') . ' ';
+ }
+
+ $output = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ return $output;
+ }
+
+ /**
+ * Method to generate a popup link to print an article
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the popup link
+ */
+ public static function print_popup($article, $params, $attribs = array(), $legacy = false)
+ {
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $request = $input->request;
+
+ $url = ContentHelperRoute::getArticleRoute($article->slug, $article->catid);
+ $url .= '&tmpl=component&print=1&layout=default&page=' . @ $request->limitstart;
+
+ $status = 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no';
+
+ // checks template image directory for image, if non found default are loaded
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/printButton.png', JText::_('JGLOBAL_PRINT'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_PRINT') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_PRINT');
+ }
+
+ $attribs['title'] = JText::_('JGLOBAL_PRINT');
+ $attribs['onclick'] = "window.open(this.href,'win2','" . $status . "'); return false;";
+ $attribs['rel'] = 'nofollow';
+
+ return JHtml::_('link', JRoute::_($url), $text, $attribs);
+ }
+
+ /**
+ * Method to generate a link to print an article
+ *
+ * @param object $article Not used, @deprecated for 4.0
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Not used, @deprecated for 4.0
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the popup link
+ */
+ public static function print_screen($article, $params, $attribs = array(), $legacy = false)
+ {
+ // Checks template image directory for image, if none found default are loaded
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/printButton.png', JText::_('JGLOBAL_PRINT'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_PRINT') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_PRINT');
+ }
+
+ return '' . $text . ' ';
+ }
+
+}
diff --git a/plugins/system/t3/base-bs3/html/com_content/index.html b/plugins/system/t3/base-bs3/html/com_content/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_content/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_finder/search/default_form.php b/plugins/system/t3/base-bs3/html/com_finder/search/default_form.php
new file mode 100644
index 0000000..eca5a69
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_finder/search/default_form.php
@@ -0,0 +1,121 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_mailto/mailto/default.php b/plugins/system/t3/base-bs3/html/com_mailto/mailto/default.php
new file mode 100644
index 0000000..87281e8
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_mailto/mailto/default.php
@@ -0,0 +1,82 @@
+
+
+get('data');
+?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_mailto/mailto/index.html b/plugins/system/t3/base-bs3/html/com_mailto/mailto/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_mailto/mailto/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_newsfeeds/category/default_items.php b/plugins/system/t3/base-bs3/html/com_newsfeeds/category/default_items.php
new file mode 100644
index 0000000..a216ca2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_newsfeeds/category/default_items.php
@@ -0,0 +1,102 @@
+items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_newsfeeds/category/index.html b/plugins/system/t3/base-bs3/html/com_newsfeeds/category/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_newsfeeds/category/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_newsfeeds/index.html b/plugins/system/t3/base-bs3/html/com_newsfeeds/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_newsfeeds/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_search/search/default.php b/plugins/system/t3/base-bs3/html/com_search/search/default.php
new file mode 100644
index 0000000..94f0d43
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_search/search/default.php
@@ -0,0 +1,30 @@
+
+
+
+ params->get('show_page_heading', 1)) : ?>
+
+ escape($this->params->get('page_heading'))) : ?>
+ escape($this->params->get('page_heading')); ?>
+
+ escape($this->params->get('page_title')); ?>
+
+
+
+
+ loadTemplate('form'); ?>
+ error == null && count($this->results) > 0) :
+ echo $this->loadTemplate('results');
+ else :
+ echo $this->loadTemplate('error');
+ endif; ?>
+
diff --git a/plugins/system/t3/base-bs3/html/com_search/search/default_error.php b/plugins/system/t3/base-bs3/html/com_search/search/default_error.php
new file mode 100644
index 0000000..fef58f1
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_search/search/default_error.php
@@ -0,0 +1,17 @@
+
+
+error) : ?>
+
+ escape($this->error); ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_search/search/default_form.php b/plugins/system/t3/base-bs3/html/com_search/search/default_form.php
new file mode 100644
index 0000000..c46351b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_search/search/default_form.php
@@ -0,0 +1,79 @@
+getUpperLimitSearchWord();
+?>
+
diff --git a/plugins/system/t3/base-bs3/html/com_search/search/default_results.php b/plugins/system/t3/base-bs3/html/com_search/search/default_results.php
new file mode 100644
index 0000000..1ceec3a
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_search/search/default_results.php
@@ -0,0 +1,48 @@
+
+
+
+ results as $result) : ?>
+
+ pagination->limitstart + $result->count . '. '; ?>
+ href) : ?>
+ browsernav == 1) : ?>
+ target="_blank"
+ >
+ escape($result->title); ?>
+
+
+ escape($result->title); ?>
+
+
+ section) : ?>
+
+
+ (escape($result->section); ?>)
+
+
+
+
+ text; ?>
+
+ params->get('show_date')) : ?>
+
+ ' . $result->created . ''); ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_tags/tag/default.php b/plugins/system/t3/base-bs3/html/com_tags/tag/default.php
new file mode 100644
index 0000000..15b36cf
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_tags/tag/default.php
@@ -0,0 +1,63 @@
+item) == 1);
+?>
+
+params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+params->get('show_tag_title', 1)) : ?>
+
+ document->title, '', 'com_tag.tag'); ?>
+
+
+
+item) == 1 && (($this->params->get('tag_list_show_tag_image', 1)) || $this->params->get('tag_list_show_tag_description', 1))) : ?>
+
+ item[0]->images); ?>
+ params->get('tag_list_show_tag_image', 1) == 1 && !empty($images->image_fulltext)) : ?>
+
+
+ params->get('tag_list_show_tag_description') == 1 && $this->item[0]->description) : ?>
+ item[0]->description, '', 'com_tags.tag'); ?>
+
+
+
+
+
+params->get('tag_list_show_tag_description', 1) || $this->params->get('show_description_image', 1)): ?>
+ params->get('show_description_image', 1) == 1 && $this->params->get('tag_list_image')) :?>
+
+
+ params->get('tag_list_description', '') > '') :?>
+ params->get('tag_list_description'), '', 'com_tags.tag'); ?>
+
+
+
+
+loadTemplate('items'); ?>
+ pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+ if (($this->params->def('show_pagination', 1) == 1 || ($this->params->get('show_pagination') == 2)) && ($pagesTotal > 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_tags/tag/default_items.php b/plugins/system/t3/base-bs3/html/com_tags/tag/default_items.php
new file mode 100644
index 0000000..3e12da4
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_tags/tag/default_items.php
@@ -0,0 +1,91 @@
+authorise('core.edit', 'com_tags');
+$canCreate = $user->authorise('core.create', 'com_tags');
+$canEditState = $user->authorise('core.edit.state', 'com_tags');
+$items = $this->items;
+$n = count($this->items);
+
+?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_tags/tags/default.php b/plugins/system/t3/base-bs3/html/com_tags/tags/default.php
new file mode 100644
index 0000000..a0f1717
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_tags/tags/default.php
@@ -0,0 +1,32 @@
+params->get('all_tags_description');
+$descriptionImage = $this->params->get('all_tags_description_image');
+?>
+
+ state->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+ params->get('all_tags_show_description_image') && !empty($descriptionImage)):?>
+
';?>
+
+
+
+
+
+ loadTemplate('items'); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_tags/tags/default_items.php b/plugins/system/t3/base-bs3/html/com_tags/tags/default_items.php
new file mode 100644
index 0000000..ec2704e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_tags/tags/default_items.php
@@ -0,0 +1,152 @@
+authorise('core.edit', 'com_tags');
+$canCreate = $user->authorise('core.create', 'com_tags');
+$canEditState = $user->authorise('core.edit.state', 'com_tags');
+
+$columns = $this->params->get('tag_columns', 1);
+// Avoid division by 0 and negative columns.
+if ($columns < 1)
+{
+ $columns = 1;
+}
+$bsspans = floor(12 / $columns);
+if ($bsspans < 1)
+{
+ $bsspans = 1;
+}
+
+$bscolumns = min($columns, floor(12 / $bsspans));
+$n = count($this->items);
+?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/index.html b/plugins/system/t3/base-bs3/html/com_users/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/login/default_login.php b/plugins/system/t3/base-bs3/html/com_users/login/default_login.php
new file mode 100644
index 0000000..fd0072d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/login/default_login.php
@@ -0,0 +1,114 @@
+
+
+
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+ params->get('logindescription_show') == 1 && str_replace(' ', '', $this->params->get('login_description')) != '') || $this->params->get('login_image') != '') : ?>
+
+
+
+ params->get('logindescription_show') == 1) : ?>
+ params->get('login_description'); ?>
+
+
+ params->get('login_image')!='')) :?>
+
+
+
+ params->get('logindescription_show') == 1 && str_replace(' ', '', $this->params->get('login_description')) != '') || $this->params->get('login_image') != '') : ?>
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_users/login/default_logout.php b/plugins/system/t3/base-bs3/html/com_users/login/default_logout.php
new file mode 100644
index 0000000..491155f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/login/default_logout.php
@@ -0,0 +1,46 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+ params->get('logoutdescription_show') == 1 && str_replace(' ', '', $this->params->get('logout_description')) != '')|| $this->params->get('logout_image') != '') : ?>
+
+
+
+ params->get('logoutdescription_show') == 1) : ?>
+ params->get('logout_description'); ?>
+
+
+ params->get('logout_image') != '')) :?>
+
+
+
+ params->get('logoutdescription_show') == 1 && str_replace(' ', '', $this->params->get('logout_description')) != '')|| $this->params->get('logout_image') != '') : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/login/index.html b/plugins/system/t3/base-bs3/html/com_users/login/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/login/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/default.php b/plugins/system/t3/base-bs3/html/com_users/profile/default.php
new file mode 100644
index 0000000..f95f3d2
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/default.php
@@ -0,0 +1,43 @@
+
+
+id == $this->data->id) : ?>
+
+
+params->get('show_page_heading')) : ?>
+
+
+
+loadTemplate('core'); ?>
+
+loadTemplate('params'); ?>
+
+loadTemplate('custom'); ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/default_core.php b/plugins/system/t3/base-bs3/html/com_users/profile/default_core.php
new file mode 100644
index 0000000..fa7013e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/default_core.php
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+ data->name; ?>
+
+
+
+
+
+ data->username); ?>
+
+
+
+
+
+ data->registerDate); ?>
+
+
+
+
+
+ data->lastvisitDate != '0000-00-00 00:00:00'): ?>
+
+ data->lastvisitDate); ?>
+
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/default_custom.php b/plugins/system/t3/base-bs3/html/com_users/profile/default_custom.php
new file mode 100644
index 0000000..4d7e3aa
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/default_custom.php
@@ -0,0 +1,47 @@
+form->getFieldsets();
+if (isset($fieldsets['core'])) unset($fieldsets['core']);
+if (isset($fieldsets['params'])) unset($fieldsets['params']);
+
+foreach ($fieldsets as $group => $fieldset): // Iterate through the form fieldsets
+ $fields = $this->form->getFieldset($group);
+ if (count($fields)):
+?>
+
+ label)):// If the fieldset has a label set, display it as the legend.?>
+ label); ?>
+
+
+ hidden) :?>
+ title; ?>
+
+ id)):?>
+ id, $field->value);?>
+ fieldname)):?>
+ fieldname, $field->value);?>
+ type)):?>
+ type, $field->value);?>
+
+ value);?>
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/default_params.php b/plugins/system/t3/base-bs3/html/com_users/profile/default_params.php
new file mode 100644
index 0000000..937971b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/default_params.php
@@ -0,0 +1,44 @@
+
+form->getFieldset('params'); ?>
+
+
+
+
+ hidden) :?>
+ title; ?>
+
+ id)):?>
+ id, $field->value);?>
+ fieldname)):?>
+ fieldname, $field->value);?>
+ type)):?>
+ type, $field->value);?>
+
+ value);?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/edit.php b/plugins/system/t3/base-bs3/html/com_users/profile/edit.php
new file mode 100644
index 0000000..c935d65
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/edit.php
@@ -0,0 +1,77 @@
+load('plg_user_profile', JPATH_ADMINISTRATOR);
+?>
+
+params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/profile/index.html b/plugins/system/t3/base-bs3/html/com_users/profile/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/profile/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/registration/complete.php b/plugins/system/t3/base-bs3/html/com_users/registration/complete.php
new file mode 100644
index 0000000..024c57d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/registration/complete.php
@@ -0,0 +1,18 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/registration/default.php b/plugins/system/t3/base-bs3/html/com_users/registration/default.php
new file mode 100644
index 0000000..be27f3b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/registration/default.php
@@ -0,0 +1,66 @@
+
+
+params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/registration/index.html b/plugins/system/t3/base-bs3/html/com_users/registration/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/registration/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/remind/default.php b/plugins/system/t3/base-bs3/html/com_users/remind/default.php
new file mode 100644
index 0000000..53fc79b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/remind/default.php
@@ -0,0 +1,52 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/remind/index.html b/plugins/system/t3/base-bs3/html/com_users/remind/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/remind/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/reset/complete.php b/plugins/system/t3/base-bs3/html/com_users/reset/complete.php
new file mode 100644
index 0000000..02f0a88
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/reset/complete.php
@@ -0,0 +1,41 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/reset/confirm.php b/plugins/system/t3/base-bs3/html/com_users/reset/confirm.php
new file mode 100644
index 0000000..e872c23
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/reset/confirm.php
@@ -0,0 +1,40 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/reset/default.php b/plugins/system/t3/base-bs3/html/com_users/reset/default.php
new file mode 100644
index 0000000..ab48841
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/reset/default.php
@@ -0,0 +1,53 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_users/reset/index.html b/plugins/system/t3/base-bs3/html/com_users/reset/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_users/reset/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/categories/default.php b/plugins/system/t3/base-bs3/html/com_weblinks/categories/default.php
new file mode 100644
index 0000000..a9e5ce5
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/categories/default.php
@@ -0,0 +1,40 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+ params->get('show_base_description')) : ?>
+
+ params->get('categories_description')) : ?>
+
+ params->get('categories_description'), '', 'com_weblinks.categories'); ?>
+
+
+
+ parent->description) : ?>
+
+ parent->description, '', 'com_weblinks.categories'); ?>
+
+
+
+
+ loadTemplate('items'); ?>
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/categories/default_items.php b/plugins/system/t3/base-bs3/html/com_weblinks/categories/default_items.php
new file mode 100644
index 0000000..fd7d095
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/categories/default_items.php
@@ -0,0 +1,63 @@
+items[$this->parent->id]) > 0 && $this->maxLevelcat != 0) : ?>
+items[$this->parent->id] as $id => $item) : ?>
+ params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) :
+ if (!isset($this->items[$this->parent->id][$id + 1]))
+ {
+ $class = ' class="category-item last"';
+ }
+ ?>
+ >
+
+
+ params->get('show_subcat_desc_cat') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_weblinks.categories'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ items[$item->id] = $item->getChildren();
+ $this->parent = $item;
+ $this->maxLevelcat--;
+ echo $this->loadTemplate('items');
+ $this->parent = $item->getParent();
+ $this->maxLevelcat++;
+ ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/categories/index.html b/plugins/system/t3/base-bs3/html/com_weblinks/categories/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/categories/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/category/default.php b/plugins/system/t3/base-bs3/html/com_weblinks/category/default.php
new file mode 100644
index 0000000..1dd9686
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/category/default.php
@@ -0,0 +1,45 @@
+
+
+params->get('show_page_heading')) : ?>
+
+
+params->get('show_category_title', 1)) : ?>
+
+ category->title, '', 'com_weblinks.category'); ?>
+
+
+params->get('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
+
+ params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
+
+
+ params->get('show_description') && $this->category->description) : ?>
+ category->description, '', 'com_weblinks.category'); ?>
+
+
+
+
+loadTemplate('items'); ?>
+children[$this->category->id])&& $this->maxLevel != 0) : ?>
+
+
+ loadTemplate('children'); ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/category/default_children.php b/plugins/system/t3/base-bs3/html/com_weblinks/category/default_children.php
new file mode 100644
index 0000000..772e318
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/category/default_children.php
@@ -0,0 +1,57 @@
+children[$this->category->id]) > 0 && $this->maxLevel != 0) :
+?>
+
+item->params;
+JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html');
+
+if(version_compare(JVERSION, '3.0', 'lt')){
+ JHtml::_('behavior.tooltip');
+}
+JHtml::_('behavior.framework');
+
+// Get the user object.
+$user = JFactory::getUser();
+// Check if user is allowed to add/edit based on weblinks permissinos.
+$canEdit = $user->authorise('core.edit', 'com_weblinks');
+$canCreate = $user->authorise('core.create', 'com_weblinks');
+$canEditState = $user->authorise('core.edit.state', 'com_weblinks');
+
+$n = count($this->items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/category/index.html b/plugins/system/t3/base-bs3/html/com_weblinks/category/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/category/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/form/edit.php b/plugins/system/t3/base-bs3/html/com_weblinks/form/edit.php
new file mode 100644
index 0000000..47d3442
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/form/edit.php
@@ -0,0 +1,145 @@
+state->get('params');
+?>
+
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/form/index.html b/plugins/system/t3/base-bs3/html/com_weblinks/form/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/form/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/com_weblinks/index.html b/plugins/system/t3/base-bs3/html/com_weblinks/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/com_weblinks/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/index.html b/plugins/system/t3/base-bs3/html/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/index.html b/plugins/system/t3/base-bs3/html/layouts/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/associations.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/associations.php
new file mode 100644
index 0000000..b6c3695
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/associations.php
@@ -0,0 +1,22 @@
+
+
+ $item) : ?>
+
+ link; ?>
+
+
+
+params;
+$canEdit = $displayData->params->get('access-edit');
+JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html');
+JHtml::_('behavior.framework');
+?>
+
+ get('show_title') || $displayData->state == 0 || ($params->get('show_author') && !empty($displayData->author ))) : ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/blog_style_default_links.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/blog_style_default_links.php
new file mode 100644
index 0000000..873e502
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/blog_style_default_links.php
@@ -0,0 +1,19 @@
+
+
+get('link_items') as $item) : ?>
+
+
+ title; ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default.php
new file mode 100644
index 0000000..8d2e137
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default.php
@@ -0,0 +1,34 @@
+
+
+params->get('show_page_heading')) : ?>
+
+ escape($displayData->params->get('page_heading')); ?>
+
+
+
+params->get('show_base_description')) : ?>
+
+ params->get('categories_description')) : ?>
+
+ params->get('categories_description'), '', $displayData->get('extension') . '.categories'); ?>
+
+
+
+ parent->description) : ?>
+
+ parent->description, '', $displayData->parent->extension . '.categories'); ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default_items.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default_items.php
new file mode 100644
index 0000000..d8bb18e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/categories_default_items.php
@@ -0,0 +1,25 @@
+item;
+$items = $displayData->get('items');
+$params = $displayData->params;
+$extension = $displayData->get('extension');
+$className = substr($extension, 4);
+// This will work for the core components but not necessarily for other components
+// that may have different pluralisation rules.
+if (substr($className, -1) == 's')
+{
+ $className = rtrim($className, 's');
+}
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/category_default.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/category_default.php
new file mode 100644
index 0000000..2104898
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/category_default.php
@@ -0,0 +1,65 @@
+params;
+$extension = $displayData->get('category')->extension;
+$canEdit = $params->get('access-edit');
+$className = substr($extension, 4);
+// This will work for the core components but not necessarily for other components
+// that may have different pluralisation rules.
+if (substr($className, -1) == 's')
+{
+ $className = rtrim($className, 's');
+}
+$tagsData = isset($displayData->get('category')->tags) ? $displayData->get('category')->tags->itemTags : null;
+?>
+
+ get('show_page_heading')) : ?>
+
+ escape($params->get('page_heading')); ?>
+
+
+ get('show_category_title', 1)) : ?>
+
+ get('category')->title, '', $extension.'.category.title'); ?>
+
+
+ get('show_tags', 1)) : ?>
+
+
+ get('show_description', 1) || $params->def('show_description_image', 1)) : ?>
+
+ get('show_description_image') && $displayData->get('category')->getParams()->get('image')) : ?>
+
+
+ get('show_description') && $displayData->get('category')->description) : ?>
+ get('category')->description, '', $extension .'.category'); ?>
+
+
+
+
+
+
+ loadTemplate($displayData->subtemplatename); ?>
+
+
+ get('children') && $displayData->maxLevel != 0) : ?>
+
+
+
+
+
+ loadTemplate('children'); ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/fulltext_image.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/fulltext_image.php
new file mode 100644
index 0000000..4358a26
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/fulltext_image.php
@@ -0,0 +1,27 @@
+images);
+if (empty($images->image_fulltext)) return ;
+
+$imgfloat = (empty($images->float_fulltext)) ? $params->get('float_fulltext') : $images->float_fulltext;
+?>
+
+
+
image_fulltext_caption): ?>
+ image_fulltext_caption) . '"'; ?>
+
+ src="image_fulltext); ?>"
+ alt="image_fulltext_alt); ?>" itemprop="image"/>
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/icons.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/icons.php
new file mode 100644
index 0000000..3161b6d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/icons.php
@@ -0,0 +1,42 @@
+get('access-edit');
+
+?>
+
+
+
+ get('show_print_icon') || $displayData['params']->get('show_email_icon')) : ?>
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/content/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/author.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/author.php
new file mode 100644
index 0000000..0643887
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/author.php
@@ -0,0 +1,23 @@
+created_by_alias ? $item->created_by_alias : $item->author);
+$author = '' . $author . ' ';
+?>
+
+
+
+ contact_link ) && $displayData['params']->get('link_author') == true) : ?>
+ contact_link, $author, array('itemprop' => 'url')); ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/block.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/block.php
new file mode 100644
index 0000000..d7fd875
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/block.php
@@ -0,0 +1,60 @@
+get('info_block_position', 2);
+?>
+
+
+
+
+
+
+ get('info_block_show_title', 1)) : ?>
+
+
+
+
+ get('show_author') && !empty($displayData['item']->author )) : ?>
+
+
+
+ get('show_parent_category') && !empty($displayData['item']->parent_slug)) : ?>
+
+
+
+ get('show_category')) : ?>
+
+
+
+ get('show_publish_date')) : ?>
+
+
+
+
+
+ get('show_create_date')) : ?>
+
+
+
+ get('show_modify_date')) : ?>
+
+
+
+ get('show_hits')) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/category.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/category.php
new file mode 100644
index 0000000..5415f07
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/category.php
@@ -0,0 +1,24 @@
+escape($item->category_title);
+if (!isset($item->catslug)) {
+ $item->catslug = $item->category_alias ? ($item->catid.':'.$item->category_alias) : $item->catid;
+}
+?>
+
+
+ get('link_category') && $item->catslug) : ?>
+ catslug)), ''.$title.' '); ?>
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/create_date.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/create_date.php
new file mode 100644
index 0000000..18aae59
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/create_date.php
@@ -0,0 +1,18 @@
+
+
+
+
+ created, JText::_('DATE_FORMAT_LC3'))); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/hits.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/hits.php
new file mode 100644
index 0000000..a74306a
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/hits.php
@@ -0,0 +1,17 @@
+
+
+
+
+ hits); ?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/modify_date.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/modify_date.php
new file mode 100644
index 0000000..8569604
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/modify_date.php
@@ -0,0 +1,18 @@
+
+
+
+
+ modified, JText::_('DATE_FORMAT_LC3'))); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/parent_category.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/parent_category.php
new file mode 100644
index 0000000..8646f2b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/parent_category.php
@@ -0,0 +1,23 @@
+escape($item->parent_title);
+?>
+
+
+ get('link_parent_category') && !empty($item->parent_slug)) : ?>
+ parent_slug)), ''.$title.' '); ?>
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/publish_date.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/publish_date.php
new file mode 100644
index 0000000..704fda5
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/info_block/publish_date.php
@@ -0,0 +1,17 @@
+
+
+
+
+ publish_up, JText::_('DATE_FORMAT_LC3')); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/intro_image.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/intro_image.php
new file mode 100644
index 0000000..c9d32c1
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/intro_image.php
@@ -0,0 +1,21 @@
+params;
+?>
+images); ?>
+image_intro) && !empty($images->image_intro)) : ?>
+ float_intro)) ? $params->get('float_intro') : $images->float_intro; ?>
+ image_intro_caption):
+ echo 'class="caption"' . ' title="' . htmlspecialchars($images->image_intro_caption) . '"';
+ endif; ?>
+ src="image_intro); ?>" alt="image_intro_alt); ?>" itemprop="thumbnailUrl"/>
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/item_title.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/item_title.php
new file mode 100644
index 0000000..43427da
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/item_title.php
@@ -0,0 +1,45 @@
+get('access-edit');
+if (empty ($item->catslug)) {
+ $item->catslug = $item->category_alias ? ($item->catid.':'.$item->category_alias) : $item->catid;
+}
+$url = JRoute::_(ContentHelperRoute::getArticleRoute($item->slug, $item->catslug));
+$uri = JUri::getInstance();
+$prefix = $uri->toString(array('scheme', 'host', 'port'));
+?>
+
+
+ < class="article-title" itemprop="name">
+ get('link_titles')) : ?>
+
+ escape($item->title); ?>
+
+ escape($item->title); ?>
+
+
+ >
+
+ state == 0) : ?>
+
+
+ publish_up) > strtotime(JFactory::getDate())) : ?>
+
+
+ publish_down) < strtotime(JFactory::getDate())) && $item->publish_down != '0000-00-00 00:00:00') : ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/options_default.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/options_default.php
new file mode 100644
index 0000000..c80ac8e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/options_default.php
@@ -0,0 +1,50 @@
+
+
+ name ?>
+ description)): ?>
+ description; ?>
+
+ fieldsname);
+ foreach($fieldsnames as $fieldname)
+ {
+ foreach ($displayData->form->getFieldset($fieldname) as $field)
+ {
+ $classnames = 'control-group';
+ $rel = '';
+ $showon = $displayData->form->getFieldAttribute($field->fieldname, 'showon');
+ if (!empty($showon))
+ {
+ JHtml::_('jquery.framework');
+ JHtml::_('script', 'jui/cms.js', false, true);
+
+ $id = $displayData->form->getFormControl();
+ $showon = explode(':', $showon, 2);
+ $classnames .= ' showon_' . implode(' showon_', explode(',', $showon[1]));
+ $rel = ' rel="showon_' . $id . '['. $showon[0] . ']"';
+ }
+ ?>
+ >
+ showlabel) || $displayData->showlabel): ?>
+
label; ?>
+
+
input; ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/content/tags.php b/plugins/system/t3/base-bs3/html/layouts/joomla/content/tags.php
new file mode 100644
index 0000000..8b06229
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/content/tags.php
@@ -0,0 +1,29 @@
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/associations.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/associations.php
new file mode 100644
index 0000000..b8facc1
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/associations.php
@@ -0,0 +1,13 @@
+getForm()->renderFieldset('item_associations');
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/details.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/details.php
new file mode 100644
index 0000000..27cec29
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/details.php
@@ -0,0 +1,104 @@
+getForm()->getValue('title');
+$published = $displayData->getForm()->getField('published');
+$saveHistory = $displayData->get('state')->get('params')->get('save_history', 0);
+?>
+
+
+
+
+
+
+
+ getForm()->getValue('name'); ?>
+
+
+
+
+
+ getForm()->getValue('title'); ?>
+
+
+
+
+
+
+ getForm()->getLabel('published'); ?>
+
+
+ getForm()->getInput('published'); ?>
+
+
+
+
+
+ getForm()->getLabel('state'); ?>
+
+
+ getForm()->getInput('state'); ?>
+
+
+
+
+
+ getForm()->getLabel('access'); ?>
+
+
+ getForm()->getInput('access'); ?>
+
+
+
+
+ getForm()->getLabel('featured'); ?>
+
+
+ getForm()->getInput('featured'); ?>
+
+
+
+
+
+ getForm()->getLabel('language'); ?>
+
+
+ getForm()->getInput('language'); ?>
+
+
+
+
+
+
+
+ getForm()->getLabel('tags'); ?>
+
+
+ getForm()->getInput('tags'); ?>
+
+
+
+
+
+ getForm()->getLabel('version_note'); ?>
+
+
+ getForm()->getInput('version_note'); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/fieldset.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/fieldset.php
new file mode 100644
index 0000000..03e96e6
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/fieldset.php
@@ -0,0 +1,68 @@
+getForm();
+
+$name = $displayData->get('fieldset');
+$fieldSet = $form->getFieldset($name);
+
+if (empty($fieldSet))
+{
+ return;
+}
+
+$ignoreFields = $displayData->get('ignore_fields') ? : array();
+$extraFields = $displayData->get('extra_fields') ? : array();
+
+if ($displayData->get('show_options', 1))
+{
+ if (isset($fieldSet->description) && trim($fieldSet->description))
+ {
+ echo '' . $this->escape(JText::_($fieldSet->description)) . '
';
+ }
+
+ if (isset($extraFields[$name]))
+ {
+ foreach ($extraFields[$name] as $f)
+ {
+ if (in_array($f, $ignoreFields))
+ {
+ continue;
+ }
+ if ($form->getField($f))
+ {
+ $fieldSet[] = $form->getField($f);
+ }
+ }
+ }
+
+ $html = array();
+
+ foreach ($fieldSet as $field)
+ {
+ $html[] = $field->renderField();
+ }
+
+ echo implode('', $html);
+}
+else
+{
+ $html = array();
+ $html[] = '';
+ foreach ($fieldSet as $field)
+ {
+ $html[] = $field->input;
+ }
+ $html[] = '
';
+
+ echo implode('', $html);
+}
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/frontediting_modules.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/frontediting_modules.php
new file mode 100644
index 0000000..5387a7c
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/frontediting_modules.php
@@ -0,0 +1,61 @@
+]*class="[^"]* jmoddiv"/', $moduleHtml))
+{
+ // Module has already module edit button:
+ return;
+}
+
+// Add css class jmoddiv and data attributes for module-editing URL and for the tooltip:
+$editUrl = JUri::base() . 'administrator/index.php?option=com_modules&view=module&layout=edit&id=' . (int) $mod->id;
+
+// Add class, editing URL and tooltip, and if module of type menu, also the tooltip for editing the menu item:
+$count = 0;
+$moduleHtml = preg_replace(
+ // Replace first tag of module with a class
+ '/^(\s*<(?:div|span|nav|ul|ol|h\d) [^>]*class="[^"]*)"/',
+ // By itself, adding class jmoddiv and data attributes for the url and tooltip:
+ '\\1 jmoddiv" data-jmodediturl="' . $editUrl . '" data-jmodtip="'
+ . T3J::tooltipText(
+ JText::_('JLIB_HTML_EDIT_MODULE'),
+ htmlspecialchars($mod->title) . ' ' . sprintf(JText::_('JLIB_HTML_EDIT_MODULE_IN_POSITION'), htmlspecialchars($position)),
+ 0
+ )
+ . '"'
+ // And if menu editing is enabled and allowed and it's a menu module, add data attributes for menu editing:
+ . ($menusEditing && $mod->module == 'mod_menu' ?
+ '" data-jmenuedittip="' . T3J::tooltipText('JLIB_HTML_EDIT_MENU_ITEM', 'JLIB_HTML_EDIT_MENU_ITEM_ID') . '"'
+ :
+ ''
+ ),
+ $moduleHtml,
+ 1,
+ $count
+);
+
+if ($count)
+{
+ // Load once booststrap tooltip and add stylesheet and javascript to head:
+ JHtml::_('bootstrap.tooltip');
+ JHtml::_('bootstrap.popover');
+
+ JHtml::_('stylesheet', 'system/frontediting.css', array(), true);
+ JHtml::_('script', 'system/frontediting.js', false, true);
+}
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/global.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/global.php
new file mode 100644
index 0000000..6df535b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/global.php
@@ -0,0 +1,72 @@
+getForm();
+$input = $app->input;
+$component = $input->getCmd('option', 'com_content');
+if ($component == 'com_categories')
+{
+ $extension = $input->getCmd('extension', 'com_content');
+ $parts = explode('.', $extension);
+ $component = $parts[0];
+}
+$saveHistory = JComponentHelper::getParams($component)->get('save_history', 0);
+
+$fields = $displayData->get('fields') ?: array(
+ array('category', 'catid'),
+ array('parent', 'parent_id'),
+ 'tags',
+ array('published', 'state', 'enabled'),
+ 'featured',
+ 'sticky',
+ 'access',
+ 'language',
+ 'note',
+ 'version_note'
+);
+
+$hiddenFields = $displayData->get('hidden_fields') ?: array();
+
+// Multilanguage check:
+/*if (!JLanguageMultilang::isEnabled())
+{
+ $hiddenFields[] = 'language';
+}*/
+if (!$saveHistory)
+{
+ $hiddenFields[] = 'version_note';
+}
+
+$html = array();
+$html[] = '';
+
+foreach ($fields as $field)
+{
+ $field = is_array($field) ? $field : array($field);
+ foreach ($field as $f)
+ {
+ if ($form->getField($f))
+ {
+ if (in_array($f, $hiddenFields))
+ {
+ $form->setFieldAttribute($f, 'type', 'hidden');
+ }
+
+ $html[] = $form->renderField($f);
+ break;
+ }
+ }
+}
+
+$html[] = ' ';
+
+echo implode('', $html);
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/item_title.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/item_title.php
new file mode 100644
index 0000000..1930253
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/item_title.php
@@ -0,0 +1,24 @@
+getForm()->getValue('title');
+$name = $displayData->getForm()->getValue('name');
+
+?>
+
+
+
+
+
+
+
+getForm();
+
+// JLayout for standard handling of metadata fields in the administrator content edit screens.
+$fieldSets = $form->getFieldsets('metadata');
+?>
+
+ $fieldSet) : ?>
+ description) && trim($fieldSet->description)) : ?>
+ escape(JText::_($fieldSet->description)); ?>
+
+
+ renderField('metadesc');
+ echo $form->renderField('metakey');
+ echo $form->renderField('xreference');
+ }
+
+ foreach ($form->getFieldset($name) as $field)
+ {
+ if ($field->name != 'jform[metadata][tags][]')
+ {
+ echo $field->renderField();
+ }
+ } ?>
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/params.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/params.php
new file mode 100644
index 0000000..c62bd98
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/params.php
@@ -0,0 +1,98 @@
+getForm();
+
+$fieldSets = $form->getFieldsets('params');
+if (empty($fieldSets))
+{
+ $fieldSets = $form->getFieldsets('attribs');
+}
+
+if (empty($fieldSets))
+{
+ return;
+}
+
+$ignoreFieldsets = $displayData->get('ignore_fieldsets') ?: array();
+$ignoreFields = $displayData->get('ignore_fields') ?: array();
+$extraFields = $displayData->get('extra_fields') ?: array();
+
+if (!empty($displayData->hiddenFieldsets))
+{
+ // These are required to preserve data on save when fields are not displayed.
+ $hiddenFieldsets = $displayData->hiddenFieldsets ?: array();
+}
+
+if (!empty($displayData->configFieldsets))
+{
+ // These are required to configure showing and hiding fields in the editor.
+ $configFieldsets = $displayData->configFieldsets ?: array();
+}
+
+if ($displayData->get('show_options', 1))
+{
+ foreach ($fieldSets as $name => $fieldSet)
+ {
+ // Ensure any fieldsets we don't want to show are skipped (including repeating formfield fieldsets)
+ if (in_array($name, $ignoreFieldsets) || (!empty($configFieldsets) && in_array($name, $configFieldsets))
+ || !empty($hiddenFieldsets) && in_array($name, $hiddenFieldsets)
+ || (isset($fieldSet->repeat) && $fieldSet->repeat == true))
+ {
+ continue;
+ }
+
+ if (!empty($fieldSet->label))
+ {
+ $label = JText::_($fieldSet->label, true);
+ }
+ else
+ {
+ $label = strtoupper('JGLOBAL_FIELDSET_' . $name);
+ if (JText::_($label, true) == $label)
+ {
+ $label = strtoupper($app->input->get('option') . '_' . $name . '_FIELDSET_LABEL');
+ }
+ $label = JText::_($label, true);
+ }
+
+ echo JHtml::_('bootstrap.addTab', 'myTab', 'attrib-' . $name, $label);
+
+ $displayData->fieldset = $name;
+ echo JLayoutHelper::render('joomla.edit.fieldset', $displayData);
+
+ echo JHtml::_('bootstrap.endTab');
+ }
+}
+else
+{
+ $html = array();
+ $html[] = '';
+ foreach ($fieldSets as $name => $fieldSet)
+ {
+ if (in_array($name, $ignoreFieldsets))
+ {
+ continue;
+ }
+
+ if (in_array($name, $hiddenFieldsets))
+ {
+ foreach ($form->getFieldset($name) as $field)
+ {
+ echo $field->input;
+ }
+ }
+ }
+ $html[] = '
';
+
+ echo implode('', $html);
+}
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/publishingdata.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/publishingdata.php
new file mode 100644
index 0000000..40e8441
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/publishingdata.php
@@ -0,0 +1,46 @@
+getForm();
+
+$fields = $displayData->get('fields') ?: array(
+ 'publish_up',
+ 'publish_down',
+ array('created', 'created_time'),
+ array('created_by', 'created_user_id'),
+ 'created_by_alias',
+ array('modified', 'modified_time'),
+ array('modified_by', 'modified_user_id'),
+ 'version',
+ 'hits',
+ 'id'
+);
+
+$hiddenFields = $displayData->get('hidden_fields') ?: array();
+
+foreach ($fields as $field)
+{
+ $field = is_array($field) ? $field : array($field);
+ foreach ($field as $f)
+ {
+ if ($form->getField($f))
+ {
+ if (in_array($f, $hiddenFields))
+ {
+ $form->setFieldAttribute($f, 'type', 'hidden');
+ }
+
+ echo $form->renderField($f);
+ break;
+ }
+ }
+}
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/edit/title_alias.php b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/title_alias.php
new file mode 100644
index 0000000..da19d5d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/edit/title_alias.php
@@ -0,0 +1,22 @@
+getForm();
+
+$title = $form->getField('title') ? 'title' : ($form->getField('name') ? 'name' : '');
+
+?>
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons.php b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons.php
new file mode 100644
index 0000000..fa32b1c
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons.php
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons/button.php b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons/button.php
new file mode 100644
index 0000000..7d9d024
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/buttons/button.php
@@ -0,0 +1,26 @@
+
+get('name')) : ?>
+ get('class')) ? $button->get('class') : null;
+ $class .= ($button->get('modal')) ? ' modal-button' : null;
+ $href = ($button->get('link')) ? ' href="' . JUri::base() . $button->get('link') . '"' : null;
+ $onclick = ($button->get('onclick')) ? ' onclick="' . $button->get('onclick') . '"' : ' onclick="IeCursorFix(); return false;"';
+ $title = ($button->get('title')) ? $button->get('title') : $button->get('text');
+ ?>
+ rel="get('options'); ?>">
+ get('text'); ?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/editors/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/editors/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/form/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/form/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/form/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/form/renderfield.php b/plugins/system/t3/base-bs3/html/layouts/joomla/form/renderfield.php
new file mode 100644
index 0000000..c36c34e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/form/renderfield.php
@@ -0,0 +1,35 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupclose.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupclose.php
new file mode 100644
index 0000000..1f2eb2b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupopen.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupopen.php
new file mode 100644
index 0000000..d51482c
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupopen.php
@@ -0,0 +1,13 @@
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsclose.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsclose.php
new file mode 100644
index 0000000..1f8eb24
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupseparator.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupseparator.php
new file mode 100644
index 0000000..f661627
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupseparator.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsopen.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsopen.php
new file mode 100644
index 0000000..5a74c90
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/groupsopen.php
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/links/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/links/link.php b/plugins/system/t3/base-bs3/html/layouts/joomla/links/link.php
new file mode 100644
index 0000000..402a2cd
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/links/link.php
@@ -0,0 +1,23 @@
+escape($displayData['title']) . '"');
+$text = empty($displayData['text']) ? '' : ('
' . $displayData['text'] . ' ')
+
+?>
+
>
+ >
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/link.php b/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/link.php
new file mode 100644
index 0000000..bee0caf
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/pagination/link.php
@@ -0,0 +1,88 @@
+text;
+
+switch ((string) $item->text)
+{
+ // Check for "Start" item
+ case JText::_('JLIB_HTML_START') :
+ $icon = "icon-backward";
+ break;
+
+ // Check for "Prev" item
+ case $item->text == JText::_('JPREV') :
+ $item->text = JText::_('JPREVIOUS');
+ $icon = "icon-step-backward";
+ break;
+
+ // Check for "Next" item
+ case JText::_('JNEXT') :
+ $icon = "icon-step-forward";
+ break;
+
+ // Check for "End" item
+ case JText::_('JLIB_HTML_END') :
+ $icon = "icon-forward";
+ break;
+
+ default:
+ $icon = null;
+ break;
+}
+
+if ($icon !== null)
+{
+ $display = '
';
+}
+
+if ($displayData['active'])
+{
+ if ($item->base > 0)
+ {
+ $limit = 'limitstart.value=' . $item->base;
+ }
+ else
+ {
+ $limit = 'limitstart.value=0';
+ }
+
+ $cssClasses = array();
+
+ $title = '';
+
+ if (!is_numeric($item->text))
+ {
+ JHtml::_('bootstrap.tooltip');
+ $cssClasses[] = 'hasTooltip';
+ $title = ' title="' . $item->text . '" ';
+ }
+
+ $onClick = 'document.adminForm.' . $item->prefix . 'limitstart.value=' . ($item->base > 0 ? $item->base : '0') . '; Joomla.submitform();return false;';
+}
+else
+{
+ $class = (property_exists($item, 'active') && $item->active) ? 'active' : 'disabled';
+}
+?>
+
+
+ href="#" onclick="">
+
+
+
+
+
+
+
+get('showLimitBox', true);
+$showPagesLinks = $options->get('showPagesLinks', true);
+$showLimitStart = $options->get('showLimitStart', true);
+
+// Calculate to display range of pages
+$currentPage = 1;
+$range = 1;
+$step = 5;
+
+if (!empty($pages['pages']))
+{
+ foreach ($pages['pages'] as $k => $page)
+ {
+ if (!$page['active'])
+ {
+ $currentPage = $k;
+ }
+ }
+}
+
+if ($currentPage >= $step)
+{
+ if ($currentPage % $step == 0)
+ {
+ $range = ceil($currentPage / $step) + 1;
+ }
+ else
+ {
+ $range = ceil($currentPage / $step);
+ }
+}
+?>
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/icon.php b/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/icon.php
new file mode 100644
index 0000000..caae785
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/icon.php
@@ -0,0 +1,25 @@
+escape($displayData['title']) . '"');
+$text = empty($displayData['text']) ? '' : ('
' . $displayData['text'] . ' ')
+
+?>
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/quickicons/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default.php b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default.php
new file mode 100644
index 0000000..4082d26
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default.php
@@ -0,0 +1,46 @@
+ isset($data['options']['filtersHidden']) ? $data['options']['filtersHidden'] : empty($data['view']->activeFilters),
+ 'defaultLimit' => isset($data['options']['defaultLimit']) ? $data['options']['defaultLimit'] : JFactory::getApplication()->getCfg('list_limit', 20),
+ 'searchFieldSelector' => '#filter_search',
+ 'orderFieldSelector' => '#list_fullordering'
+);
+
+$data['options'] = array_unique(array_merge($customOptions, $data['options']));
+
+$formSelector = !empty($data['options']['formSelector']) ? $data['options']['formSelector'] : '#adminForm';
+
+// Load search tools
+JHtml::_('searchtools.form', $formSelector, $data['options']);
+
+?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/bar.php b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/bar.php
new file mode 100644
index 0000000..2bb11b6
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/bar.php
@@ -0,0 +1,53 @@
+get('filterButton', true);
+$searchButton = $data['options']->get('searchButton', true);
+
+$filters = $data['view']->filterForm->getGroup('filter');
+?>
+
+
+
+
+
+
+
+ input; ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+filterForm->getGroup('filter');
+?>
+
+ $field) : ?>
+
+
+ input; ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/list.php b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/list.php
new file mode 100644
index 0000000..5350f6d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/default/list.php
@@ -0,0 +1,25 @@
+filterForm->getGroup('list');
+?>
+
+
+ $field) : ?>
+
+ input; ?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/sort.php b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/sort.php
new file mode 100644
index 0000000..2e0f4bd
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/grid/sort.php
@@ -0,0 +1,27 @@
+tip ? $data->tip : $data->title), JText::_('JGLOBAL_CLICK_TO_SORT_THIS_COLUMN'), 0);
+JHtml::_('bootstrap.tooltip');
+?>
+
+ icon)) : ?>
+
+
+ title)) : ?>
+ title); ?>
+
+ order == $data->selected) : ?>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/searchtools/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/submenu.php b/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/submenu.php
new file mode 100644
index 0000000..99088f9
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/sidebars/submenu.php
@@ -0,0 +1,55 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/system/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/system/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/system/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/system/message.php b/plugins/system/t3/base-bs3/html/layouts/joomla/system/message.php
new file mode 100644
index 0000000..8d5178e
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/system/message.php
@@ -0,0 +1,35 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons.php b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons.php
new file mode 100644
index 0000000..4855d18
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons.php
@@ -0,0 +1,15 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/button.php b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/button.php
new file mode 100644
index 0000000..9ff8ce6
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/button.php
@@ -0,0 +1,15 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/buttons/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/textarea.php b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/textarea.php
new file mode 100644
index 0000000..d91cb79
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/textarea.php
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/togglebutton.php b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/togglebutton.php
new file mode 100644
index 0000000..f15b359
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/tinymce/togglebutton.php
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/base.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/base.php
new file mode 100644
index 0000000..1f0bb5d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/base.php
@@ -0,0 +1,14 @@
+
+
>
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/batch.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/batch.php
new file mode 100644
index 0000000..65fd2d6
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/batch.php
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/confirm.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/confirm.php
new file mode 100644
index 0000000..cc63357
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/confirm.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containerclose.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containerclose.php
new file mode 100644
index 0000000..1f8eb24
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containerclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containeropen.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containeropen.php
new file mode 100644
index 0000000..196ecae
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/containeropen.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/help.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/help.php
new file mode 100644
index 0000000..5c377c5
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/help.php
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/iconclass.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/iconclass.php
new file mode 100644
index 0000000..9785851
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/iconclass.php
@@ -0,0 +1,12 @@
+
+icon-
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/index.html b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/link.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/link.php
new file mode 100644
index 0000000..eba13cc
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/link.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/popup.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/popup.php
new file mode 100644
index 0000000..5c76d9b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/popup.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/separator.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/separator.php
new file mode 100644
index 0000000..e8bbb4c
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/separator.php
@@ -0,0 +1,16 @@
+
+
>
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/slider.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/slider.php
new file mode 100644
index 0000000..a639f9a
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/slider.php
@@ -0,0 +1,21 @@
+
+
>
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/standard.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/standard.php
new file mode 100644
index 0000000..8f5a0f5
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/standard.php
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/title.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/title.php
new file mode 100644
index 0000000..b1e24e8
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/title.php
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/versions.php b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/versions.php
new file mode 100644
index 0000000..6add897
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/joomla/toolbar/versions.php
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtab.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtab.php
new file mode 100644
index 0000000..1412206
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtab.php
@@ -0,0 +1,17 @@
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtabscript.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtabscript.php
new file mode 100644
index 0000000..1fe41eb
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/addtabscript.php
@@ -0,0 +1,24 @@
+
" . $title . " ');
+ $('#" . $selector . "Tabs').append(tab);
+ });
+ })(jQuery);";
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtab.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtab.php
new file mode 100644
index 0000000..370f8ce
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtab.php
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtabset.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtabset.php
new file mode 100644
index 0000000..370f8ce
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/endtabset.php
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/index.html b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabset.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabset.php
new file mode 100644
index 0000000..50d8963
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabset.php
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php
new file mode 100644
index 0000000..238cdd7
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php
@@ -0,0 +1,20 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/cms/index.html b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/cms/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/layouts/libraries/index.html b/plugins/system/t3/base-bs3/html/layouts/libraries/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/layouts/libraries/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/mod_breadcrumbs/default.php b/plugins/system/t3/base-bs3/html/mod_breadcrumbs/default.php
new file mode 100644
index 0000000..9e6c950
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_breadcrumbs/default.php
@@ -0,0 +1,63 @@
+
+
+
+ get('showHere', 1)) {
+ echo '' . JText::_('MOD_BREADCRUMBS_HERE') . ' ';
+ } else {
+ echo ' ';
+ }
+
+ // Get rid of duplicated entries on trail including home page when using multilanguage
+ for ($i = 0; $i < $count; $i++) {
+ if ($i == 1 && !empty($list[$i]->link) && !empty($list[$i - 1]->link) && $list[$i]->link == $list[$i - 1]->link) {
+ unset($list[$i]);
+ }
+ }
+ // Find last and penultimate items in breadcrumbs list
+ end($list);
+ $last_item_key = key($list);
+ prev($list);
+ $penult_item_key = key($list);
+
+ // Generate the trail
+ foreach ($list as $key => $item) :
+ // Make a link if not the last item in the breadcrumbs
+ $show_last = $params->get('showLast', 1);
+
+ if ($key != $last_item_key) {
+ // Render all but last item - along with separator
+ echo '';
+ if (!empty($item->link)) {
+ echo '' . $item->name . ' ';
+ } else {
+ echo '' . $item->name . ' ';
+ }
+
+ if (($key != $penult_item_key) || $show_last) {
+ echo '' . $separator . ' ';
+ }
+
+ echo ' ';
+ } elseif ($show_last) {
+ // Render last item if reqd.
+ echo '';
+ echo '' . $item->name . ' ';
+ echo ' ';
+ }
+ endforeach; ?>
+
diff --git a/plugins/system/t3/base-bs3/html/mod_breadcrumbs/index.html b/plugins/system/t3/base-bs3/html/mod_breadcrumbs/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_breadcrumbs/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/mod_finder/default.php b/plugins/system/t3/base-bs3/html/mod_finder/default.php
new file mode 100644
index 0000000..79d56b7
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_finder/default.php
@@ -0,0 +1,164 @@
+load('com_finder', JPATH_SITE);
+
+$suffix = $params->get('moduleclass_sfx');
+$output = '
';
+$button = '';
+$label = '';
+
+if ($params->get('show_label', 1))
+{
+ $label = '
' . $params->get('alt_label', JText::_('JSEARCH_FILTER_SUBMIT')) . ' ';
+
+ switch ($params->get('label_pos', 'left')):
+ case 'top' :
+ $label = $label . '
';
+ $output = $label . $output;
+ break;
+
+ case 'bottom' :
+ $label = '
' . $label;
+ $output = $output . $label;
+ break;
+
+ case 'right' :
+ $output = $output . $label;
+ break;
+
+ case 'left' :
+ default :
+ $output = $label . $output;
+ break;
+ endswitch;
+}
+
+$output = '
' . $output . '
';
+
+if ($params->get('show_button', 1))
+{
+ $button = '
';
+
+ switch ($params->get('button_pos', 'right')):
+ case 'top' :
+ $button = $button . '
';
+ $output = $button . $output;
+ break;
+
+ case 'bottom' :
+ $button = '
' . $button;
+ $output = $output . $button;
+ break;
+
+ case 'right' :
+ $output = $output . $button;
+ break;
+
+ case 'left' :
+ default :
+ $output = $button . $output;
+ break;
+ endswitch;
+}
+
+JHtml::stylesheet('com_finder/finder.css', false, true, false);
+?>
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/mod_finder/index.html b/plugins/system/t3/base-bs3/html/mod_finder/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_finder/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/mod_footer/default.php b/plugins/system/t3/base-bs3/html/mod_footer/default.php
new file mode 100644
index 0000000..ccc25f1
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_footer/default.php
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/mod_footer/index.html b/plugins/system/t3/base-bs3/html/mod_footer/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_footer/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/mod_login/default.php b/plugins/system/t3/base-bs3/html/mod_login/default.php
new file mode 100644
index 0000000..1d76809
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_login/default.php
@@ -0,0 +1,144 @@
+
+
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/mod_login/index.html b/plugins/system/t3/base-bs3/html/mod_login/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_login/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base-bs3/html/mod_menu/default.php b/plugins/system/t3/base-bs3/html/mod_menu/default.php
new file mode 100644
index 0000000..49b2b21
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_menu/default.php
@@ -0,0 +1,95 @@
+
+
get('tag_id') != null)
+ {
+ $tag = $params->get('tag_id').'';
+ echo ' id="'.$tag.'"';
+ }
+?>>
+ &$item) :
+ $class = 'item-'.$item->id;
+ if ($item->id == $active_id) {
+ $class .= ' current';
+ }
+
+ if (in_array($item->id, $path)) {
+ $class .= ' active';
+ }
+ elseif ($item->type == 'alias') {
+ $aliasToId = $item->params->get('aliasoptions');
+ if (count($path) > 0 && $aliasToId == $path[count($path)-1]) {
+ $class .= ' active';
+ }
+ elseif (in_array($aliasToId, $path)) {
+ $class .= ' alias-parent-active';
+ }
+ }
+
+ if ($item->type == 'separator') {
+ $class .= ' divider';
+ }
+
+ if ($item->deeper) {
+ if ($item->level > 1){
+ $class .= ' dropdown-submenu';
+ } else {
+ $class .= ' deeper dropdown';
+ }
+ }
+
+ if ($item->parent) {
+ $class .= ' parent';
+ }
+
+ if (!empty($class)) {
+ $class = ' class="'.trim($class) .'"';
+ }
+
+ echo '';
+
+ // Render the menu item.
+ switch ($item->type) :
+ case 'separator':
+ case 'url':
+ case 'component':
+ case 'heading':
+ require JModuleHelper::getLayoutPath('mod_menu', 'default_'.$item->type);
+ break;
+
+ default:
+ require JModuleHelper::getLayoutPath('mod_menu', 'default_url');
+ break;
+ endswitch;
+
+ // The next item is deeper.
+ if ($item->deeper) {
+ echo ' ';
+ echo str_repeat(' ', $item->level_diff);
+ }
+ // The next item is on the same level.
+ else {
+ echo '';
+ }
+ endforeach;
+endif;
+?>
diff --git a/plugins/system/t3/base-bs3/html/mod_menu/default_component.php b/plugins/system/t3/base-bs3/html/mod_menu/default_component.php
new file mode 100644
index 0000000..327c20f
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_menu/default_component.php
@@ -0,0 +1,49 @@
+anchor_css ? $item->anchor_css : '';
+$title = $item->anchor_title ? 'title="'.$item->anchor_title.'" ' : '';
+$dropdown = '';
+$caret = '';
+
+if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+}
+
+if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+}
+
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+} else {
+ $linktype = $item->title;
+}
+
+switch ($item->browserNav) :
+ default:
+ case 0:
+?>
href="flink; ?>" > href="flink; ?>" target="_blank" > href="flink; ?>" onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;" >
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/mod_menu/default_separator.php b/plugins/system/t3/base-bs3/html/mod_menu/default_separator.php
new file mode 100644
index 0000000..16d3b2d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_menu/default_separator.php
@@ -0,0 +1,23 @@
+anchor_title ? ' title="'.$item->anchor_title.'" ' : '';
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+}
+else {
+ $linktype = $item->title;
+}
+
+?>
>
diff --git a/plugins/system/t3/base-bs3/html/mod_menu/default_url.php b/plugins/system/t3/base-bs3/html/mod_menu/default_url.php
new file mode 100644
index 0000000..709c8ea
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_menu/default_url.php
@@ -0,0 +1,53 @@
+anchor_css ? $item->anchor_css : '';
+$title = $item->anchor_title ? 'title="'.$item->anchor_title.'" ' : '';
+$dropdown = '';
+$caret = '';
+
+if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+}
+
+if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+}
+
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+} else {
+ $linktype = $item->title;
+}
+$flink = $item->flink;
+$flink = JFilterOutput::ampReplace(htmlspecialchars($flink));
+
+switch ($item->browserNav) :
+ default:
+ case 0:
+?>
+
href="" >
+
href="" target="_blank" > get('window_open');
+ ?>
href="" onclick="window.open(this.href,'targetWindow','');return false;" >
diff --git a/plugins/system/t3/base-bs3/html/mod_search/default.php b/plugins/system/t3/base-bs3/html/mod_search/default.php
new file mode 100644
index 0000000..0d01943
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_search/default.php
@@ -0,0 +1,52 @@
+
+
+
+
diff --git a/plugins/system/t3/base-bs3/html/mod_search/index.html b/plugins/system/t3/base-bs3/html/mod_search/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/mod_search/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/html/modules.php b/plugins/system/t3/base-bs3/html/modules.php
new file mode 100644
index 0000000..a1e318d
--- /dev/null
+++ b/plugins/system/t3/base-bs3/html/modules.php
@@ -0,0 +1,199 @@
+
+ *
+ * This gives template designers ultimate control over how modules are rendered.
+ *
+ * NOTICE: All chrome wrapping methods should be named: modChrome_{STYLE} and take the same
+ * three arguments.
+ */
+
+
+/*
+ * Default Module Chrome that has sematic markup and has best SEO support
+ */
+function modChrome_T3Xhtml($module, &$params, &$attribs)
+{
+ $badge = preg_match ('/badge/', $params->get('moduleclass_sfx'))? '
' : '';
+ $moduleTag = htmlspecialchars($params->get('module_tag', 'div'));
+ $headerTag = htmlspecialchars($params->get('header_tag', 'h3'));
+ $headerClass = $params->get('header_class');
+ $bootstrapSize = $params->get('bootstrap_size');
+ $moduleClass = !empty($bootstrapSize) ? ' col-sm-' . (int) $bootstrapSize . '' : '';
+ $moduleClassSfx = htmlspecialchars($params->get('moduleclass_sfx'));
+
+ if (!empty ($module->content)) {
+ $html = "<{$moduleTag} class=\"t3-module module{$moduleClassSfx} {$moduleClass}\" id=\"Mod{$module->id}\">" .
+ "
" . $badge;
+
+ if ($module->showtitle != 0) {
+ $html .= "<{$headerTag} class=\"module-title {$headerClass}\">
{$module->title} {$headerTag}>";
+ }
+
+ $html .= "
{$module->content}
{$moduleTag}>";
+
+ echo $html;
+ }
+}
+
+
+function modChrome_t3tabs($module, $params, $attribs)
+{
+ $area = isset($attribs['id']) ? (int) $attribs['id'] :'1';
+ $area = 'area-'.$area;
+
+ static $modulecount;
+ static $modules;
+
+ if ($modulecount < 1) {
+ $modulecount = count(JModuleHelper::getModules($attribs['name']));
+ $modules = array();
+ }
+
+ if ($modulecount == 1) {
+ $temp = new stdClass;
+ $temp->content = $module->content;
+ $temp->title = $module->title;
+ $temp->params = $module->params;
+ $temp->id = $module->id;
+ $modules[] = $temp;
+
+ // list of moduletitles
+ echo '
';
+ echo '
';
+ $counter = 0;
+ // modulecontent
+ foreach($modules as $rendermodule) {
+ $counter ++;
+
+ echo '
';
+ echo $rendermodule->content;
+
+ echo '
';
+ }
+ echo '
';
+ echo '';
+ $modulecount--;
+
+ } else {
+ $temp = new stdClass;
+ $temp->content = $module->content;
+ $temp->params = $module->params;
+ $temp->title = $module->title;
+ $temp->id = $module->id;
+ $modules[] = $temp;
+ $modulecount--;
+ }
+}
+
+
+function modChrome_t3slider($module, &$params, &$attribs)
+{
+ $badge = preg_match ('/badge/', $params->get('moduleclass_sfx'))?"
\n":"";
+ $headerLevel = isset($attribs['headerLevel']) ? (int) $attribs['headerLevel'] : 3;
+ ?>
+
+
+ >title; ?> >
+
+
+
content; ?>
+
+
+
+ content)) : ?>
+
+
+
+ get('moduleclass_sfx'))?"":"";
+ $headerLevel = isset($attribs['headerLevel']) ? (int) $attribs['headerLevel'] : 3;
+
+ if (!empty ($module->content)) : ?>
+
+ base : integer
+ * $item->link : string
+ * $item->text : string
+ *
+ * pagination_item_inactive
+ * Input variable $item is an object with fields:
+ * $item->base : integer
+ * $item->link : string
+ * $item->text : string
+ *
+ * This gives template designers ultimate control over how pagination is rendered.
+ *
+ * NOTE: If you override pagination_item_active OR pagination_item_inactive you MUST override them both
+ */
+
+function pagination_list_footer($list)
+{
+ $html = "";
+
+ return $html;
+}
+
+function pagination_list_render($list)
+{
+ // Initialize variables
+ $html = "";
+ return $html;
+
+}
+function pagination_item_active(&$item)
+{
+ $app = JFactory::getApplication();
+ if ($app->isAdmin())
+ {
+ if ($item->base > 0)
+ {
+ return "
text . "\" onclick=\"document.adminForm." . $this->prefix . "limitstart.value=" . $item->base
+ . "; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ else
+ {
+ return "
text . "\" onclick=\"document.adminForm." . $this->prefix
+ . "limitstart.value=0; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ }
+ else
+ {
+ return "
text . "\" href=\"" . $item->link . "\">" . $item->text . " ";
+ }
+}
+
+function pagination_item_inactive(&$item) {
+ $cls = (int)$item->text > 0 ? 'active': 'disabled';
+ return "
".$item->text." ";
+}
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/imgs/blank.gif b/plugins/system/t3/base-bs3/imgs/blank.gif
new file mode 100644
index 0000000..b8ac83f
Binary files /dev/null and b/plugins/system/t3/base-bs3/imgs/blank.gif differ
diff --git a/plugins/system/t3/base-bs3/index.html b/plugins/system/t3/base-bs3/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base-bs3/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/index.php b/plugins/system/t3/base-bs3/index.php
new file mode 100644
index 0000000..fe1c5d3
--- /dev/null
+++ b/plugins/system/t3/base-bs3/index.php
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/js/cssjanus.js b/plugins/system/t3/base-bs3/js/cssjanus.js
new file mode 100644
index 0000000..4dd05fc
--- /dev/null
+++ b/plugins/system/t3/base-bs3/js/cssjanus.js
@@ -0,0 +1,277 @@
+/**
+ * Creates a CSSJanus object.
+ *
+ * CSSJanus transforms CSS rules with horizontal relevance so that a left-to-right stylesheet can
+ * become a right-to-left stylesheet automatically. Processing can be bypassed for an entire rule
+ * or a single property by adding a / * @noflip * / comment above the rule or property.
+ *
+ * @author "Trevor Parscal"
+ * @author "Roan Kattouw"
+ * @author "Lindsey Simon"
+ * @author "Roozbeh Pournader"
+ * @author "Bryon Engelhardt"
+ *
+ * @class
+ * @constructor
+ * @param {RegExp} regex Regular expression whose matches to replace by a token
+ * @param {String} token Placeholder text
+ */
+function CSSJanus() {
+
+ /* Private Members */
+
+ var prepared = false,
+ // Tokens
+ temporaryToken = '`TMP`',
+ noFlipSingleToken = '`NOFLIP_SINGLE`',
+ noFlipClassToken = '`NOFLIP_CLASS`',
+ commentToken = '`COMMENT`',
+ // Patterns
+ nonAsciiPattern = '[^\\u0020-\\u007e]',
+ unicodePattern = '(?:(?:\\[0-9a-f]{1,6})(?:\\r\\n|\\s)?)',
+ numPattern = '(?:[0-9]*\\.[0-9]+|[0-9]+)',
+ unitPattern = '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)',
+ directionPattern = 'direction\\s*:\\s*',
+ urlSpecialCharsPattern = '[!#$%&*-~]',
+ validAfterUriCharsPattern = '[\'"]?\\s*',
+ nonLetterPattern = '(^|[^a-zA-Z])',
+ charsWithinSelectorPattern = '[^\\}]*?',
+ noFlipPattern = '\\/\\*\\s*@noflip\\s*\\*\\/',
+ commentPattern = '\\/\\*[^*]*\\*+([^\\/*][^*]*\\*+)*\\/',
+ escapePattern = '(?:' + unicodePattern + '|\\\\[^\\r\\n\\f0-9a-f])',
+ nmstartPattern = '(?:[_a-z]|' + nonAsciiPattern + '|' + escapePattern + ')',
+ nmcharPattern = '(?:[_a-z0-9-]|' + nonAsciiPattern + '|' + escapePattern + ')',
+ identPattern = '-?' + nmstartPattern + nmcharPattern + '*',
+ quantPattern = numPattern + '(?:\\s*' + unitPattern + '|' + identPattern + ')?',
+ signedQuantPattern = '((?:-?' + quantPattern + ')|(?:inherit|auto))',
+ fourNotationQuantPropsPattern = '((?:margin|padding|border-width)\\s*:\\s*)',
+ fourNotationColorPropsPattern = '(-color\\s*:\\s*)',
+ colorPattern = '(#?' + nmcharPattern + '+)',
+ urlCharsPattern = '(?:' + urlSpecialCharsPattern + '|' + nonAsciiPattern + '|' + escapePattern + ')*',
+ lookAheadNotOpenBracePattern = '(?!(' + nmcharPattern + '|\\r?\\n|\\s|#|\\:|\\.|\\,|\\+|>)*?{)',
+ lookAheadNotClosingParenPattern = '(?!' + urlCharsPattern + '?' + validAfterUriCharsPattern + '\\))',
+ lookAheadForClosingParenPattern = '(?=' + urlCharsPattern + '?' + validAfterUriCharsPattern + '\\))',
+ // Regular expressions
+ temporaryTokenRegExp = new RegExp( '`TMP`', 'g' ),
+ commentRegExp = new RegExp( commentPattern, 'gi' ),
+ noFlipSingleRegExp = new RegExp( '(' + noFlipPattern + lookAheadNotOpenBracePattern + '[^;}]+;?)', 'gi' ),
+ noFlipClassRegExp = new RegExp( '(' + noFlipPattern + charsWithinSelectorPattern + '})', 'gi' ),
+ directionLtrRegExp = new RegExp( '(' + directionPattern + ')ltr', 'gi' ),
+ directionRtlRegExp = new RegExp( '(' + directionPattern + ')rtl', 'gi' ),
+ leftRegExp = new RegExp( nonLetterPattern + '(left)' + lookAheadNotClosingParenPattern + lookAheadNotOpenBracePattern, 'gi' ),
+ rightRegExp = new RegExp( nonLetterPattern + '(right)' + lookAheadNotClosingParenPattern + lookAheadNotOpenBracePattern, 'gi' ),
+ leftInUrlRegExp = new RegExp( nonLetterPattern + '(left)' + lookAheadForClosingParenPattern, 'gi' ),
+ rightInUrlRegExp = new RegExp( nonLetterPattern + '(right)' + lookAheadForClosingParenPattern, 'gi' ),
+ ltrInUrlRegExp = new RegExp( nonLetterPattern + '(ltr)' + lookAheadForClosingParenPattern, 'gi' ),
+ rtlInUrlRegExp = new RegExp( nonLetterPattern + '(rtl)' + lookAheadForClosingParenPattern, 'gi' ),
+ cursorEastRegExp = new RegExp( nonLetterPattern + '([ns]?)e-resize', 'gi' ),
+ cursorWestRegExp = new RegExp( nonLetterPattern + '([ns]?)w-resize', 'gi' ),
+ fourNotationQuantRegExp = new RegExp( fourNotationQuantPropsPattern + signedQuantPattern + '(\\s+)' + signedQuantPattern + '(\\s+)' + signedQuantPattern + '(\\s+)' + signedQuantPattern, 'gi' ),
+ fourNotationColorRegExp = new RegExp( fourNotationColorPropsPattern + colorPattern + '(\\s+)' + colorPattern + '(\\s+)' + colorPattern + '(\\s+)' + colorPattern, 'gi' ),
+ bgHorizontalPercentageRegExp = new RegExp( '(background(?:-position)?\\s*:\\s*[^%]*?)(-?' + numPattern + ')(%\\s*(?:' + quantPattern + '|' + identPattern + '))', 'gi' ),
+ bgHorizontalPercentageXRegExp = new RegExp( '(background-position-x\\s*:\\s*)(-?' + numPattern + ')(%)', 'gi' ),
+ borderRadiusRegExp = new RegExp( '(border-radius\\s*:\\s*)([^;]*)', 'gi' );
+
+ /* Private Methods */
+
+ /**
+ * Inverts the horizontal value of a background position property.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched property
+ * @param {String} pre Text before value
+ * @param {String} value Horizontal value
+ * @param {String} post Text after value
+ * @return {String} Inverted property
+ */
+ function calculateNewBackgroundPosition( match, pre, value, post ) {
+ return pre + ( 100 - Number( value ) ) + post;
+ }
+
+ /**
+ * Inverts the horizontal value of a background position property.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched property
+ * @param {String} pre Text before value
+ * @param {String} value Horizontal value
+ * @param {String} post Text after value
+ * @return {String} Inverted property
+ */
+ function calculateNewBorderRadius( match, pre, values ) {
+ values = values.split( /\s+/g );
+ switch ( values.length ) {
+ case 4:
+ values = [values[1], values[0], values[3], values[2]];
+ break;
+ case 3:
+ values = [values[1], values[0], values[2]];
+ break;
+ case 2:
+ values = [values[1], values[0]];
+ break;
+ }
+ return pre + values.join( ' ' );
+ }
+
+ /* Methods */
+
+ return {
+ /**
+ * Transform a left-to-right stylesheet to right-to-left.
+ *
+ * @method
+ * @param {String} css Stylesheet to transform
+ * @param {Boolean} swapLtrRtlInUrl Swap 'ltr' and 'rtl' in URLs
+ * @param {Boolean} swapLeftRightInUrl Swap 'left' and 'right' in URLs
+ * @return {String} Transformed stylesheet
+ */
+ 'transform': function( css, swapLtrRtlInUrl, swapLeftRightInUrl ) {
+ // Tokenizers
+ var noFlipSingleTokenizer = new Tokenizer( noFlipSingleRegExp, noFlipSingleToken ),
+ noFlipClassTokenizer = new Tokenizer( noFlipClassRegExp, noFlipClassToken ),
+ commentTokenizer = new Tokenizer( commentRegExp, commentToken );
+
+ // Tokenize
+ css = commentTokenizer.tokenize(
+ noFlipClassTokenizer.tokenize(
+ noFlipSingleTokenizer.tokenize(
+ // We wrap tokens in ` , not ~ like the original implementation does.
+ // This was done because ` is not a legal character in CSS and can only
+ // occur in URLs, where we escape it to %60 before inserting our tokens.
+ css.replace( '`', '%60' )
+ )
+ )
+ );
+
+ // Transform URLs
+ if ( swapLtrRtlInUrl ) {
+ // Replace 'ltr' with 'rtl' and vice versa in background URLs
+ css = css
+ .replace( ltrInUrlRegExp, '$1' + temporaryToken )
+ .replace( rtlInUrlRegExp, '$1ltr' )
+ .replace( temporaryTokenRegExp, 'rtl' );
+ }
+ if ( swapLeftRightInUrl ) {
+ // Replace 'left' with 'right' and vice versa in background URLs
+ css = css
+ .replace( leftInUrlRegExp, '$1' + temporaryToken )
+ .replace( rightInUrlRegExp, '$1left' )
+ .replace( temporaryTokenRegExp, 'right' );
+ }
+
+ // Transform rules
+ css = css
+ // Replace direction: ltr; with direction: rtl; and vice versa.
+ .replace( directionLtrRegExp, '$1' + temporaryToken )
+ .replace( directionRtlRegExp, '$1ltr' )
+ .replace( temporaryTokenRegExp, 'rtl' )
+ // Flip rules like left: , padding-right: , etc.
+ .replace( leftRegExp, '$1' + temporaryToken )
+ .replace( rightRegExp, '$1left' )
+ .replace( temporaryTokenRegExp, 'right' )
+ // Flip East and West in rules like cursor: nw-resize;
+ .replace( cursorEastRegExp, '$1$2' + temporaryToken )
+ .replace( cursorWestRegExp, '$1$2e-resize' )
+ .replace( temporaryTokenRegExp, 'w-resize' )
+ // Border radius
+ .replace( borderRadiusRegExp, calculateNewBorderRadius )
+ // Swap the second and fourth parts in four-part notation rules
+ // like padding: 1px 2px 3px 4px;
+ .replace( fourNotationQuantRegExp, '$1$2$3$8$5$6$7$4' )
+ .replace( fourNotationColorRegExp, '$1$2$3$8$5$6$7$4' )
+ // Flip horizontal background percentages
+ .replace( bgHorizontalPercentageRegExp, calculateNewBackgroundPosition )
+ .replace( bgHorizontalPercentageXRegExp, calculateNewBackgroundPosition );
+
+ // Detokenize
+ css = noFlipSingleTokenizer.detokenize(
+ noFlipClassTokenizer.detokenize(
+ commentTokenizer.detokenize( css )
+ )
+ );
+
+ return css;
+ }
+ };
+}
+
+/**
+ * Creates a tokenizer object.
+ *
+ * This utility class is used by CSSJanus to protect strings by replacing them temporarily with
+ * tokens and later transforming them back.
+ *
+ * @author Trevor Parscal
+ * @author Roan Kattouw
+ *
+ * @class
+ * @constructor
+ * @param {RegExp} regex Regular expression whose matches to replace by a token
+ * @param {String} token Placeholder text
+ */
+Tokenizer = function( regex, token ) {
+
+ /* Private Members */
+
+ var matches = [],
+ index = 0;
+
+ /* Private Methods */
+
+ /**
+ * Adds a match.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched string
+ * @returns {String} Token to leave in the matched string's place
+ */
+ function tokenizeCallback( match ) {
+ matches.push( match );
+ return token;
+ }
+
+ /**
+ * Gets a match.
+ *
+ * @private
+ * @function
+ * @param {String} token Matched token
+ * @returns {String} Original matched string to restore
+ */
+ function detokenizeCallback( token ) {
+ return matches[index++];
+ }
+
+ /* Methods */
+
+ return {
+ /**
+ * Replace matching strings with tokens.
+ *
+ * @method
+ * @param {String} str String to tokenize
+ * @return {String} Tokenized string
+ */
+ 'tokenize': function( str ) {
+ return str.replace( regex, tokenizeCallback );
+ },
+ /**
+ * Restores tokens to their original values.
+ *
+ * @method
+ * @param {String} str String previously run through tokenize()
+ * @return {String} Original string
+ */
+ 'detokenize': function( str ) {
+ return str.replace( new RegExp( '(' + token + ')', 'g' ), detokenizeCallback );
+ }
+ };
+};
+
+/* Initialization */
+
+var cssjanus = new CSSJanus();
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/js/frontend-edit.js b/plugins/system/t3/base-bs3/js/frontend-edit.js
new file mode 100644
index 0000000..996262b
--- /dev/null
+++ b/plugins/system/t3/base-bs3/js/frontend-edit.js
@@ -0,0 +1,51 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+
+!function($){
+
+ $(document).ready(function(){
+
+ //frontend edit radio on/off - auto convert on-off radio if applicable
+ $('fieldset.radio').filter(function(){
+
+ return $(this).find('input').length == 2 && $(this).find('input').filter(function(){
+ return $.inArray(this.value + '', ['0', '1']) !== -1;
+ }).length == 2;
+
+ }).addClass('t3onoff').removeClass('btn-group');
+
+ //add class on/off
+ $('fieldset.t3onoff').find('label').addClass(function(){
+ return $(this).hasClass('off') || $(this).prev('input').val() == '0' ? 'off' : 'on'
+ });
+
+ //listen to all
+ $('fieldset.radio').find('label').unbind('click').click(function() {
+ var label = $(this),
+ input = $('#' + label.attr('for'));
+
+ if (!input.prop('checked')){
+ label.addClass('active').siblings().removeClass('active');
+
+ input.prop('checked', true).trigger('change');
+ }
+ });
+
+ //initial state
+ $('.radio input[checked=checked]').each(function(){
+ $('label[for=' + $(this).attr('id') + ']').addClass('active');
+ });
+
+ });
+
+}(jQuery);
\ No newline at end of file
diff --git a/plugins/system/t3/base-bs3/js/jquery-1.8.3.js b/plugins/system/t3/base-bs3/js/jquery-1.8.3.js
new file mode 100644
index 0000000..8c24ffc
--- /dev/null
+++ b/plugins/system/t3/base-bs3/js/jquery-1.8.3.js
@@ -0,0 +1,9472 @@
+/*!
+ * jQuery JavaScript Library v1.8.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
+ */
+(function( window, undefined ) {
+var
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+ location = window.location,
+ navigator = window.navigator,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // Save a reference to some core methods
+ core_push = Array.prototype.push,
+ core_slice = Array.prototype.slice,
+ core_indexOf = Array.prototype.indexOf,
+ core_toString = Object.prototype.toString,
+ core_hasOwn = Object.prototype.hasOwnProperty,
+ core_trim = String.prototype.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
+
+ // Used for detecting and trimming whitespace
+ core_rnotwhite = /\S/,
+ core_rspace = /\s+/,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return ( letter + "" ).toUpperCase();
+ },
+
+ // The ready event handler and self cleanup method
+ DOMContentLoaded = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ } else if ( document.readyState === "complete" ) {
+ // we're here because readyState === "complete" in oldIE
+ // which is good enough for us to call the dom ready!
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ },
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = ( context && context.nodeType ? context.ownerDocument || context : document );
+
+ // scripts is true for back-compat
+ selector = jQuery.parseHTML( match[1], doc, true );
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ this.attr.call( selector, context, true );
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.8.3",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ i = +i;
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ),
+ "slice", core_slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ core_toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // scripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, scripts ) {
+ var parsed;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ scripts = context;
+ context = 0;
+ }
+ context = context || document;
+
+ // Single tag
+ if ( (parsed = rsingleTag.exec( data )) ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
+ return jQuery.merge( [],
+ (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
+ },
+
+ parseJSON: function( data ) {
+ if ( !data || typeof data !== "string") {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+
+ }
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && core_rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var name,
+ i = 0,
+ length = obj.length,
+ isObj = length === undefined || jQuery.isFunction( obj );
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in obj ) {
+ if ( callback.apply( obj[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( obj[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in obj ) {
+ if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var type,
+ ret = results || [];
+
+ if ( arr != null ) {
+ // The window, strings (and functions) also have 'length'
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ type = jQuery.type( arr );
+
+ if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
+ core_push.call( ret, arr );
+ } else {
+ jQuery.merge( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value, key,
+ ret = [],
+ i = 0,
+ length = elems.length,
+ // jquery objects are treated as arrays
+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( key in elems ) {
+ value = callback( elems[ key ], key, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+ var exec,
+ bulk = key == null,
+ i = 0,
+ length = elems.length;
+
+ // Sets many values
+ if ( key && typeof key === "object" ) {
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+ }
+ chainable = 1;
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = pass === undefined && jQuery.isFunction( value );
+
+ if ( bulk ) {
+ // Bulk operations only iterate when executing function values
+ if ( exec ) {
+ exec = fn;
+ fn = function( elem, key, value ) {
+ return exec.call( jQuery( elem ), value );
+ };
+
+ // Otherwise they run against the entire set
+ } else {
+ fn.call( elems, value );
+ fn = null;
+ }
+ }
+
+ if ( fn ) {
+ for (; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+ }
+
+ chainable = 1;
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready, 1 );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.split( core_rspace ), function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ return jQuery.inArray( fn, list ) > -1;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( list && ( !fired || stack ) ) {
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
+ function() {
+ var returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ }
+ } :
+ newDefer[ action ]
+ );
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ] = list.fire
+ deferred[ tuple[0] ] = list.fire;
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function() {
+
+ var support,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ fragment,
+ eventName,
+ i,
+ isSupported,
+ clickFn,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " a ";
+
+ // Support tests won't run in some limited or non-browser environments
+ all = div.getElementsByTagName("*");
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !all || !a || !all.length ) {
+ return {};
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+ support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.5/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: ( input.value === "on" ),
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // Tests for enctype support on a form (#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
+
+ // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+ boxModel: ( document.compatMode === "CSS1Compat" ),
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ boxSizingReliable: true,
+ pixelPosition: false
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent( "onclick", clickFn = function() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ support.noCloneEvent = false;
+ });
+ div.cloneNode( true ).fireEvent("onclick");
+ div.detachEvent( "onclick", clickFn );
+ }
+
+ // Check if a radio maintains its value
+ // after being appended to the DOM
+ input = document.createElement("input");
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ input.setAttribute( "checked", "checked" );
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.lastChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ fragment.removeChild( input );
+ fragment.appendChild( div );
+
+ // Technique from Juriy Zaytsev
+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for ( i in {
+ submit: true,
+ change: true,
+ focusin: true
+ }) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
+ }
+ }
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, div, tds, marginDiv,
+ divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ div.innerHTML = "";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE <= 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+ support.boxSizing = ( div.offsetWidth === 4 );
+ support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+ // NOTE: To any future maintainer, we've window.getComputedStyle
+ // because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = document.createElement("div");
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "
";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ container.style.zoom = 1;
+ }
+
+ // Null elements to avoid leaks in IE
+ body.removeChild( container );
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ fragment.removeChild( div );
+ all = a = select = opt = input = fragment = div = null;
+
+ return support;
+})();
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+ cache: {},
+
+ deletedIds: [],
+
+ // Remove at next major release (1.9/2.0)
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( !name.indexOf( "data-" ) ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ parts = key.split( ".", 2 );
+ parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ }
+
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
+
+ self.triggerHandler( "setData" + part, parts );
+ jQuery.data( this, key, value );
+ self.triggerHandler( "changeData" + part, parts );
+ });
+ }, null, value, arguments.length > 1, null, false );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery.removeData( elem, type + "queue", true );
+ jQuery.removeData( elem, key, true );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook, fixSpecified,
+ rclass = /[\t\r\n]/g,
+ rreturn = /\r/g,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea|)$/i,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classNames, i, l, elem,
+ setClass, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ classNames = value.split( core_rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className && classNames.length === 1 ) {
+ elem.className = value;
+
+ } else {
+ setClass = " " + elem.className + " ";
+
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
+ setClass += classNames[ c ] + " ";
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var removes, className, elem, c, cl, i, l;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call(this, j, this.className) );
+ });
+ }
+ if ( (value && typeof value === "string") || value === undefined ) {
+ removes = ( value || "" ).split( core_rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+ if ( elem.nodeType === 1 && elem.className ) {
+
+ className = (" " + elem.className + " ").replace( rclass, " " );
+
+ // loop over each item in the removal list
+ for ( c = 0, cl = removes.length; c < cl; c++ ) {
+ // Remove until there is nothing to remove,
+ while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
+ className = className.replace( " " + removes[ c ] + " " , " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( className ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( core_rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val,
+ self = jQuery(this);
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
+ attrFn: {},
+
+ attr: function( elem, name, value, pass ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+
+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ ret = elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret === null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, isBool,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+
+ attrNames = value.split( core_rspace );
+
+ for ( ; i < attrNames.length; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
+ elem.removeAttribute( getSetAttribute ? name : propName );
+
+ // Set corresponding property to false for boolean attributes
+ if ( isBool && propName in elem ) {
+ elem[ propName ] = false;
+ }
+ }
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to it's default in case type is set after value
+ // This is for element creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ },
+ // Use the value property for back compat
+ // Use the nodeHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.set( elem, value, name );
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true,
+ coords: true
+ };
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
+ ret.value :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
+ }
+ return ( ret.value = value + "" );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret === null ? undefined : ret;
+ }
+ });
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Normalize to lowercase since IE uppercases css property names
+ return elem.style.cssText.toLowerCase() || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+var rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, handlers, special;
+
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+ eventHandle = elemData.handle;
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
+
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var t, tns, type, origType, namespaces, origCount,
+ j, events, special, eventType, handleObj,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
+
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, "events", true );
+ }
+ },
+
+ // Events that are safe to short-circuit if no handlers are attached.
+ // Native DOM events should not be added, they may have inline handlers.
+ customEvent: {
+ "getData": true,
+ "setData": true,
+ "changeData": true
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
+ // Event object or event type
+ var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
+ type = event.type || event,
+ namespaces = [];
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "!" ) >= 0 ) {
+ // Exclusive events trigger only for the exact event (no namespaces)
+ type = type.slice(0, -1);
+ exclusive = true;
+ }
+
+ if ( type.indexOf( "." ) >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+
+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+ // No jQuery handlers for this event type, and it can't have inline handlers
+ return;
+ }
+
+ // Caller can pass in an Event, Object, or just an event type string
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ new jQuery.Event( type, event ) :
+ // Just the event type (string)
+ new jQuery.Event( type );
+
+ event.type = type;
+ event.isTrigger = true;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+ // Handle a global trigger
+ if ( !elem ) {
+
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+ }
+ }
+ return;
+ }
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data != null ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ for ( old = elem; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old === (elem.ownerDocument || document) ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event || window.event );
+
+ var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
+ handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = core_slice.call( arguments ),
+ run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
+ handlerQueue = [];
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.disabled !== true || event.type !== "click" ) {
+ selMatch = {};
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = jQuery.Event( originalEvent );
+
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Target should not be a text node (#504, Safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === "undefined" ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "_submit_attached" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "_submit_attached", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "_change_attached", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) { // && selector != null
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ return jQuery.event.trigger( type, data, this[0], true );
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var cachedruns,
+ assertGetIdNotName,
+ Expr,
+ getText,
+ isXML,
+ contains,
+ compile,
+ sortOrder,
+ hasDuplicate,
+ outermostContext,
+
+ baseHasDuplicate = true,
+ strundefined = "undefined",
+
+ expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
+
+ Token = String,
+ document = window.document,
+ docElem = document.documentElement,
+ dirruns = 0,
+ done = 0,
+ pop = [].pop,
+ push = [].push,
+ slice = [].slice,
+ // Use a stripped-down indexOf if a native one is unavailable
+ indexOf = [].indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ // Augment a function for special use by Sizzle
+ markFunction = function( fn, value ) {
+ fn[ expando ] = value == null || value;
+ return fn;
+ },
+
+ createCache = function() {
+ var cache = {},
+ keys = [];
+
+ return markFunction(function( key, value ) {
+ // Only keep the most recent entries
+ if ( keys.push( key ) > Expr.cacheLength ) {
+ delete cache[ keys.shift() ];
+ }
+
+ // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157)
+ return (cache[ key + " " ] = value);
+ }, cache );
+ },
+
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+
+ // Regex
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ operators = "([*^$|!~]?=)",
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments not in parens/brackets,
+ // then attribute selectors and non-pseudos (denoted by :),
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
+
+ // For matchExpr.POS and matchExpr.needsContext
+ pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+ rpseudo = new RegExp( pseudos ),
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
+
+ rnot = /^:not/,
+ rsibling = /[\x20\t\r\n\f]*[+~]/,
+ rendsWithNot = /:not\($/,
+
+ rheader = /h\d/i,
+ rinputs = /input|select|textarea|button/i,
+
+ rbackslash = /\\(?!\\)/g,
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "POS": new RegExp( pos, "i" ),
+ "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ // For use in libraries implementing .is()
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
+ },
+
+ // Support
+
+ // Used for testing something on an element
+ assert = function( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // release memory in IE
+ div = null;
+ }
+ },
+
+ // Check if getElementsByTagName("*") returns only elements
+ assertTagNameNoComments = assert(function( div ) {
+ div.appendChild( document.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ }),
+
+ // Check if getAttribute returns normalized href attributes
+ assertHrefNotNormalized = assert(function( div ) {
+ div.innerHTML = " ";
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+ div.firstChild.getAttribute("href") === "#";
+ }),
+
+ // Check if attributes should be retrieved by attribute nodes
+ assertAttributes = assert(function( div ) {
+ div.innerHTML = " ";
+ var type = typeof div.lastChild.getAttribute("multiple");
+ // IE8 returns a string for some attributes even when not present
+ return type !== "boolean" && type !== "string";
+ }),
+
+ // Check if getElementsByClassName can be trusted
+ assertUsableClassName = assert(function( div ) {
+ // Opera can't find a second classname (in 9.6)
+ div.innerHTML = "
";
+ if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+ return false;
+ }
+
+ // Safari 3.2 caches class attributes and doesn't catch changes
+ div.lastChild.className = "e";
+ return div.getElementsByClassName("e").length === 2;
+ }),
+
+ // Check if getElementById returns elements by name
+ // Check if getElementsByName privileges form controls or returns elements by ID
+ assertUsableName = assert(function( div ) {
+ // Inject content
+ div.id = expando + 0;
+ div.innerHTML = "
";
+ docElem.insertBefore( div, docElem.firstChild );
+
+ // Test
+ var pass = document.getElementsByName &&
+ // buggy browsers will return fewer than the correct 2
+ document.getElementsByName( expando ).length === 2 +
+ // buggy browsers will return more than the correct 0
+ document.getElementsByName( expando + 0 ).length;
+ assertGetIdNotName = !document.getElementById( expando );
+
+ // Cleanup
+ docElem.removeChild( div );
+
+ return pass;
+ });
+
+// If slice is not available, provide a backup
+try {
+ slice.call( docElem.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+ slice = function( i ) {
+ var elem,
+ results = [];
+ for ( ; (elem = this[i]); i++ ) {
+ results.push( elem );
+ }
+ return results;
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+ var match, elem, xml, m,
+ nodeType = context.nodeType;
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( nodeType !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ xml = isXML( context );
+
+ if ( !xml && !seed ) {
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
+ push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+ return results;
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
+}
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+};
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ }
+ return ret;
+};
+
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Element contains another
+contains = Sizzle.contains = docElem.contains ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
+ } :
+ docElem.compareDocumentPosition ?
+ function( a, b ) {
+ return b && !!( a.compareDocumentPosition( b ) & 16 );
+ } :
+ function( a, b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+Sizzle.attr = function( elem, name ) {
+ var val,
+ xml = isXML( elem );
+
+ if ( !xml ) {
+ name = name.toLowerCase();
+ }
+ if ( (val = Expr.attrHandle[ name ]) ) {
+ return val( elem );
+ }
+ if ( xml || assertAttributes ) {
+ return elem.getAttribute( name );
+ }
+ val = elem.getAttributeNode( name );
+ return val ?
+ typeof elem[ name ] === "boolean" ?
+ elem[ name ] ? name : null :
+ val.specified ? val.value : null :
+ null;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ // IE6/7 return a modified href
+ attrHandle: assertHrefNotNormalized ?
+ {} :
+ {
+ "href": function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ },
+ "type": function( elem ) {
+ return elem.getAttribute("type");
+ }
+ },
+
+ find: {
+ "ID": assertGetIdNotName ?
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ } :
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+
+ return m ?
+ m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+ [m] :
+ undefined :
+ [];
+ }
+ },
+
+ "TAG": assertTagNameNoComments ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ var elem,
+ tmp = [],
+ i = 0;
+
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ },
+
+ "NAME": assertUsableName && function( tag, context ) {
+ if ( typeof context.getElementsByName !== strundefined ) {
+ return context.getElementsByName( name );
+ }
+ },
+
+ "CLASS": assertUsableClassName && function( className, context, xml ) {
+ if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
+ return context.getElementsByClassName( className );
+ }
+ }
+ },
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( rbackslash, "" );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 3 xn-component of xn+y argument ([+-]?\d*n|)
+ 4 sign of xn-component
+ 5 x of xn-component
+ 6 sign of y-component
+ 7 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1] === "nth" ) {
+ // nth-child requires argument
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
+ match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var unquoted, excess;
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ if ( match[3] ) {
+ match[2] = match[3];
+ } else if ( (unquoted = match[4]) ) {
+ // Only check arguments that contain a pseudo
+ if ( rpseudo.test(unquoted) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ unquoted = unquoted.slice( 0, excess );
+ match[0] = match[0].slice( 0, excess );
+ }
+ match[2] = unquoted;
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+ "ID": assertGetIdNotName ?
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ return elem.getAttribute("id") === id;
+ };
+ } :
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === id;
+ };
+ },
+
+ "TAG": function( nodeName ) {
+ if ( nodeName === "*" ) {
+ return function() { return true; };
+ }
+ nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
+
+ return function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ expando ][ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem, context ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.substr( result.length - check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, argument, first, last ) {
+
+ if ( type === "nth" ) {
+ return function( elem ) {
+ var node, diff,
+ parent = elem.parentNode;
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ if ( parent ) {
+ diff = 0;
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ diff++;
+ if ( elem === node ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset (or cast to NaN), then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ };
+ }
+
+ return function( elem ) {
+ var node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ var nodeType;
+ elem = elem.firstChild;
+ while ( elem ) {
+ if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
+ return false;
+ }
+ elem = elem.nextSibling;
+ }
+ return true;
+ },
+
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "text": function( elem ) {
+ var type, attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ (type = elem.type) === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
+ },
+
+ // Input types
+ "radio": createInputPseudo("radio"),
+ "checkbox": createInputPseudo("checkbox"),
+ "file": createInputPseudo("file"),
+ "password": createInputPseudo("password"),
+ "image": createInputPseudo("image"),
+
+ "submit": createButtonPseudo("submit"),
+ "reset": createButtonPseudo("reset"),
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "focus": function( elem ) {
+ var doc = elem.ownerDocument;
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ "active": function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ },
+
+ // Positional types
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 0; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 1; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+function siblingCheck( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+}
+
+sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
+ a.compareDocumentPosition :
+ a.compareDocumentPosition(b) & 4
+ ) ? -1 : 1;
+ } :
+ function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+// Always assume the presence of duplicates if sort doesn't
+// pass them to our comparison function (as in Google Chrome).
+[0, 0].sort( sortOrder );
+baseHasDuplicate = !hasDuplicate;
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ i = 1,
+ j = 0;
+
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem === results[ i - 1 ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ expando ][ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+
+ // Cast descendant combinators to space
+ matched.type = match[0].replace( rtrim, " " );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+ matched.type = type;
+ matched.matches = match;
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && combinator.dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( !xml ) {
+ var cache,
+ dirkey = dirruns + " " + doneName + " ",
+ cachedkey = dirkey + cachedruns;
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( (cache = elem[ expando ]) === cachedkey ) {
+ return elem.sizset;
+ } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
+ if ( elem.sizset ) {
+ return elem;
+ }
+ } else {
+ elem[ expando ] = cachedkey;
+ if ( matcher( elem, context, xml ) ) {
+ elem.sizset = true;
+ return elem;
+ }
+ elem.sizset = false;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( matcher( elem, context, xml ) ) {
+ return elem;
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && tokens.join("")
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Nested matchers should use non-integer dirruns
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = superMatcher.el;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++superMatcher.el;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ for ( j = 0; (matcher = setMatchers[j]); j++ ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ superMatcher.el = 0;
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ expando ][ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed, xml ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector ),
+ j = match.length;
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ context.nodeType === 9 && !xml &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
+ if ( !context ) {
+ return results;
+ }
+
+ selector = selector.slice( tokens.shift().length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( rbackslash, "" ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context,
+ xml
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && tokens.join("");
+ if ( !selector ) {
+ push.apply( results, slice.call( seed, 0 ) );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ xml,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+if ( document.querySelectorAll ) {
+ (function() {
+ var disconnectedMatch,
+ oldSelect = select,
+ rescape = /'|\\/g,
+ rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+ // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA
+ // A support test would require too much code (would include document ready)
+ rbuggyQSA = [ ":focus" ],
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ // A support test would require too much code (would include document ready)
+ // just skip matchesSelector for :active
+ rbuggyMatches = [ ":active" ],
+ matches = docElem.matchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.webkitMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector;
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explictly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = " ";
+
+ // IE8 - Some boolean attributes are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here (do not put tests after this one)
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Opera 10-12/IE9 - ^= $= *= and empty values
+ // Should not select anything
+ div.innerHTML = "
";
+ if ( div.querySelectorAll("[test^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here (do not put tests after this one)
+ div.innerHTML = " ";
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push(":enabled", ":disabled");
+ }
+ });
+
+ // rbuggyQSA always contains :focus, so no need for a length check
+ rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
+
+ select = function( selector, context, results, seed, xml ) {
+ // Only use querySelectorAll when not filtering,
+ // when this is not xml,
+ // and when no QSA bugs apply
+ if ( !seed && !xml && !rbuggyQSA.test( selector ) ) {
+ var groups, i,
+ old = true,
+ nid = expando,
+ newContext = context,
+ newSelector = context.nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + groups[i].join("");
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results, slice.call( newContext.querySelectorAll(
+ newSelector
+ ), 0 ) );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+
+ return oldSelect( selector, context, results, seed, xml );
+ };
+
+ if ( matches ) {
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ try {
+ matches.call( div, "[test!='']:sizzle" );
+ rbuggyMatches.push( "!=", pseudos );
+ } catch ( e ) {}
+ });
+
+ // rbuggyMatches always contains :active and :focus, so no need for a length check
+ rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
+
+ Sizzle.matchesSelector = function( elem, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ // rbuggyMatches always contains :active, so no need for an existence check
+ if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) {
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+ };
+ }
+ })();
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Back-compat
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ rneedsContext = jQuery.expr.match.needsContext,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i, l, length, n, r, ret,
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return jQuery( selector ).filter(function() {
+ for ( i = 0, l = self.length; i < l; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ });
+ }
+
+ ret = this.pushStack( "", "find", selector );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( n = length; n < ret.length; n++ ) {
+ for ( r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ rneedsContext.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ ret = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+ }
+ cur = cur.parentNode;
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( this.length > 1 && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( elem === qualifier ) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+ });
+}
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = / ]", "i"),
+ rcheckableType = /^(?:checkbox|radio)$/,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*\s*$/g,
+ wrapMap = {
+ option: [ 1, "", " " ],
+ legend: [ 1, "", " " ],
+ thead: [ 1, "" ],
+ tr: [ 2, "" ],
+ td: [ 3, "" ],
+ col: [ 2, "" ],
+ area: [ 1, "", " " ],
+ _default: [ 0, "", "" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+// unless wrapped in a div with non-breaking characters in front of it.
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "X", "
" ];
+}
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( !isDisconnected( this[0] ) ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ }
+
+ if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
+ }
+ },
+
+ after: function() {
+ if ( !isDisconnected( this[0] ) ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ }
+
+ if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1>$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function( value ) {
+ if ( !isDisconnected( this[0] ) ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ }
+
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+
+ // Flatten any nested arrays
+ args = [].concat.apply( [], args );
+
+ var results, first, fragment, iNoClone,
+ i = 0,
+ value = args[0],
+ scripts = [],
+ l = this.length;
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call( this, i, table ? self.html() : undefined );
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ results = jQuery.buildFragment( args, this, scripts );
+ fragment = results.fragment;
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ // Fragments from the fragment cache must always be cloned and never used in place.
+ for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
+ callback.call(
+ table && jQuery.nodeName( this[i], "table" ) ?
+ findOrAppend( this[i], "tbody" ) :
+ this[i],
+ i === iNoClone ?
+ fragment :
+ jQuery.clone( fragment, true, true )
+ );
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ if ( jQuery.ajax ) {
+ jQuery.ajax({
+ url: elem.src,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ } else {
+ jQuery.error("no ajax");
+ }
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
+ }
+ }
+
+ return this;
+ }
+});
+
+function findOrAppend( elem, tag ) {
+ return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ if ( nodeName === "object" ) {
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, context, scripts ) {
+ var fragment, cacheable, cachehit,
+ first = args[ 0 ];
+
+ // Set context from what may come in as undefined or a jQuery collection or a node
+ // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
+ // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put or elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+ // Mark cacheable and look for a hit
+ cacheable = true;
+ fragment = jQuery.fragments[ first ];
+ cachehit = fragment !== undefined;
+ }
+
+ if ( !fragment ) {
+ fragment = context.createDocumentFragment();
+ jQuery.clean( args, context, fragment, scripts );
+
+ // Update the cache, but only store false
+ // unless this is a second parsing of the same content
+ if ( cacheable ) {
+ jQuery.fragments[ first ] = cachehit && fragment;
+ }
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ l = insert.length,
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+ } else {
+ for ( ; i < l; i++ ) {
+ elems = ( i > 0 ? this.clone(true) : this ).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var srcElements,
+ destElements,
+ i,
+ clone;
+
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
+ safe = context === document && safeFragment,
+ ret = [];
+
+ // Ensure that context is a document
+ if ( !context || typeof context.createDocumentFragment === "undefined" ) {
+ context = document;
+ }
+
+ // Use the already-created safe fragment if context permits
+ for ( i = 0; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Ensure a safe container in which to render the html
+ safe = safe || createSafeFragment( context );
+ div = context.createElement("div");
+ safe.appendChild( div );
+
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1>$2>");
+
+ // Go to html and back, then peel off extra wrappers
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ depth = wrap[0];
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a , *may* have spurious
+ hasBody = rtbody.test(elem);
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare or
+ wrap[1] === "" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+
+ // Take out of fragment container (we need a fresh div each time)
+ div.parentNode.removeChild( div );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ jQuery.merge( ret, elem );
+ }
+ }
+
+ // Fix #11356: Clear elements from safeFragment
+ if ( div ) {
+ elem = div = safe = null;
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ fixDefaultChecked( elem );
+ } else if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+ }
+ }
+
+ // Append elements to a provided document fragment
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var data, id, elem, type,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ jQuery.deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+// Limit scope pollution from any deprecated API
+(function() {
+
+var matched, browser;
+
+// Use of jQuery.browser is frowned upon.
+// More details: http://api.jquery.com/jQuery.browser
+// jQuery.uaMatch maintained for back-compat
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+matched = jQuery.uaMatch( navigator.userAgent );
+browser = {};
+
+if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+}
+
+// Chrome is Webkit, but Webkit is also Safari.
+if ( browser.chrome ) {
+ browser.webkit = true;
+} else if ( browser.webkit ) {
+ browser.safari = true;
+}
+
+jQuery.browser = browser;
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+};
+
+})();
+var curCSS, iframe, iframeDoc,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
+
+ eventsToggle = jQuery.fn.toggle;
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+ var elem, display,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && elem.style.display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ display = curCSS( elem, "display" );
+
+ if ( !values[ index ] && display !== "none" ) {
+ jQuery._data( elem, "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state, fn2 ) {
+ var bool = typeof state === "boolean";
+
+ if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
+ return eventsToggle.apply( this, arguments );
+ }
+
+ return this.each(function() {
+ if ( bool ? state : isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, numeric, extra ) {
+ var val, num, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( numeric || extra !== undefined ) {
+ num = parseFloat( val );
+ return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// NOTE: To any future maintainer, we've window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ curCSS = function( elem, name ) {
+ var ret, width, minWidth, maxWidth,
+ computed = window.getComputedStyle( elem, null ),
+ style = elem.style;
+
+ if ( computed ) {
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ curCSS = function( elem, name ) {
+ var left, rsLeft,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ // we use jQuery.css instead of curCSS here
+ // because of the reliableMarginRight CSS hook!
+ val += jQuery.css( elem, extra + cssExpand[ i ], true );
+ }
+
+ // From this point on we use curCSS for maximum performance (relevant in animations)
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ valueIsBorderBox = true,
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox
+ )
+ ) + "px";
+}
+
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ if ( elemdisplay[ nodeName ] ) {
+ return elemdisplay[ nodeName ];
+ }
+
+ var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
+ display = elem.css("display");
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // Use the already-created iframe if possible
+ iframe = document.body.appendChild(
+ iframe || jQuery.extend( document.createElement("iframe"), {
+ frameBorder: 0,
+ width: 0,
+ height: 0
+ })
+ );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write("");
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
+
+ display = curCSS( elem, "display" );
+ document.body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ });
+ } else {
+ return getWidthOrHeight( elem, name, extra );
+ }
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ return curCSS( elem, "marginRight" );
+ }
+ });
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ var ret = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ rselectTextarea = /^(?:select|textarea)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/phantom.js b/plugins/system/t3/base/bootstrap/js/tests/phantom.js
new file mode 100644
index 0000000..4105bf5
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/phantom.js
@@ -0,0 +1,63 @@
+// Simple phantom.js integration script
+// Adapted from Modernizr
+
+function waitFor(testFx, onReady, timeOutMillis) {
+ var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 5001 //< Default Max Timout is 5s
+ , start = new Date().getTime()
+ , condition = false
+ , interval = setInterval(function () {
+ if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
+ // If not time-out yet and condition not yet fulfilled
+ condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()) //< defensive code
+ } else {
+ if (!condition) {
+ // If condition still not fulfilled (timeout but condition is 'false')
+ console.log("'waitFor()' timeout")
+ phantom.exit(1)
+ } else {
+ // Condition fulfilled (timeout and/or condition is 'true')
+ typeof(onReady) === "string" ? eval(onReady) : onReady() //< Do what it's supposed to do once the condition is fulfilled
+ clearInterval(interval) //< Stop this interval
+ }
+ }
+ }, 100) //< repeat check every 100ms
+}
+
+
+if (phantom.args.length === 0 || phantom.args.length > 2) {
+ console.log('Usage: phantom.js URL')
+ phantom.exit()
+}
+
+var page = new WebPage()
+
+// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
+page.onConsoleMessage = function(msg) {
+ console.log(msg)
+};
+
+page.open(phantom.args[0], function(status){
+ if (status !== "success") {
+ console.log("Unable to access network")
+ phantom.exit()
+ } else {
+ waitFor(function(){
+ return page.evaluate(function(){
+ var el = document.getElementById('qunit-testresult')
+ if (el && el.innerText.match('completed')) {
+ return true
+ }
+ return false
+ })
+ }, function(){
+ var failedNum = page.evaluate(function(){
+ var el = document.getElementById('qunit-testresult')
+ try {
+ return el.getElementsByClassName('failed')[0].innerHTML
+ } catch (e) { }
+ return 10000
+ });
+ phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0)
+ })
+ }
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/server.js b/plugins/system/t3/base/bootstrap/js/tests/server.js
new file mode 100644
index 0000000..7c8445f
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/server.js
@@ -0,0 +1,14 @@
+/*
+ * Simple connect server for phantom.js
+ * Adapted from Modernizr
+ */
+
+var connect = require('connect')
+ , http = require('http')
+ , fs = require('fs')
+ , app = connect()
+ .use(connect.static(__dirname + '/../../'));
+
+http.createServer(app).listen(3000);
+
+fs.writeFileSync(__dirname + '/pid.txt', process.pid, 'utf-8')
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-affix.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-affix.js
new file mode 100644
index 0000000..bc25df9
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-affix.js
@@ -0,0 +1,19 @@
+$(function () {
+
+ module("bootstrap-affix")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).affix, 'affix method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).affix()[0] == document.body, 'document.body returned')
+ })
+
+ test("should exit early if element is not visible", function () {
+ var $affix = $('
').affix()
+ $affix.data('affix').checkPosition()
+ ok(!$affix.hasClass('affix'), 'affix class was not added')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-alert.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-alert.js
new file mode 100644
index 0000000..7f24e0e
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-alert.js
@@ -0,0 +1,56 @@
+$(function () {
+
+ module("bootstrap-alerts")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).alert, 'alert method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).alert()[0] == document.body, 'document.body returned')
+ })
+
+ test("should fade element out on clicking .close", function () {
+ var alertHTML = ''
+ + '
× '
+ + '
Holy guacamole! Best check yo self, you\'re not looking too good.
'
+ + '
'
+ , alert = $(alertHTML).alert()
+
+ alert.find('.close').click()
+
+ ok(!alert.hasClass('in'), 'remove .in class on .close click')
+ })
+
+ test("should remove element when clicking .close", function () {
+ $.support.transition = false
+
+ var alertHTML = ''
+ + '
× '
+ + '
Holy guacamole! Best check yo self, you\'re not looking too good.
'
+ + '
'
+ , alert = $(alertHTML).appendTo('#qunit-fixture').alert()
+
+ ok($('#qunit-fixture').find('.alert-message').length, 'element added to dom')
+
+ alert.find('.close').click()
+
+ ok(!$('#qunit-fixture').find('.alert-message').length, 'element removed from dom')
+ })
+
+ test("should not fire closed when close is prevented", function () {
+ $.support.transition = false
+ stop();
+ $('
')
+ .bind('close', function (e) {
+ e.preventDefault();
+ ok(true);
+ start();
+ })
+ .bind('closed', function () {
+ ok(false);
+ })
+ .alert('close')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-button.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-button.js
new file mode 100644
index 0000000..03c4a8e
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-button.js
@@ -0,0 +1,77 @@
+$(function () {
+
+ module("bootstrap-buttons")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).button, 'button method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).button()[0] == document.body, 'document.body returned')
+ })
+
+ test("should return set state to loading", function () {
+ var btn = $('mdo ')
+ equals(btn.html(), 'mdo', 'btn text equals mdo')
+ btn.button('loading')
+ equals(btn.html(), 'fat', 'btn text equals fat')
+ stop()
+ setTimeout(function () {
+ ok(btn.attr('disabled'), 'btn is disabled')
+ ok(btn.hasClass('disabled'), 'btn has disabled class')
+ start()
+ }, 0)
+ })
+
+ test("should return reset state", function () {
+ var btn = $('mdo ')
+ equals(btn.html(), 'mdo', 'btn text equals mdo')
+ btn.button('loading')
+ equals(btn.html(), 'fat', 'btn text equals fat')
+ stop()
+ setTimeout(function () {
+ ok(btn.attr('disabled'), 'btn is disabled')
+ ok(btn.hasClass('disabled'), 'btn has disabled class')
+ start()
+ stop()
+ }, 0)
+ btn.button('reset')
+ equals(btn.html(), 'mdo', 'btn text equals mdo')
+ setTimeout(function () {
+ ok(!btn.attr('disabled'), 'btn is not disabled')
+ ok(!btn.hasClass('disabled'), 'btn does not have disabled class')
+ start()
+ }, 0)
+ })
+
+ test("should toggle active", function () {
+ var btn = $('mdo ')
+ ok(!btn.hasClass('active'), 'btn does not have active class')
+ btn.button('toggle')
+ ok(btn.hasClass('active'), 'btn has class active')
+ })
+
+ test("should toggle active when btn children are clicked", function () {
+ var btn = $('mdo ')
+ , inner = $(' ')
+ btn
+ .append(inner)
+ .appendTo($('#qunit-fixture'))
+ ok(!btn.hasClass('active'), 'btn does not have active class')
+ inner.click()
+ ok(btn.hasClass('active'), 'btn has class active')
+ })
+
+ test("should toggle active when btn children are clicked within btn-group", function () {
+ var btngroup = $('
')
+ , btn = $('fat ')
+ , inner = $(' ')
+ btngroup
+ .append(btn.append(inner))
+ .appendTo($('#qunit-fixture'))
+ ok(!btn.hasClass('active'), 'btn does not have active class')
+ inner.click()
+ ok(btn.hasClass('active'), 'btn has class active')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-carousel.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-carousel.js
new file mode 100644
index 0000000..4c93c7b
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-carousel.js
@@ -0,0 +1,42 @@
+$(function () {
+
+ module("bootstrap-carousel")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).carousel, 'carousel method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).carousel()[0] == document.body, 'document.body returned')
+ })
+
+ test("should not fire sliden when slide is prevented", function () {
+ $.support.transition = false
+ stop()
+ $('
')
+ .bind('slide', function (e) {
+ e.preventDefault();
+ ok(true);
+ start();
+ })
+ .bind('slid', function () {
+ ok(false);
+ })
+ .carousel('next')
+ })
+
+ test("should fire slide event with relatedTarget", function () {
+ var template = '{{_i}}First Thumbnail label{{/i}} Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}} Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}} Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹ › '
+ $.support.transition = false
+ stop()
+ $(template)
+ .on('slide', function (e) {
+ e.preventDefault();
+ ok(e.relatedTarget);
+ ok($(e.relatedTarget).hasClass('item'));
+ start();
+ })
+ .carousel('next')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-collapse.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-collapse.js
new file mode 100644
index 0000000..6cc7ac7
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-collapse.js
@@ -0,0 +1,88 @@
+$(function () {
+
+ module("bootstrap-collapse")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).collapse, 'collapse method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).collapse()[0] == document.body, 'document.body returned')
+ })
+
+ test("should show a collapsed element", function () {
+ var el = $('
').collapse('show')
+ ok(el.hasClass('in'), 'has class in')
+ ok(/height/.test(el.attr('style')), 'has height set')
+ })
+
+ test("should hide a collapsed element", function () {
+ var el = $('
').collapse('hide')
+ ok(!el.hasClass('in'), 'does not have class in')
+ ok(/height/.test(el.attr('style')), 'has height set')
+ })
+
+ test("should not fire shown when show is prevented", function () {
+ $.support.transition = false
+ stop()
+ $('
')
+ .bind('show', function (e) {
+ e.preventDefault();
+ ok(true);
+ start();
+ })
+ .bind('shown', function () {
+ ok(false);
+ })
+ .collapse('show')
+ })
+
+ test("should reset style to auto after finishing opening collapse", function () {
+ $.support.transition = false
+ stop()
+ $('
')
+ .bind('show', function () {
+ ok(this.style.height == '0px')
+ })
+ .bind('shown', function () {
+ ok(this.style.height == 'auto')
+ start()
+ })
+ .collapse('show')
+ })
+
+ test("should add active class to target when collapse shown", function () {
+ $.support.transition = false
+ stop()
+
+ var target = $(' ')
+ .appendTo($('#qunit-fixture'))
+
+ var collapsible = $('
')
+ .appendTo($('#qunit-fixture'))
+ .on('show', function () {
+ ok(!target.hasClass('collapsed'))
+ start()
+ })
+
+ target.click()
+ })
+
+ test("should remove active class to target when collapse hidden", function () {
+ $.support.transition = false
+ stop()
+
+ var target = $(' ')
+ .appendTo($('#qunit-fixture'))
+
+ var collapsible = $('
')
+ .appendTo($('#qunit-fixture'))
+ .on('hide', function () {
+ ok(target.hasClass('collapsed'))
+ start()
+ })
+
+ target.click()
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-dropdown.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-dropdown.js
new file mode 100644
index 0000000..4e52c84
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-dropdown.js
@@ -0,0 +1,87 @@
+$(function () {
+
+ module("bootstrap-dropdowns")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).dropdown, 'dropdown method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).dropdown()[0] == document.body, 'document.body returned')
+ })
+
+ test("should not open dropdown if target is disabled", function () {
+ var dropdownHTML = ''
+ + ''
+ + 'Dropdown '
+ + ''
+ + ' '
+ + ' '
+ , dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').dropdown().click()
+
+ ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
+ })
+
+ test("should not open dropdown if target is disabled", function () {
+ var dropdownHTML = ''
+ + ''
+ + 'Dropdown '
+ + ''
+ + ' '
+ + ' '
+ , dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').dropdown().click()
+
+ ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
+ })
+
+ test("should add class open to menu if clicked", function () {
+ var dropdownHTML = ''
+ + ''
+ + 'Dropdown '
+ + ''
+ + ' '
+ + ' '
+ , dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').dropdown().click()
+
+ ok(dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
+ })
+
+ test("should remove open class if body clicked", function () {
+ var dropdownHTML = ''
+ + ''
+ + 'Dropdown '
+ + ''
+ + ' '
+ + ' '
+ , dropdown = $(dropdownHTML)
+ .appendTo('#qunit-fixture')
+ .find('[data-toggle="dropdown"]')
+ .dropdown()
+ .click()
+ ok(dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
+ $('body').click()
+ ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class removed')
+ dropdown.remove()
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-modal.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-modal.js
new file mode 100644
index 0000000..0851f64
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-modal.js
@@ -0,0 +1,114 @@
+$(function () {
+
+ module("bootstrap-modal")
+
+ test("should be defined on jquery object", function () {
+ var div = $("
")
+ ok(div.modal, 'modal method is defined')
+ })
+
+ test("should return element", function () {
+ var div = $("
")
+ ok(div.modal() == div, 'document.body returned')
+ $('#modal-test').remove()
+ })
+
+ test("should expose defaults var for settings", function () {
+ ok($.fn.modal.defaults, 'default object exposed')
+ })
+
+ test("should insert into dom when show method is called", function () {
+ stop()
+ $.support.transition = false
+ $("
")
+ .bind("shown", function () {
+ ok($('#modal-test').length, 'modal insterted into dom')
+ $(this).remove()
+ start()
+ })
+ .modal("show")
+ })
+
+ test("should fire show event", function () {
+ stop()
+ $.support.transition = false
+ $("
")
+ .bind("show", function () {
+ ok(true, "show was called")
+ })
+ .bind("shown", function () {
+ $(this).remove()
+ start()
+ })
+ .modal("show")
+ })
+
+ test("should not fire shown when default prevented", function () {
+ stop()
+ $.support.transition = false
+ $("
")
+ .bind("show", function (e) {
+ e.preventDefault()
+ ok(true, "show was called")
+ start()
+ })
+ .bind("shown", function () {
+ ok(false, "shown was called")
+ })
+ .modal("show")
+ })
+
+ test("should hide modal when hide is called", function () {
+ stop()
+ $.support.transition = false
+
+ $("
")
+ .bind("shown", function () {
+ ok($('#modal-test').is(":visible"), 'modal visible')
+ ok($('#modal-test').length, 'modal insterted into dom')
+ $(this).modal("hide")
+ })
+ .bind("hidden", function() {
+ ok(!$('#modal-test').is(":visible"), 'modal hidden')
+ $('#modal-test').remove()
+ start()
+ })
+ .modal("show")
+ })
+
+ test("should toggle when toggle is called", function () {
+ stop()
+ $.support.transition = false
+ var div = $("
")
+ div
+ .bind("shown", function () {
+ ok($('#modal-test').is(":visible"), 'modal visible')
+ ok($('#modal-test').length, 'modal insterted into dom')
+ div.modal("toggle")
+ })
+ .bind("hidden", function() {
+ ok(!$('#modal-test').is(":visible"), 'modal hidden')
+ div.remove()
+ start()
+ })
+ .modal("toggle")
+ })
+
+ test("should remove from dom when click [data-dismiss=modal]", function () {
+ stop()
+ $.support.transition = false
+ var div = $("
")
+ div
+ .bind("shown", function () {
+ ok($('#modal-test').is(":visible"), 'modal visible')
+ ok($('#modal-test').length, 'modal insterted into dom')
+ div.find('.close').click()
+ })
+ .bind("hidden", function() {
+ ok(!$('#modal-test').is(":visible"), 'modal hidden')
+ div.remove()
+ start()
+ })
+ .modal("toggle")
+ })
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-phantom.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-phantom.js
new file mode 100644
index 0000000..a04aeaa
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-phantom.js
@@ -0,0 +1,21 @@
+// Logging setup for phantom integration
+// adapted from Modernizr
+
+QUnit.begin = function () {
+ console.log("Starting test suite")
+ console.log("================================================\n")
+}
+
+QUnit.moduleDone = function (opts) {
+ if (opts.failed === 0) {
+ console.log("\u2714 All tests passed in '" + opts.name + "' module")
+ } else {
+ console.log("\u2716 " + opts.failed + " tests failed in '" + opts.name + "' module")
+ }
+}
+
+QUnit.done = function (opts) {
+ console.log("\n================================================")
+ console.log("Tests completed in " + opts.runtime + " milliseconds")
+ console.log(opts.passed + " tests of " + opts.total + " passed, " + opts.failed + " failed.")
+}
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-popover.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-popover.js
new file mode 100644
index 0000000..04d5279
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-popover.js
@@ -0,0 +1,107 @@
+$(function () {
+
+ module("bootstrap-popover")
+
+ test("should be defined on jquery object", function () {
+ var div = $('
')
+ ok(div.popover, 'popover method is defined')
+ })
+
+ test("should return element", function () {
+ var div = $('
')
+ ok(div.popover() == div, 'document.body returned')
+ })
+
+ test("should render popover element", function () {
+ $.support.transition = false
+ var popover = $('@mdo ')
+ .appendTo('#qunit-fixture')
+ .popover('show')
+
+ ok($('.popover').length, 'popover was inserted')
+ popover.popover('hide')
+ ok(!$(".popover").length, 'popover removed')
+ })
+
+ test("should store popover instance in popover data object", function () {
+ $.support.transition = false
+ var popover = $('@mdo ')
+ .popover()
+
+ ok(!!popover.data('popover'), 'popover instance exists')
+ })
+
+ test("should get title and content from options", function () {
+ $.support.transition = false
+ var popover = $('@fat ')
+ .appendTo('#qunit-fixture')
+ .popover({
+ title: function () {
+ return '@fat'
+ }
+ , content: function () {
+ return 'loves writing tests (╯°□°)╯︵ â”»â”â”»'
+ }
+ })
+
+ popover.popover('show')
+
+ ok($('.popover').length, 'popover was inserted')
+ equals($('.popover .popover-title').text(), '@fat', 'title correctly inserted')
+ equals($('.popover .popover-content').text(), 'loves writing tests (╯°□°)╯︵ â”»â”â”»', 'content correctly inserted')
+
+ popover.popover('hide')
+ ok(!$('.popover').length, 'popover was removed')
+ $('#qunit-fixture').empty()
+ })
+
+ test("should get title and content from attributes", function () {
+ $.support.transition = false
+ var popover = $('@mdo ')
+ .appendTo('#qunit-fixture')
+ .popover()
+ .popover('show')
+
+ ok($('.popover').length, 'popover was inserted')
+ equals($('.popover .popover-title').text(), '@mdo', 'title correctly inserted')
+ equals($('.popover .popover-content').text(), "loves data attributes (ã¥ï½¡â—•â€¿â€¿â—•ï½¡)㥠︵ â”»â”â”»", 'content correctly inserted')
+
+ popover.popover('hide')
+ ok(!$('.popover').length, 'popover was removed')
+ $('#qunit-fixture').empty()
+ })
+
+ test("should respect custom classes", function() {
+ $.support.transition = false
+ var popover = $('@fat ')
+ .appendTo('#qunit-fixture')
+ .popover({
+ title: 'Test'
+ , content: 'Test'
+ , template: ''
+ })
+
+ popover.popover('show')
+
+ ok($('.popover').length, 'popover was inserted')
+ ok($('.popover').hasClass('foobar'), 'custom class is present')
+
+ popover.popover('hide')
+ ok(!$('.popover').length, 'popover was removed')
+ $('#qunit-fixture').empty()
+ })
+
+ test("should destroy popover", function () {
+ var popover = $('
').popover({trigger: 'hover'}).on('click.foo', function(){})
+ ok(popover.data('popover'), 'popover has data')
+ ok(popover.data('events').mouseover && popover.data('events').mouseout, 'popover has hover event')
+ ok(popover.data('events').click[0].namespace == 'foo', 'popover has extra click.foo event')
+ popover.popover('show')
+ popover.popover('destroy')
+ ok(!popover.hasClass('in'), 'popover is hidden')
+ ok(!popover.data('popover'), 'popover does not have data')
+ ok(popover.data('events').click[0].namespace == 'foo', 'popover still has click.foo')
+ ok(!popover.data('events').mouseover && !popover.data('events').mouseout, 'popover does not have any events')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-scrollspy.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-scrollspy.js
new file mode 100644
index 0000000..bee46a9
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-scrollspy.js
@@ -0,0 +1,31 @@
+$(function () {
+
+ module("bootstrap-scrollspy")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).scrollspy, 'scrollspy method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).scrollspy()[0] == document.body, 'document.body returned')
+ })
+
+ test("should switch active class on scroll", function () {
+ var sectionHTML = '
'
+ , $section = $(sectionHTML).append('#qunit-fixture')
+ , topbarHTML =''
+ , $topbar = $(topbarHTML).scrollspy()
+
+ ok($topbar.find('.active', true))
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tab.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tab.js
new file mode 100644
index 0000000..9878047
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tab.js
@@ -0,0 +1,61 @@
+$(function () {
+
+ module("bootstrap-tabs")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).tab, 'tabs method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).tab()[0] == document.body, 'document.body returned')
+ })
+
+ test("should activate element by tab id", function () {
+ var tabsHTML =
+ ''
+
+ $('').appendTo("#qunit-fixture")
+
+ $(tabsHTML).find('li:last a').tab('show')
+ equals($("#qunit-fixture").find('.active').attr('id'), "profile")
+
+ $(tabsHTML).find('li:first a').tab('show')
+ equals($("#qunit-fixture").find('.active').attr('id'), "home")
+ })
+
+ test("should activate element by tab id", function () {
+ var pillsHTML =
+ ''
+
+ $('').appendTo("#qunit-fixture")
+
+ $(pillsHTML).find('li:last a').tab('show')
+ equals($("#qunit-fixture").find('.active').attr('id'), "profile")
+
+ $(pillsHTML).find('li:first a').tab('show')
+ equals($("#qunit-fixture").find('.active').attr('id'), "home")
+ })
+
+
+ test("should not fire closed when close is prevented", function () {
+ $.support.transition = false
+ stop();
+ $('
')
+ .bind('show', function (e) {
+ e.preventDefault();
+ ok(true);
+ start();
+ })
+ .bind('shown', function () {
+ ok(false);
+ })
+ .tab('show')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tooltip.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tooltip.js
new file mode 100644
index 0000000..2eb8c8f
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-tooltip.js
@@ -0,0 +1,144 @@
+$(function () {
+
+ module("bootstrap-tooltip")
+
+ test("should be defined on jquery object", function () {
+ var div = $("
")
+ ok(div.tooltip, 'popover method is defined')
+ })
+
+ test("should return element", function () {
+ var div = $("
")
+ ok(div.tooltip() == div, 'document.body returned')
+ })
+
+ test("should expose default settings", function () {
+ ok(!!$.fn.tooltip.defaults, 'defaults is defined')
+ })
+
+ test("should remove title attribute", function () {
+ var tooltip = $(' ').tooltip()
+ ok(!tooltip.attr('title'), 'title tag was removed')
+ })
+
+ test("should add data attribute for referencing original title", function () {
+ var tooltip = $(' ').tooltip()
+ equals(tooltip.attr('data-original-title'), 'Another tooltip', 'original title preserved in data attribute')
+ })
+
+ test("should place tooltips relative to placement option", function () {
+ $.support.transition = false
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({placement: 'bottom'})
+ .tooltip('show')
+
+ ok($(".tooltip").is('.fade.bottom.in'), 'has correct classes applied')
+ tooltip.tooltip('hide')
+ })
+
+ test("should always allow html entities", function () {
+ $.support.transition = false
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip('show')
+
+ ok($('.tooltip b').length, 'b tag was inserted')
+ tooltip.tooltip('hide')
+ ok(!$(".tooltip").length, 'tooltip removed')
+ })
+
+ test("should respect custom classes", function () {
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({ template: ''})
+ .tooltip('show')
+
+ ok($('.tooltip').hasClass('some-class'), 'custom class is present')
+ tooltip.tooltip('hide')
+ ok(!$(".tooltip").length, 'tooltip removed')
+ })
+
+ test("should not show tooltip if leave event occurs before delay expires", function () {
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({ delay: 200 })
+
+ stop()
+
+ tooltip.trigger('mouseenter')
+
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ tooltip.trigger('mouseout')
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ start()
+ }, 200)
+ }, 100)
+ })
+
+ test("should not show tooltip if leave event occurs before delay expires, even if hide delay is 0", function () {
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({ delay: { show: 200, hide: 0} })
+
+ stop()
+
+ tooltip.trigger('mouseenter')
+
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ tooltip.trigger('mouseout')
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ start()
+ }, 200)
+ }, 100)
+ })
+
+ test("should not show tooltip if leave event occurs before delay expires", function () {
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({ delay: 100 })
+ stop()
+ tooltip.trigger('mouseenter')
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ tooltip.trigger('mouseout')
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ start()
+ }, 100)
+ }, 50)
+ })
+
+ test("should show tooltip if leave event hasn't occured before delay expires", function () {
+ var tooltip = $(' ')
+ .appendTo('#qunit-fixture')
+ .tooltip({ delay: 150 })
+ stop()
+ tooltip.trigger('mouseenter')
+ setTimeout(function () {
+ ok(!$(".tooltip").is('.fade.in'), 'tooltip is not faded in')
+ }, 100)
+ setTimeout(function () {
+ ok($(".tooltip").is('.fade.in'), 'tooltip has faded in')
+ start()
+ }, 200)
+ })
+
+ test("should destroy tooltip", function () {
+ var tooltip = $('
').tooltip().on('click.foo', function(){})
+ ok(tooltip.data('tooltip'), 'tooltip has data')
+ ok(tooltip.data('events').mouseover && tooltip.data('events').mouseout, 'tooltip has hover event')
+ ok(tooltip.data('events').click[0].namespace == 'foo', 'tooltip has extra click.foo event')
+ tooltip.tooltip('show')
+ tooltip.tooltip('destroy')
+ ok(!tooltip.hasClass('in'), 'tooltip is hidden')
+ ok(!tooltip.data('tooltip'), 'tooltip does not have data')
+ ok(tooltip.data('events').click[0].namespace == 'foo', 'tooltip still has click.foo')
+ ok(!tooltip.data('events').mouseover && !tooltip.data('events').mouseout, 'tooltip does not have any events')
+ })
+
+})
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-transition.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-transition.js
new file mode 100644
index 0000000..086773f
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-transition.js
@@ -0,0 +1,13 @@
+$(function () {
+
+ module("bootstrap-transition")
+
+ test("should be defined on jquery support object", function () {
+ ok($.support.transition !== undefined, 'transition object is defined')
+ })
+
+ test("should provide an end object", function () {
+ ok($.support.transition ? $.support.transition.end : true, 'end string is defined')
+ })
+
+})
\ No newline at end of file
diff --git a/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-typeahead.js b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-typeahead.js
new file mode 100644
index 0000000..eb447aa
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/unit/bootstrap-typeahead.js
@@ -0,0 +1,204 @@
+$(function () {
+
+ module("bootstrap-typeahead")
+
+ test("should be defined on jquery object", function () {
+ ok($(document.body).typeahead, 'alert method is defined')
+ })
+
+ test("should return element", function () {
+ ok($(document.body).typeahead()[0] == document.body, 'document.body returned')
+ })
+
+ test("should listen to an input", function () {
+ var $input = $(' ')
+ $input.typeahead()
+ ok($input.data('events').blur, 'has a blur event')
+ ok($input.data('events').keypress, 'has a keypress event')
+ ok($input.data('events').keyup, 'has a keyup event')
+ if ($.browser.webkit || $.browser.msie) {
+ ok($input.data('events').keydown, 'has a keydown event')
+ } else {
+ ok($input.data('events').keydown, 'does not have a keydown event')
+ }
+ })
+
+ test("should create a menu", function () {
+ var $input = $(' ')
+ ok($input.typeahead().data('typeahead').$menu, 'has a menu')
+ })
+
+ test("should listen to the menu", function () {
+ var $input = $(' ')
+ , $menu = $input.typeahead().data('typeahead').$menu
+
+ ok($menu.data('events').mouseover, 'has a mouseover(pseudo: mouseenter)')
+ ok($menu.data('events').click, 'has a click')
+ })
+
+ test("should show menu when query entered", function () {
+ var $input = $(' ').typeahead({
+ source: ['aa', 'ab', 'ac']
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('a')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+
+ typeahead.$menu.remove()
+ })
+
+ test("should accept data source via synchronous function", function () {
+ var $input = $(' ').typeahead({
+ source: function () {
+ return ['aa', 'ab', 'ac']
+ }
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('a')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+
+ typeahead.$menu.remove()
+ })
+
+ test("should accept data source via asynchronous function", function () {
+ var $input = $(' ').typeahead({
+ source: function (query, process) {
+ process(['aa', 'ab', 'ac'])
+ }
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('a')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+
+ typeahead.$menu.remove()
+ })
+
+ test("should not explode when regex chars are entered", function () {
+ var $input = $(' ').typeahead({
+ source: ['aa', 'ab', 'ac', 'mdo*', 'fat+']
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('+')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 1, 'has 1 item in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+
+ typeahead.$menu.remove()
+ })
+
+ test("should hide menu when query entered", function () {
+ stop()
+ var $input = $(' ').typeahead({
+ source: ['aa', 'ab', 'ac']
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('a')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+
+ $input.blur()
+
+ setTimeout(function () {
+ ok(!typeahead.$menu.is(":visible"), "typeahead is no longer visible")
+ start()
+ }, 200)
+
+ typeahead.$menu.remove()
+ })
+
+ test("should set next item when down arrow is pressed", function () {
+ var $input = $(' ').typeahead({
+ source: ['aa', 'ab', 'ac']
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('a')
+ typeahead.lookup()
+
+ ok(typeahead.$menu.is(":visible"), 'typeahead is visible')
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+ equals(typeahead.$menu.find('.active').length, 1, 'one item is active')
+ ok(typeahead.$menu.find('li').first().hasClass('active'), "first item is active")
+
+ $input.trigger({
+ type: 'keydown'
+ , keyCode: 40
+ })
+
+ ok(typeahead.$menu.find('li').first().next().hasClass('active'), "second item is active")
+
+
+ $input.trigger({
+ type: 'keydown'
+ , keyCode: 38
+ })
+
+ ok(typeahead.$menu.find('li').first().hasClass('active'), "first item is active")
+
+ typeahead.$menu.remove()
+ })
+
+
+ test("should set input value to selected item", function () {
+ var $input = $(' ').typeahead({
+ source: ['aa', 'ab', 'ac']
+ })
+ , typeahead = $input.data('typeahead')
+ , changed = false
+
+ $input.val('a')
+ typeahead.lookup()
+
+ $input.change(function() { changed = true });
+
+ $(typeahead.$menu.find('li')[2]).mouseover().click()
+
+ equals($input.val(), 'ac', 'input value was correctly set')
+ ok(!typeahead.$menu.is(':visible'), 'the menu was hidden')
+ ok(changed, 'a change event was fired')
+
+ typeahead.$menu.remove()
+ })
+
+ test("should start querying when minLength is met", function () {
+ var $input = $(' ').typeahead({
+ source: ['aaaa', 'aaab', 'aaac'],
+ minLength: 3
+ })
+ , typeahead = $input.data('typeahead')
+
+ $input.val('aa')
+ typeahead.lookup()
+
+ equals(typeahead.$menu.find('li').length, 0, 'has 0 items in menu')
+
+ $input.val('aaa')
+ typeahead.lookup()
+
+ equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu')
+
+ typeahead.$menu.remove()
+ })
+})
diff --git a/plugins/system/t3/base/bootstrap/js/tests/vendor/jquery.js b/plugins/system/t3/base/bootstrap/js/tests/vendor/jquery.js
new file mode 100644
index 0000000..93adea1
--- /dev/null
+++ b/plugins/system/t3/base/bootstrap/js/tests/vendor/jquery.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.2 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;ca ",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q=""+"",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
+a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c ",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=" ",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="
";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/ ]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,""," "],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""," "],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div","
"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
+.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>$2>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/
+
+
+ params->get('presentation_style') == 'tabs') : ?>
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/default_address.php b/plugins/system/t3/base/html/com_contact/contact/default_address.php
new file mode 100644
index 0000000..62e2cc5
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/default_address.php
@@ -0,0 +1,127 @@
+
+
+ params->get('address_check') > 0) &&
+ ($this->contact->address || $this->contact->suburb || $this->contact->state || $this->contact->country || $this->contact->postcode)) : ?>
+ params->get('address_check') > 0) : ?>
+
+
+ params->get('marker_address'); ?>
+
+
+
+
+ contact->address && $this->params->get('show_street_address')) : ?>
+
+
+ contact->address .' '; ?>
+
+
+
+
+ contact->suburb && $this->params->get('show_suburb')) : ?>
+
+
+ contact->suburb .' '; ?>
+
+
+
+ contact->state && $this->params->get('show_state')) : ?>
+
+
+ contact->state . ' '; ?>
+
+
+
+ contact->postcode && $this->params->get('show_postcode')) : ?>
+
+
+ contact->postcode .' '; ?>
+
+
+
+ contact->country && $this->params->get('show_country')) : ?>
+
+
+ contact->country .' '; ?>
+
+
+
+
+
+contact->email_to && $this->params->get('show_email')) : ?>
+
+
+ params->get('marker_email')); ?>
+
+
+
+
+ contact->email_to; ?>
+
+
+
+
+contact->telephone && $this->params->get('show_telephone')) : ?>
+
+
+ params->get('marker_telephone'); ?>
+
+
+
+
+ contact->telephone); ?>
+
+
+
+contact->fax && $this->params->get('show_fax')) : ?>
+
+
+ params->get('marker_fax'); ?>
+
+
+
+
+ contact->fax); ?>
+
+
+
+contact->mobile && $this->params->get('show_mobile')) :?>
+
+
+ params->get('marker_mobile'); ?>
+
+
+
+
+ contact->mobile); ?>
+
+
+
+contact->webpage && $this->params->get('show_webpage')) : ?>
+
+
+
+
+
+
+
+ contact->webpage; ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/default_articles.php b/plugins/system/t3/base/html/com_contact/contact/default_articles.php
new file mode 100644
index 0000000..55c6000
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/default_articles.php
@@ -0,0 +1,25 @@
+
+params->get('show_articles')) : ?>
+
+
+ item->articles as $article) : ?>
+
+ slug, $article->catslug)), htmlspecialchars($article->title, ENT_COMPAT, 'UTF-8')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/default_form.php b/plugins/system/t3/base/html/com_contact/contact/default_form.php
new file mode 100644
index 0000000..bdab230
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/default_form.php
@@ -0,0 +1,80 @@
+error)) : ?>
+
+ error; ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/default_links.php b/plugins/system/t3/base/html/com_contact/contact/default_links.php
new file mode 100644
index 0000000..fdab55f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/default_links.php
@@ -0,0 +1,62 @@
+params->get('presentation_style')=='sliders'):?>
+
+
+
+
+
+params->get('presentation_style') == 'tabs') : ?>
+
+
+params->get('presentation_style')=='plain'):?>
+'. JText::_('COM_CONTACT_LINKS').''; ?>
+
+
+
+
+params->get('presentation_style')=='sliders'):?>
+
+
+
+
+params->get('presentation_style') == 'tabs') : ?>
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/default_profile.php b/plugins/system/t3/base/html/com_contact/contact/default_profile.php
new file mode 100644
index 0000000..f07c9b2
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/default_profile.php
@@ -0,0 +1,40 @@
+
+item->profile->getFieldset('profile'); ?>
+
+
diff --git a/plugins/system/t3/base/html/com_contact/contact/index.html b/plugins/system/t3/base/html/com_contact/contact/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/contact/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_contact/featured/default.php b/plugins/system/t3/base/html/com_contact/featured/default.php
new file mode 100644
index 0000000..ddd19e5
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/featured/default.php
@@ -0,0 +1,39 @@
+
+
+params->get('show_page_heading') != 0 ) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+loadTemplate('items'); ?>
+pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+if ($this->params->def('show_pagination', 2) == 1 || ($this->params->get('show_pagination') == 2 && $pagesTotal > 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/featured/default_items.php b/plugins/system/t3/base/html/com_contact/featured/default_items.php
new file mode 100644
index 0000000..762f4dc
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/featured/default_items.php
@@ -0,0 +1,165 @@
+escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+
+// Create a shortcut for params.
+$params = &$this->item->params;
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_contact/featured/index.html b/plugins/system/t3/base/html/com_contact/featured/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/featured/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_contact/index.html b/plugins/system/t3/base/html/com_contact/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_contact/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_content/archive/default.php b/plugins/system/t3/base/html/com_content/archive/default.php
new file mode 100644
index 0000000..1ff8754
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/archive/default.php
@@ -0,0 +1,51 @@
+
+
+ params->get('show_page_heading', 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/archive/default_items.php b/plugins/system/t3/base/html/com_content/archive/default_items.php
new file mode 100644
index 0000000..46eee3e
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/archive/default_items.php
@@ -0,0 +1,62 @@
+params;
+
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+?>
+
+
+ items as $i => $item) : ?>
+
+
+ $item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+ $item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $item, 'params' => $params)); ?>
+
+
+
+
+
+ get('show_intro')) :?>
+ introtext, $params->get('introtext_limit')); ?>
+
+
+
+
+
+ $item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/archive/index.html b/plugins/system/t3/base/html/com_content/archive/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/archive/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_content/article/default.php b/plugins/system/t3/base/html/com_content/article/default.php
new file mode 100644
index 0000000..c6a7988
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/article/default.php
@@ -0,0 +1,158 @@
+item->params;
+$images = json_decode($this->item->images);
+$urls = json_decode($this->item->urls);
+$user = JFactory::getUser();
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = !empty($this->print) || $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+JHtml::_('behavior.caption');
+JHtml::_('bootstrap.tooltip');
+?>
+
+params->get('show_page_heading', 1)) : ?>
+
+
+
+
+
+
+item->pagination) && $this->item->pagination && !$this->item->paginationposition && $this->item->paginationrelative) : ?>
+ item->pagination; ?>
+
+
+
+
+
+
+get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h1')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params, 'print' => $this->print)); ?>
+
+
+
+
+
+item->toc)) : ?>
+ item->toc; ?>
+
+
+get('show_tags', 1) && !empty($this->item->tags)) : ?>
+ item->tags->itemTags); ?>
+
+
+get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+item->event->beforeDisplayContent; ?>
+
+urls_position) && ($urls->urls_position == '0')) || ($params->get('urls_position') == '0' && empty($urls->urls_position))) || (empty($urls->urls_position) && (!$params->get('urls_position')))): ?>
+ loadTemplate('links'); ?>
+
+
+get('access-view')): ?>
+
+ $this->item, 'params' => $params)); ?>
+
+ item->pagination) AND $this->item->pagination AND !$this->item->paginationposition AND !$this->item->paginationrelative):
+ echo $this->item->pagination;
+ endif; ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+ item->pagination) && $this->item->pagination && $this->item->paginationposition && !$this->item->paginationrelative): ?>
+ ';
+ echo $this->item->pagination;
+ ?>
+
+
+ urls_position) && ($urls->urls_position == '1')) || ($params->get('urls_position') == '1'))): ?>
+ loadTemplate('links'); ?>
+
+
+
+get('show_noauth') == true and $user->get('guest')) : ?>
+
+ item->introtext; ?>
+
+ get('show_readmore') && $this->item->fulltext != null) :
+ $link1 = JRoute::_('index.php?option=com_users&view=login');
+ $link = new JURI($link1);
+ ?>
+
+
+
+
+
+
+
+item->pagination) && $this->item->pagination && $this->item->paginationposition && $this->item->paginationrelative): ?>
+ item->pagination; ?>
+
+
+item->event->afterDisplayContent; ?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_content/article/default_links.php b/plugins/system/t3/base/html/com_content/article/default_links.php
new file mode 100644
index 0000000..8fc7ef9
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/article/default_links.php
@@ -0,0 +1,79 @@
+item->urls);
+
+// Create shortcuts to some parameters.
+$params = $this->item->params;
+if ($urls && (!empty($urls->urla) || !empty($urls->urlb) || !empty($urls->urlc))) :
+?>
+
+
+ urla, $urls->urlatext, $urls->targeta, 'a'),
+ array($urls->urlb, $urls->urlbtext, $urls->targetb, 'b'),
+ array($urls->urlc, $urls->urlctext, $urls->targetc, 'c')
+ );
+ foreach($urlarray as $url) :
+ $link = $url[0];
+ $label = $url[1];
+ $target = $url[2];
+ $id = $url[3];
+
+ if( ! $link) :
+ continue;
+ endif;
+
+ // If no label is present, take the link
+ $label = ($label) ? $label : $link;
+
+ // If no target is present, use the default
+ $target = $target ? $target : $params->get('target'.$id);
+ ?>
+
+ '.
+ htmlspecialchars($label) .'';
+ break;
+
+ case 2:
+ // open in a popup window
+ $attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=600';
+ echo "".
+ htmlspecialchars($label).' ';
+ break;
+ case 3:
+ // open in a modal window
+ JHtml::_('behavior.modal', 'a.modal'); ?>
+
+ ';
+ break;
+
+ default:
+ // open in parent window
+ echo ' '.
+ htmlspecialchars($label) . ' ';
+ break;
+ }
+ ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/article/index.html b/plugins/system/t3/base/html/com_content/article/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/article/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_content/categories/default.php b/plugins/system/t3/base/html/com_content/categories/default.php
new file mode 100644
index 0000000..3ab379b
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/categories/default.php
@@ -0,0 +1,21 @@
+
+
+
+loadTemplate('items');
+?>
+
diff --git a/plugins/system/t3/base/html/com_content/categories/default_items.php b/plugins/system/t3/base/html/com_content/categories/default_items.php
new file mode 100644
index 0000000..e3bc6a6
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/categories/default_items.php
@@ -0,0 +1,68 @@
+items[$this->parent->id]) > 0 && $this->maxLevelcat != 0) :
+?>
+ items[$this->parent->id] as $id => $item) : ?>
+ params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) :
+ if (!isset($this->items[$this->parent->id][$id + 1]))
+ {
+ $class = ' last';
+ }
+ ?>
+
+
+
+ params->get('show_description_image') && $item->getParams()->get('image')) : ?>
+
+
+ params->get('show_subcat_desc_cat') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.categories'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ items[$item->id] = $item->getChildren();
+ $this->parent = $item;
+ $this->maxLevelcat--;
+ echo $this->loadTemplate('items');
+ $this->parent = $item->getParent();
+ $this->maxLevelcat++;
+ ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/categories/index.html b/plugins/system/t3/base/html/com_content/categories/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/categories/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_content/category/blog.php b/plugins/system/t3/base/html/com_content/category/blog.php
new file mode 100644
index 0000000..ed606ec
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/blog.php
@@ -0,0 +1,121 @@
+
+
+ params->get('show_page_heading', 1)) : ?>
+
+
+ params->get('show_category_title', 1) or $this->params->get('page_subheading')) : ?>
+
+
+
+ params->get('show_tags', 1) && !empty($this->category->tags->itemTags)) : ?>
+ category->tags->itemTags); ?>
+
+
+ params->get('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
+
+ params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
+
+
+ params->get('show_description') && $this->category->description) : ?>
+ category->description, '', 'com_content.category'); ?>
+
+
+
+
+ lead_items) && empty($this->link_items) && empty($this->intro_items)) : ?>
+ params->get('show_no_articles', 1)) : ?>
+
+
+
+
+
+ lead_items)) : ?>
+
+ lead_items as &$item) : ?>
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+
+
+
+ intro_items));
+ $counter = 0;
+ ?>
+
+ intro_items)) : ?>
+ intro_items as $key => &$item) : ?>
+ columns) + 1; ?>
+
+ columns; ?>
+
+
+
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+ columns) or ($counter == $introcount)) : ?>
+
+
+
+
+
+ link_items)) : ?>
+
+ loadTemplate('links'); ?>
+
+
+
+ children[$this->category->id])&& $this->maxLevel != 0) : ?>
+
+ params->get('show_category_heading_title_text', 1) == 1) : ?>
+
+
+ loadTemplate('children'); ?>
+
+
+ pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+ if (($this->params->def('show_pagination', 1) == 1 || ($this->params->get('show_pagination') == 2)) && ($pagesTotal > 1)) : ?>
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/category/blog_children.php b/plugins/system/t3/base/html/com_content/category/blog_children.php
new file mode 100644
index 0000000..329df75
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/blog_children.php
@@ -0,0 +1,85 @@
+children[$this->category->id]) > 0 && $this->maxLevel != 0) : ?>
+
+ children[$this->category->id] as $id => $child) : ?>
+ params->get('show_empty_categories') || $child->numitems || count($child->getChildren())) :
+ if (!isset($this->children[$this->category->id][$id + 1])) :
+ $class = ' class="last"';
+ endif;
+ ?>
+ >
+
+ isRTL()) : ?>
+
+
+
+
+ params->get('show_subcat_desc') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.category'); ?>
+
+
+
+
+ getChildren()) > 0) : ?>
+
+ children[$child->id] = $child->getChildren();
+ $this->category = $child;
+ $this->maxLevel--;
+ if ($this->maxLevel != 0) :
+ echo $this->loadTemplate('children');
+ endif;
+ $this->category = $child->getParent();
+ $this->maxLevel++;
+ ?>
+
+
+
+
+
+
+item->params;
+$images = json_decode($this->item->images);
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+// update catslug if not exists - compatible with 2.5
+if (empty ($this->item->catslug)) {
+ $this->item->catslug = $this->item->category_alias ? ($this->item->catid.':'.$this->item->category_alias) : $this->item->catid;
+}
+?>
+
+item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+|| ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+
+
+
+ get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params)); ?>
+
+
+
+
+
+
+ get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+ item->event->beforeDisplayContent; ?>
+
+ item); ?>
+
+ item->introtext; ?>
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+
+ get('show_readmore') && $this->item->readmore) :
+ if ($params->get('access-view')) :
+ $link = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ else :
+ $menu = JFactory::getApplication()->getMenu();
+ $active = $menu->getActive();
+ $itemId = $active->id;
+ $link1 = JRoute::_('index.php?option=com_users&view=login&Itemid=' . $itemId);
+ $returnURL = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ $link = new JURI($link1);
+ $link->setVar('return', base64_encode($returnURL));
+ endif;
+ ?>
+
+
+
+
+
+
+
+item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+|| ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+item->event->afterDisplayContent; ?>
diff --git a/plugins/system/t3/base/html/com_content/category/blog_links.php b/plugins/system/t3/base/html/com_content/category/blog_links.php
new file mode 100644
index 0000000..f3c926f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/blog_links.php
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+link_items as &$item) :
+?>
+
+
+ title; ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/category/default.php b/plugins/system/t3/base/html/com_content/category/default.php
new file mode 100644
index 0000000..39ebf1a
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/default.php
@@ -0,0 +1,23 @@
+
+
+
+subtemplatename = 'articles';
+echo JLayoutHelper::render('joomla.content.category_default', $this);
+?>
+
+
diff --git a/plugins/system/t3/base/html/com_content/category/default_articles.php b/plugins/system/t3/base/html/com_content/category/default_articles.php
new file mode 100644
index 0000000..d535811
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/default_articles.php
@@ -0,0 +1,214 @@
+item->params;
+$n = count($this->items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+
+// Check for at least one editable article
+$isEditable = false;
+
+if (!empty($this->items))
+{
+ foreach ($this->items as $article)
+ {
+ if ($article->params->get('access-edit'))
+ {
+ $isEditable = true;
+ break;
+ }
+ }
+}
+?>
+
+items)) : ?>
+
+ params->get('show_no_articles', 1)) : ?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/category/default_children.php b/plugins/system/t3/base/html/com_content/category/default_children.php
new file mode 100644
index 0000000..a063d64
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/default_children.php
@@ -0,0 +1,85 @@
+
+
+children[$this->category->id]) > 0) : ?>
+ children[$this->category->id] as $id => $child) : ?>
+ params->get('show_empty_categories') || $child->getNumItems(true) || count($child->getChildren())) :
+ if (!isset($this->children[$this->category->id][$id + 1])) :
+ $class = ' class="last"';
+ endif;
+ ?>
+
+ >
+
+ isRTL()) : ?>
+
+
+
+ params->get('show_subcat_desc') == 1) :?>
+ description) : ?>
+
+ description, '', 'com_content.category'); ?>
+
+
+
+
+ getChildren()) > 0) :?>
+
+ children[$child->id] = $child->getChildren();
+ $this->category = $child;
+ $this->maxLevel--;
+ if ($this->maxLevel != 0) :
+ echo $this->loadTemplate('children');
+ endif;
+ $this->category = $child->getParent();
+ $this->maxLevel++;
+ ?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/category/index.html b/plugins/system/t3/base/html/com_content/category/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/category/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_content/featured/default.php b/plugins/system/t3/base/html/com_content/featured/default.php
new file mode 100644
index 0000000..f924a05
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/featured/default.php
@@ -0,0 +1,100 @@
+
+
+params->get('show_page_heading') != 0) : ?>
+
+
+
+
+lead_items)) : ?>
+
+ lead_items as &$item) : ?>
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+
+
+intro_items));
+ $counter = 0;
+?>
+intro_items)) : ?>
+ intro_items as $key => &$item) : ?>
+
+ columns) + 1;
+ $row = $counter / $this->columns;
+
+ if ($rowcount == 1) : ?>
+
+
+
+
+ item = &$item;
+ echo $this->loadTemplate('item');
+ ?>
+
+
+
+ columns) or ($counter == $introcount)) : ?>
+
+
+
+
+
+
+
+link_items)) : ?>
+
+
+ loadTemplate('links'); ?>
+
+
+
+pagination->pagesTotal) ? $this->pagination->pagesTotal : $this->pagination->get('pages.total');
+if ($this->params->def('show_pagination', 2) == 1 || ($this->params->get('show_pagination') == 2 && $pagesTotal > 1)) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/featured/default_item.php b/plugins/system/t3/base/html/com_content/featured/default_item.php
new file mode 100644
index 0000000..4b81405
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/featured/default_item.php
@@ -0,0 +1,116 @@
+item->params;
+$images = json_decode($this->item->images);
+$info = $params->get('info_block_position', 2);
+$aInfo1 = ($params->get('show_publish_date') || $params->get('show_category') || $params->get('show_parent_category') || $params->get('show_author'));
+$aInfo2 = ($params->get('show_create_date') || $params->get('show_modify_date') || $params->get('show_hits'));
+$topInfo = ($aInfo1 && $info != 1) || ($aInfo2 && $info == 0);
+$botInfo = ($aInfo1 && $info == 1) || ($aInfo2 && $info != 0);
+$icons = $params->get('access-edit') || $params->get('show_print_icon') || $params->get('show_email_icon');
+
+
+?>
+ item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+
+
+
+
+ get('show_title')) : ?>
+ $this->item, 'params' => $params, 'title-tag'=>'h2')); ?>
+
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'above')); ?>
+
+
+
+ $this->item, 'params' => $params)); ?>
+
+
+
+
+
+
+
+ get('show_intro')) : ?>
+ item->event->afterDisplayTitle; ?>
+
+
+ item->event->beforeDisplayContent; ?>
+
+ item); ?>
+
+ item->introtext; ?>
+
+
+
+
+
+ $this->item, 'params' => $params, 'position' => 'below')); ?>
+
+
+
+
+ get('show_tags', 1) && !empty($this->item->tags)) : ?>
+ item->tags->itemTags); ?>
+
+
+ get('show_readmore') && $this->item->readmore) :
+ if ($params->get('access-view')) :
+ $link = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ else :
+ $menu = JFactory::getApplication()->getMenu();
+ $active = $menu->getActive();
+ $itemId = $active->id;
+ $link1 = JRoute::_('index.php?option=com_users&view=login&Itemid=' . $itemId);
+ $returnURL = JRoute::_(ContentHelperRoute::getArticleRoute($this->item->slug, $this->item->catid));
+ $link = new JURI($link1);
+ $link->setVar('return', base64_encode($returnURL));
+ endif;
+ ?>
+
+
+
+
+
+
+ item->state == 0 || strtotime($this->item->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($this->item->publish_down) < strtotime(JFactory::getDate())) && $this->item->publish_down != '0000-00-00 00:00:00' )) : ?>
+
+
+item->event->afterDisplayContent; ?>
diff --git a/plugins/system/t3/base/html/com_content/featured/default_links.php b/plugins/system/t3/base/html/com_content/featured/default_links.php
new file mode 100644
index 0000000..f010e4b
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/featured/default_links.php
@@ -0,0 +1,19 @@
+
+
+link_items as &$item) : ?>
+
+
+ title; ?>
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/featured/index.html b/plugins/system/t3/base/html/com_content/featured/index.html
new file mode 100644
index 0000000..42682b4
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/featured/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_content/form/edit.php b/plugins/system/t3/base/html/com_content/form/edit.php
new file mode 100644
index 0000000..08a8e71
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/form/edit.php
@@ -0,0 +1,392 @@
+state->get('params');
+//$images = json_decode($this->item->images);
+//$urls = json_decode($this->item->urls);
+
+// This checks if the editor config options have ever been saved. If they haven't they will fall back to the original settings.
+$editoroptions = isset($params->show_publishing_options);
+if (!$editoroptions)
+{
+ $params->show_urls_images_frontend = '0';
+}
+
+//T3: customize
+$fieldsets = $this->form->getFieldsets('attribs');
+$extrafields = array();
+
+foreach ($fieldsets as $fieldset) {
+ if(isset($fieldset->group) && $fieldset->group == 'extrafields'){
+ $extrafields[] = $fieldset;
+ }
+}
+
+if(count($extrafields)){
+ if(is_string($this->item->attribs)){
+ $this->item->attribs = json_decode($this->item->attribs);
+ }
+ $tmp = new stdClass;
+ $tmp->attribs = $this->item->attribs;
+ $this->form->bind($tmp);
+}
+//T3: customize
+?>
+
+
+
+ get('show_page_heading', 1)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_content/icon.php b/plugins/system/t3/base/html/com_content/icon.php
new file mode 100644
index 0000000..50ea9ee
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/icon.php
@@ -0,0 +1,284 @@
+id;
+
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/new.png', JText::_('JNEW'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JNEW') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JNEW') . ' ';
+ }
+
+ // Add the button classes to the attribs array
+ if (isset($attribs['class']))
+ {
+ $attribs['class'] = $attribs['class'] . ' btn btn-primary';
+ }
+ else
+ {
+ $attribs['class'] = 'btn btn-primary';
+ }
+
+ $button = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ $output = '' . $button . ' ';
+
+ return $output;
+ }
+
+ /**
+ * Method to generate a link to the email item page for the given article
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the email item link
+ */
+ public static function email($article, $params, $attribs = array(), $legacy = false)
+ {
+ require_once JPATH_SITE . '/components/com_mailto/helpers/mailto.php';
+
+ $uri = JUri::getInstance();
+ $base = $uri->toString(array('scheme', 'host', 'port'));
+ $template = JFactory::getApplication()->getTemplate();
+ $link = $base . JRoute::_(ContentHelperRoute::getArticleRoute($article->slug, $article->catid), false);
+ $url = 'index.php?option=com_mailto&tmpl=component&template=' . $template . '&link=' . MailToHelper::addLink($link);
+
+ $status = 'width=400,height=350,menubar=yes,resizable=yes';
+
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/emailButton.png', JText::_('JGLOBAL_EMAIL'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_EMAIL');
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_EMAIL');
+ }
+
+ $attribs['title'] = JText::_('JGLOBAL_EMAIL');
+ $attribs['onclick'] = "window.open(this.href,'win2','" . $status . "'); return false;";
+
+ $output = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ return $output;
+ }
+
+ /**
+ * Display an edit icon for the article.
+ *
+ * This icon will not display in a popup window, nor if the article is trashed.
+ * Edit access checks must be performed in the calling code.
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML for the article edit icon.
+ * @since 1.6
+ */
+ public static function edit($article, $params, $attribs = array(), $legacy = false)
+ {
+ $user = JFactory::getUser();
+ $uri = JUri::getInstance();
+
+ // Ignore if in a popup window.
+ if ($params && $params->get('popup'))
+ {
+ return;
+ }
+
+ // Ignore if the state is negative (trashed).
+ if ($article->state < 0)
+ {
+ return;
+ }
+
+ JHtml::_('bootstrap.tooltip');
+
+ // Show checked_out icon if the article is checked out by a different user
+ if (property_exists($article, 'checked_out') && property_exists($article, 'checked_out_time') && $article->checked_out > 0 && $article->checked_out != $user->get('id'))
+ {
+ $checkoutUser = JFactory::getUser($article->checked_out);
+ $button = JHtml::_('image', 'system/checked_out.png', null, null, true);
+ $date = JHtml::_('date', $article->checked_out_time);
+ $tooltip = JText::_('JLIB_HTML_CHECKED_OUT') . ' :: ' . JText::sprintf('COM_CONTENT_CHECKED_OUT_BY', $checkoutUser->name) . ' ' . $date;
+
+ return '' . $button . ' ';
+ }
+
+ $url = 'index.php?option=com_content&task=article.edit&a_id=' . $article->id . '&return=' . base64_encode($uri);
+
+ if ($article->state == 0)
+ {
+ $overlib = JText::_('JUNPUBLISHED');
+ }
+ else
+ {
+ $overlib = JText::_('JPUBLISHED');
+ }
+
+ $date = JHtml::_('date', $article->created);
+ $author = $article->created_by_alias ? $article->created_by_alias : $article->author;
+
+ $overlib .= '<br />';
+ $overlib .= $date;
+ $overlib .= '<br />';
+ $overlib .= JText::sprintf('COM_CONTENT_WRITTEN_BY', htmlspecialchars($author, ENT_COMPAT, 'UTF-8'));
+
+ if ($legacy)
+ {
+ $icon = $article->state ? 'edit.png' : 'edit_unpublished.png';
+ if (strtotime($article->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($article->publish_down) < strtotime(JFactory::getDate())) && $article->publish_down != '0000-00-00 00:00:00'))
+ {
+ $icon = 'edit_unpublished.png';
+ }
+ $text = JHtml::_('image', 'system/' . $icon, JText::_('JGLOBAL_EDIT'), null, true);
+ }
+ else
+ {
+ $icon = $article->state ? 'edit' : 'eye-close';
+ if (strtotime($article->publish_up) > strtotime(JFactory::getDate())
+ || ((strtotime($article->publish_down) < strtotime(JFactory::getDate())) && $article->publish_down != '0000-00-00 00:00:00'))
+ {
+ $icon = 'eye-close';
+ }
+ $text = ' ' . JText::_('JGLOBAL_EDIT') . ' ';
+ }
+
+ $output = JHtml::_('link', JRoute::_($url), $text, $attribs);
+
+ return $output;
+ }
+
+ /**
+ * Method to generate a popup link to print an article
+ *
+ * @param object $article The article information
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the popup link
+ */
+ public static function print_popup($article, $params, $attribs = array(), $legacy = false)
+ {
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $request = $input->request;
+
+ $url = ContentHelperRoute::getArticleRoute($article->slug, $article->catid);
+ $url .= '&tmpl=component&print=1&layout=default&page=' . @ $request->limitstart;
+
+ $status = 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no';
+
+ // checks template image directory for image, if non found default are loaded
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/printButton.png', JText::_('JGLOBAL_PRINT'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_PRINT') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_PRINT');
+ }
+
+ $attribs['title'] = JText::_('JGLOBAL_PRINT');
+ $attribs['onclick'] = "window.open(this.href,'win2','" . $status . "'); return false;";
+ $attribs['rel'] = 'nofollow';
+
+ return JHtml::_('link', JRoute::_($url), $text, $attribs);
+ }
+
+ /**
+ * Method to generate a link to print an article
+ *
+ * @param object $article Not used, @deprecated for 4.0
+ * @param JRegistry $params The item parameters
+ * @param array $attribs Not used, @deprecated for 4.0
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML markup for the popup link
+ */
+ public static function print_screen($article, $params, $attribs = array(), $legacy = false)
+ {
+ // Checks template image directory for image, if none found default are loaded
+ if ($params->get('show_icons'))
+ {
+ if ($legacy)
+ {
+ $text = JHtml::_('image', 'system/printButton.png', JText::_('JGLOBAL_PRINT'), null, true);
+ }
+ else
+ {
+ $text = ' ' . JText::_('JGLOBAL_PRINT') . ' ';
+ }
+ }
+ else
+ {
+ $text = JText::_('JGLOBAL_PRINT');
+ }
+
+ return '' . $text . ' ';
+ }
+
+}
diff --git a/plugins/system/t3/base/html/com_content/index.html b/plugins/system/t3/base/html/com_content/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/com_content/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_finder/search/default_form.php b/plugins/system/t3/base/html/com_finder/search/default_form.php
new file mode 100644
index 0000000..ad5be58
--- /dev/null
+++ b/plugins/system/t3/base/html/com_finder/search/default_form.php
@@ -0,0 +1,117 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_newsfeeds/category/default_items.php b/plugins/system/t3/base/html/com_newsfeeds/category/default_items.php
new file mode 100644
index 0000000..137be81
--- /dev/null
+++ b/plugins/system/t3/base/html/com_newsfeeds/category/default_items.php
@@ -0,0 +1,93 @@
+items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_newsfeeds/category/index.html b/plugins/system/t3/base/html/com_newsfeeds/category/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_newsfeeds/category/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_newsfeeds/index.html b/plugins/system/t3/base/html/com_newsfeeds/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_newsfeeds/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_search/search/default.php b/plugins/system/t3/base/html/com_search/search/default.php
new file mode 100644
index 0000000..ece9e84
--- /dev/null
+++ b/plugins/system/t3/base/html/com_search/search/default.php
@@ -0,0 +1,30 @@
+
+
+
+params->get('show_page_heading', 1)) : ?>
+
+ escape($this->params->get('page_heading'))) :?>
+ escape($this->params->get('page_heading')); ?>
+
+ escape($this->params->get('page_title')); ?>
+
+
+
+
+loadTemplate('form'); ?>
+error == null && count($this->results) > 0) :
+ echo $this->loadTemplate('results');
+else :
+ echo $this->loadTemplate('error');
+endif; ?>
+
diff --git a/plugins/system/t3/base/html/com_search/search/default_form.php b/plugins/system/t3/base/html/com_search/search/default_form.php
new file mode 100644
index 0000000..70f3f56
--- /dev/null
+++ b/plugins/system/t3/base/html/com_search/search/default_form.php
@@ -0,0 +1,79 @@
+getUpperLimitSearchWord();
+?>
+
diff --git a/plugins/system/t3/base/html/com_search/search/default_results.php b/plugins/system/t3/base/html/com_search/search/default_results.php
new file mode 100644
index 0000000..ccfc1fc
--- /dev/null
+++ b/plugins/system/t3/base/html/com_search/search/default_results.php
@@ -0,0 +1,45 @@
+
+
+
+results as $result) : ?>
+
+ pagination->limitstart + $result->count.'. ';?>
+ href) :?>
+ browsernav == 1) :?> target="_blank">
+ escape($result->title);?>
+
+
+ escape($result->title);?>
+
+
+ section) : ?>
+
+
+ (escape($result->section); ?>)
+
+
+
+
+ text; ?>
+
+ params->get('show_date')) : ?>
+
+ created); ?>
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/index.html b/plugins/system/t3/base/html/com_users/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_users/login/default_login.php b/plugins/system/t3/base/html/com_users/login/default_login.php
new file mode 100644
index 0000000..9677a76
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/login/default_login.php
@@ -0,0 +1,112 @@
+
+
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+ params->get('logindescription_show') == 1 && str_replace(' ', '', $this->params->get('login_description')) != '') || $this->params->get('login_image') != '') : ?>
+
+
+
+ params->get('logindescription_show') == 1) : ?>
+ params->get('login_description'); ?>
+
+
+ params->get('login_image')!='')) :?>
+
+
+
+ params->get('logindescription_show') == 1 && str_replace(' ', '', $this->params->get('login_description')) != '') || $this->params->get('login_image') != '') : ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get('allowUserRegistration')) : ?>
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_users/login/default_logout.php b/plugins/system/t3/base/html/com_users/login/default_logout.php
new file mode 100644
index 0000000..da0ef30
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/login/default_logout.php
@@ -0,0 +1,46 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+ params->get('logoutdescription_show') == 1 && str_replace(' ', '', $this->params->get('logout_description')) != '')|| $this->params->get('logout_image') != '') : ?>
+
+
+
+ params->get('logoutdescription_show') == 1) : ?>
+ params->get('logout_description'); ?>
+
+
+ params->get('logout_image') != '')) :?>
+
+
+
+ params->get('logoutdescription_show') == 1 && str_replace(' ', '', $this->params->get('logout_description')) != '')|| $this->params->get('logout_image') != '') : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/login/index.html b/plugins/system/t3/base/html/com_users/login/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/login/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_users/profile/default.php b/plugins/system/t3/base/html/com_users/profile/default.php
new file mode 100644
index 0000000..451de5d
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/default.php
@@ -0,0 +1,37 @@
+
+
+id == $this->data->id) : ?>
+
+
+params->get('show_page_heading')) : ?>
+
+
+
+loadTemplate('core'); ?>
+
+loadTemplate('params'); ?>
+
+loadTemplate('custom'); ?>
+
+
diff --git a/plugins/system/t3/base/html/com_users/profile/default_core.php b/plugins/system/t3/base/html/com_users/profile/default_core.php
new file mode 100644
index 0000000..fa7013e
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/default_core.php
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+ data->name; ?>
+
+
+
+
+
+ data->username); ?>
+
+
+
+
+
+ data->registerDate); ?>
+
+
+
+
+
+ data->lastvisitDate != '0000-00-00 00:00:00'): ?>
+
+ data->lastvisitDate); ?>
+
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/profile/default_custom.php b/plugins/system/t3/base/html/com_users/profile/default_custom.php
new file mode 100644
index 0000000..4d7e3aa
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/default_custom.php
@@ -0,0 +1,47 @@
+form->getFieldsets();
+if (isset($fieldsets['core'])) unset($fieldsets['core']);
+if (isset($fieldsets['params'])) unset($fieldsets['params']);
+
+foreach ($fieldsets as $group => $fieldset): // Iterate through the form fieldsets
+ $fields = $this->form->getFieldset($group);
+ if (count($fields)):
+?>
+
+ label)):// If the fieldset has a label set, display it as the legend.?>
+ label); ?>
+
+
+ hidden) :?>
+ title; ?>
+
+ id)):?>
+ id, $field->value);?>
+ fieldname)):?>
+ fieldname, $field->value);?>
+ type)):?>
+ type, $field->value);?>
+
+ value);?>
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/profile/default_params.php b/plugins/system/t3/base/html/com_users/profile/default_params.php
new file mode 100644
index 0000000..937971b
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/default_params.php
@@ -0,0 +1,44 @@
+
+form->getFieldset('params'); ?>
+
+
+
+
+ hidden) :?>
+ title; ?>
+
+ id)):?>
+ id, $field->value);?>
+ fieldname)):?>
+ fieldname, $field->value);?>
+ type)):?>
+ type, $field->value);?>
+
+ value);?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/profile/edit.php b/plugins/system/t3/base/html/com_users/profile/edit.php
new file mode 100644
index 0000000..96f88bf
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/edit.php
@@ -0,0 +1,68 @@
+load('plg_user_profile', JPATH_ADMINISTRATOR);
+?>
+
+params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/profile/index.html b/plugins/system/t3/base/html/com_users/profile/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/profile/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_users/registration/complete.php b/plugins/system/t3/base/html/com_users/registration/complete.php
new file mode 100644
index 0000000..024c57d
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/registration/complete.php
@@ -0,0 +1,18 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/registration/default.php b/plugins/system/t3/base/html/com_users/registration/default.php
new file mode 100644
index 0000000..cdb09a2
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/registration/default.php
@@ -0,0 +1,60 @@
+
+
+params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/registration/index.html b/plugins/system/t3/base/html/com_users/registration/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/registration/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_users/remind/default.php b/plugins/system/t3/base/html/com_users/remind/default.php
new file mode 100644
index 0000000..74a23df
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/remind/default.php
@@ -0,0 +1,48 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/remind/index.html b/plugins/system/t3/base/html/com_users/remind/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/remind/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_users/reset/complete.php b/plugins/system/t3/base/html/com_users/reset/complete.php
new file mode 100644
index 0000000..02f0a88
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/reset/complete.php
@@ -0,0 +1,41 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/reset/confirm.php b/plugins/system/t3/base/html/com_users/reset/confirm.php
new file mode 100644
index 0000000..2614723
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/reset/confirm.php
@@ -0,0 +1,40 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/reset/default.php b/plugins/system/t3/base/html/com_users/reset/default.php
new file mode 100644
index 0000000..a16c372
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/reset/default.php
@@ -0,0 +1,49 @@
+
+
+ params->get('show_page_heading')) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_users/reset/index.html b/plugins/system/t3/base/html/com_users/reset/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_users/reset/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_weblinks/categories/default.php b/plugins/system/t3/base/html/com_weblinks/categories/default.php
new file mode 100644
index 0000000..aac7edd
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/categories/default.php
@@ -0,0 +1,42 @@
+
+
+params->get('show_page_heading')) : ?>
+
+
+
+params->get('show_base_description')) : ?>
+
+ params->get('categories_description')) : ?>
+
+ params->get('categories_description'), '', 'com_weblinks.categories'); ?>
+
+
+
+ parent->description) : ?>
+
+ parent->description, '', 'com_weblinks.categories'); ?>
+
+
+
+
+loadTemplate('items');
+?>
+
diff --git a/plugins/system/t3/base/html/com_weblinks/categories/default_items.php b/plugins/system/t3/base/html/com_weblinks/categories/default_items.php
new file mode 100644
index 0000000..19097cc
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/categories/default_items.php
@@ -0,0 +1,56 @@
+items[$this->parent->id]) > 0 && $this->maxLevelcat != 0) :
+?>
+
+
diff --git a/plugins/system/t3/base/html/com_weblinks/categories/index.html b/plugins/system/t3/base/html/com_weblinks/categories/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/categories/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_weblinks/category/default.php b/plugins/system/t3/base/html/com_weblinks/category/default.php
new file mode 100644
index 0000000..1dd9686
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/category/default.php
@@ -0,0 +1,45 @@
+
+
+params->get('show_page_heading')) : ?>
+
+
+params->get('show_category_title', 1)) : ?>
+
+ category->title, '', 'com_weblinks.category'); ?>
+
+
+params->get('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
+
+ params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
+
+
+ params->get('show_description') && $this->category->description) : ?>
+ category->description, '', 'com_weblinks.category'); ?>
+
+
+
+
+loadTemplate('items'); ?>
+children[$this->category->id])&& $this->maxLevel != 0) : ?>
+
+
+ loadTemplate('children'); ?>
+
+
+
diff --git a/plugins/system/t3/base/html/com_weblinks/category/default_children.php b/plugins/system/t3/base/html/com_weblinks/category/default_children.php
new file mode 100644
index 0000000..772e318
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/category/default_children.php
@@ -0,0 +1,57 @@
+children[$this->category->id]) > 0 && $this->maxLevel != 0) :
+?>
+
+item->params;
+JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html');
+JHtml::_('behavior.tooltip');
+JHtml::_('behavior.framework');
+
+// Get the user object.
+$user = JFactory::getUser();
+// Check if user is allowed to add/edit based on weblinks permissinos.
+$canEdit = $user->authorise('core.edit', 'com_weblinks');
+$canCreate = $user->authorise('core.create', 'com_weblinks');
+$canEditState = $user->authorise('core.edit.state', 'com_weblinks');
+
+$n = count($this->items);
+$listOrder = $this->escape($this->state->get('list.ordering'));
+$listDirn = $this->escape($this->state->get('list.direction'));
+?>
+
+items)) : ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_weblinks/category/index.html b/plugins/system/t3/base/html/com_weblinks/category/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/category/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/com_weblinks/form/edit.php b/plugins/system/t3/base/html/com_weblinks/form/edit.php
new file mode 100644
index 0000000..af20ec1
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/form/edit.php
@@ -0,0 +1,145 @@
+state->get('params');
+?>
+
+
+
+ params->get('show_page_heading')) : ?>
+
+ escape($this->params->get('page_heading')); ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/com_weblinks/form/index.html b/plugins/system/t3/base/html/com_weblinks/form/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/form/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/com_weblinks/index.html b/plugins/system/t3/base/html/com_weblinks/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/com_weblinks/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/index.html b/plugins/system/t3/base/html/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/index.html b/plugins/system/t3/base/html/layouts/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/associations.php b/plugins/system/t3/base/html/layouts/joomla/content/associations.php
new file mode 100644
index 0000000..b6c3695
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/associations.php
@@ -0,0 +1,22 @@
+
+
+ $item) : ?>
+
+ link; ?>
+
+
+
+params;
+$canEdit = $displayData->params->get('access-edit');
+JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html');
+JHtml::_('behavior.framework');
+?>
+
+ get('show_title') || $displayData->state == 0 || ($params->get('show_author') && !empty($displayData->author ))) : ?>
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/blog_style_default_links.php b/plugins/system/t3/base/html/layouts/joomla/content/blog_style_default_links.php
new file mode 100644
index 0000000..873e502
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/blog_style_default_links.php
@@ -0,0 +1,19 @@
+
+
+get('link_items') as $item) : ?>
+
+
+ title; ?>
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/categories_default.php b/plugins/system/t3/base/html/layouts/joomla/content/categories_default.php
new file mode 100644
index 0000000..8d2e137
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/categories_default.php
@@ -0,0 +1,34 @@
+
+
+params->get('show_page_heading')) : ?>
+
+ escape($displayData->params->get('page_heading')); ?>
+
+
+
+params->get('show_base_description')) : ?>
+
+ params->get('categories_description')) : ?>
+
+ params->get('categories_description'), '', $displayData->get('extension') . '.categories'); ?>
+
+
+
+ parent->description) : ?>
+
+ parent->description, '', $displayData->parent->extension . '.categories'); ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/categories_default_items.php b/plugins/system/t3/base/html/layouts/joomla/content/categories_default_items.php
new file mode 100644
index 0000000..d8bb18e
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/categories_default_items.php
@@ -0,0 +1,25 @@
+item;
+$items = $displayData->get('items');
+$params = $displayData->params;
+$extension = $displayData->get('extension');
+$className = substr($extension, 4);
+// This will work for the core components but not necessarily for other components
+// that may have different pluralisation rules.
+if (substr($className, -1) == 's')
+{
+ $className = rtrim($className, 's');
+}
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/category_default.php b/plugins/system/t3/base/html/layouts/joomla/content/category_default.php
new file mode 100644
index 0000000..2c2eade
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/category_default.php
@@ -0,0 +1,65 @@
+params;
+$extension = $displayData->get('category')->extension;
+$canEdit = $params->get('access-edit');
+$className = substr($extension, 4);
+// This will work for the core components but not necessarily for other components
+// that may have different pluralisation rules.
+if (substr($className, -1) == 's')
+{
+ $className = rtrim($className, 's');
+}
+$tagsData = isset($displayData->get('category')->tags) ? $displayData->get('category')->tags->itemTags : null;
+?>
+
+
+ get('show_page_heading')) : ?>
+
+ escape($params->get('page_heading')); ?>
+
+
+ get('show_category_title', 1)) : ?>
+
+ get('category')->title, '', $extension.'.category.title'); ?>
+
+
+ get('show_tags', 1)) : ?>
+
+
+ get('show_description', 1) || $params->def('show_description_image', 1)) : ?>
+
+ get('show_description_image') && $displayData->get('category')->getParams()->get('image')) : ?>
+
+
+ get('show_description') && $displayData->get('category')->description) : ?>
+ get('category')->description, '', $extension .'.category'); ?>
+
+
+
+
+ loadTemplate($displayData->subtemplatename); ?>
+
+ get('children') && $displayData->maxLevel != 0) : ?>
+
+
+
+
+
+ loadTemplate('children'); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/fulltext_image.php b/plugins/system/t3/base/html/layouts/joomla/content/fulltext_image.php
new file mode 100644
index 0000000..4358a26
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/fulltext_image.php
@@ -0,0 +1,27 @@
+images);
+if (empty($images->image_fulltext)) return ;
+
+$imgfloat = (empty($images->float_fulltext)) ? $params->get('float_fulltext') : $images->float_fulltext;
+?>
+
+
+
image_fulltext_caption): ?>
+ image_fulltext_caption) . '"'; ?>
+
+ src="image_fulltext); ?>"
+ alt="image_fulltext_alt); ?>" itemprop="image"/>
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/icons.php b/plugins/system/t3/base/html/layouts/joomla/content/icons.php
new file mode 100644
index 0000000..3161b6d
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/icons.php
@@ -0,0 +1,42 @@
+get('access-edit');
+
+?>
+
+
+
+ get('show_print_icon') || $displayData['params']->get('show_email_icon')) : ?>
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/index.html b/plugins/system/t3/base/html/layouts/joomla/content/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/author.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/author.php
new file mode 100644
index 0000000..93c3e6f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/author.php
@@ -0,0 +1,23 @@
+created_by_alias ? $item->created_by_alias : $item->author);
+$author = '' . $author . ' ';
+?>
+
+
+
+ contact_link ) && $displayData['params']->get('link_author') == true) : ?>
+ contact_link, $author, array('itemprop' => 'url')); ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/block.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/block.php
new file mode 100644
index 0000000..d7fd875
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/block.php
@@ -0,0 +1,60 @@
+get('info_block_position', 2);
+?>
+
+
+
+
+
+
+ get('info_block_show_title', 1)) : ?>
+
+
+
+
+ get('show_author') && !empty($displayData['item']->author )) : ?>
+
+
+
+ get('show_parent_category') && !empty($displayData['item']->parent_slug)) : ?>
+
+
+
+ get('show_category')) : ?>
+
+
+
+ get('show_publish_date')) : ?>
+
+
+
+
+
+ get('show_create_date')) : ?>
+
+
+
+ get('show_modify_date')) : ?>
+
+
+
+ get('show_hits')) : ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/category.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/category.php
new file mode 100644
index 0000000..6a0e262
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/category.php
@@ -0,0 +1,24 @@
+escape($item->category_title);
+if (!isset($item->catslug)) {
+ $item->catslug = $item->category_alias ? ($item->catid.':'.$item->category_alias) : $item->catid;
+}
+?>
+
+
+ get('link_category') && $item->catslug) : ?>
+ catslug)), ''.$title.' '); ?>
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/create_date.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/create_date.php
new file mode 100644
index 0000000..4c22c05
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/create_date.php
@@ -0,0 +1,18 @@
+
+
+
+
+ created, JText::_('DATE_FORMAT_LC3'))); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/hits.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/hits.php
new file mode 100644
index 0000000..40f486a
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/hits.php
@@ -0,0 +1,17 @@
+
+
+
+
+ hits); ?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/index.html b/plugins/system/t3/base/html/layouts/joomla/content/info_block/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/modify_date.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/modify_date.php
new file mode 100644
index 0000000..91f276f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/modify_date.php
@@ -0,0 +1,18 @@
+
+
+
+
+ modified, JText::_('DATE_FORMAT_LC3'))); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/parent_category.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/parent_category.php
new file mode 100644
index 0000000..545c7be
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/parent_category.php
@@ -0,0 +1,23 @@
+escape($item->parent_title);
+?>
+
+
+ get('link_parent_category') && !empty($item->parent_slug)) : ?>
+ parent_slug)), ''.$title.' '); ?>
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/info_block/publish_date.php b/plugins/system/t3/base/html/layouts/joomla/content/info_block/publish_date.php
new file mode 100644
index 0000000..704fda5
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/info_block/publish_date.php
@@ -0,0 +1,17 @@
+
+
+
+
+ publish_up, JText::_('DATE_FORMAT_LC3')); ?>
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/intro_image.php b/plugins/system/t3/base/html/layouts/joomla/content/intro_image.php
new file mode 100644
index 0000000..c9d32c1
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/intro_image.php
@@ -0,0 +1,21 @@
+params;
+?>
+images); ?>
+image_intro) && !empty($images->image_intro)) : ?>
+ float_intro)) ? $params->get('float_intro') : $images->float_intro; ?>
+ image_intro_caption):
+ echo 'class="caption"' . ' title="' . htmlspecialchars($images->image_intro_caption) . '"';
+ endif; ?>
+ src="image_intro); ?>" alt="image_intro_alt); ?>" itemprop="thumbnailUrl"/>
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/item_title.php b/plugins/system/t3/base/html/layouts/joomla/content/item_title.php
new file mode 100644
index 0000000..4510e3c
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/item_title.php
@@ -0,0 +1,45 @@
+get('access-edit');
+if (empty ($item->catslug)) {
+ $item->catslug = $item->category_alias ? ($item->catid.':'.$item->category_alias) : $item->catid;
+}
+$url = JRoute::_(ContentHelperRoute::getArticleRoute($item->slug, $item->catslug));
+$uri = JUri::getInstance();
+$prefix = $uri->toString(array('scheme', 'host', 'port'));
+?>
+
+
+ < class="article-title" itemprop="name">
+ get('link_titles')) : ?>
+
+ escape($item->title); ?>
+
+ escape($item->title); ?>
+
+
+ >
+
+ state == 0) : ?>
+
+
+ publish_up) > strtotime(JFactory::getDate())) : ?>
+
+
+ publish_down) < strtotime(JFactory::getDate())) && $item->publish_down != '0000-00-00 00:00:00') : ?>
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/options_default.php b/plugins/system/t3/base/html/layouts/joomla/content/options_default.php
new file mode 100644
index 0000000..c80ac8e
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/options_default.php
@@ -0,0 +1,50 @@
+
+
+ name ?>
+ description)): ?>
+ description; ?>
+
+ fieldsname);
+ foreach($fieldsnames as $fieldname)
+ {
+ foreach ($displayData->form->getFieldset($fieldname) as $field)
+ {
+ $classnames = 'control-group';
+ $rel = '';
+ $showon = $displayData->form->getFieldAttribute($field->fieldname, 'showon');
+ if (!empty($showon))
+ {
+ JHtml::_('jquery.framework');
+ JHtml::_('script', 'jui/cms.js', false, true);
+
+ $id = $displayData->form->getFormControl();
+ $showon = explode(':', $showon, 2);
+ $classnames .= ' showon_' . implode(' showon_', explode(',', $showon[1]));
+ $rel = ' rel="showon_' . $id . '['. $showon[0] . ']"';
+ }
+ ?>
+ >
+ showlabel) || $displayData->showlabel): ?>
+
label; ?>
+
+
input; ?>
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/content/tags.php b/plugins/system/t3/base/html/layouts/joomla/content/tags.php
new file mode 100644
index 0000000..8b06229
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/content/tags.php
@@ -0,0 +1,29 @@
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/associations.php b/plugins/system/t3/base/html/layouts/joomla/edit/associations.php
new file mode 100644
index 0000000..b8facc1
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/associations.php
@@ -0,0 +1,13 @@
+getForm()->renderFieldset('item_associations');
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/details.php b/plugins/system/t3/base/html/layouts/joomla/edit/details.php
new file mode 100644
index 0000000..27cec29
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/details.php
@@ -0,0 +1,104 @@
+getForm()->getValue('title');
+$published = $displayData->getForm()->getField('published');
+$saveHistory = $displayData->get('state')->get('params')->get('save_history', 0);
+?>
+
+
+
+
+
+
+
+ getForm()->getValue('name'); ?>
+
+
+
+
+
+ getForm()->getValue('title'); ?>
+
+
+
+
+
+
+ getForm()->getLabel('published'); ?>
+
+
+ getForm()->getInput('published'); ?>
+
+
+
+
+
+ getForm()->getLabel('state'); ?>
+
+
+ getForm()->getInput('state'); ?>
+
+
+
+
+
+ getForm()->getLabel('access'); ?>
+
+
+ getForm()->getInput('access'); ?>
+
+
+
+
+ getForm()->getLabel('featured'); ?>
+
+
+ getForm()->getInput('featured'); ?>
+
+
+
+
+
+ getForm()->getLabel('language'); ?>
+
+
+ getForm()->getInput('language'); ?>
+
+
+
+
+
+
+
+ getForm()->getLabel('tags'); ?>
+
+
+ getForm()->getInput('tags'); ?>
+
+
+
+
+
+ getForm()->getLabel('version_note'); ?>
+
+
+ getForm()->getInput('version_note'); ?>
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/fieldset.php b/plugins/system/t3/base/html/layouts/joomla/edit/fieldset.php
new file mode 100644
index 0000000..03e96e6
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/fieldset.php
@@ -0,0 +1,68 @@
+getForm();
+
+$name = $displayData->get('fieldset');
+$fieldSet = $form->getFieldset($name);
+
+if (empty($fieldSet))
+{
+ return;
+}
+
+$ignoreFields = $displayData->get('ignore_fields') ? : array();
+$extraFields = $displayData->get('extra_fields') ? : array();
+
+if ($displayData->get('show_options', 1))
+{
+ if (isset($fieldSet->description) && trim($fieldSet->description))
+ {
+ echo '' . $this->escape(JText::_($fieldSet->description)) . '
';
+ }
+
+ if (isset($extraFields[$name]))
+ {
+ foreach ($extraFields[$name] as $f)
+ {
+ if (in_array($f, $ignoreFields))
+ {
+ continue;
+ }
+ if ($form->getField($f))
+ {
+ $fieldSet[] = $form->getField($f);
+ }
+ }
+ }
+
+ $html = array();
+
+ foreach ($fieldSet as $field)
+ {
+ $html[] = $field->renderField();
+ }
+
+ echo implode('', $html);
+}
+else
+{
+ $html = array();
+ $html[] = '';
+ foreach ($fieldSet as $field)
+ {
+ $html[] = $field->input;
+ }
+ $html[] = '
';
+
+ echo implode('', $html);
+}
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/frontediting_modules.php b/plugins/system/t3/base/html/layouts/joomla/edit/frontediting_modules.php
new file mode 100644
index 0000000..5387a7c
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/frontediting_modules.php
@@ -0,0 +1,61 @@
+]*class="[^"]* jmoddiv"/', $moduleHtml))
+{
+ // Module has already module edit button:
+ return;
+}
+
+// Add css class jmoddiv and data attributes for module-editing URL and for the tooltip:
+$editUrl = JUri::base() . 'administrator/index.php?option=com_modules&view=module&layout=edit&id=' . (int) $mod->id;
+
+// Add class, editing URL and tooltip, and if module of type menu, also the tooltip for editing the menu item:
+$count = 0;
+$moduleHtml = preg_replace(
+ // Replace first tag of module with a class
+ '/^(\s*<(?:div|span|nav|ul|ol|h\d) [^>]*class="[^"]*)"/',
+ // By itself, adding class jmoddiv and data attributes for the url and tooltip:
+ '\\1 jmoddiv" data-jmodediturl="' . $editUrl . '" data-jmodtip="'
+ . T3J::tooltipText(
+ JText::_('JLIB_HTML_EDIT_MODULE'),
+ htmlspecialchars($mod->title) . ' ' . sprintf(JText::_('JLIB_HTML_EDIT_MODULE_IN_POSITION'), htmlspecialchars($position)),
+ 0
+ )
+ . '"'
+ // And if menu editing is enabled and allowed and it's a menu module, add data attributes for menu editing:
+ . ($menusEditing && $mod->module == 'mod_menu' ?
+ '" data-jmenuedittip="' . T3J::tooltipText('JLIB_HTML_EDIT_MENU_ITEM', 'JLIB_HTML_EDIT_MENU_ITEM_ID') . '"'
+ :
+ ''
+ ),
+ $moduleHtml,
+ 1,
+ $count
+);
+
+if ($count)
+{
+ // Load once booststrap tooltip and add stylesheet and javascript to head:
+ JHtml::_('bootstrap.tooltip');
+ JHtml::_('bootstrap.popover');
+
+ JHtml::_('stylesheet', 'system/frontediting.css', array(), true);
+ JHtml::_('script', 'system/frontediting.js', false, true);
+}
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/global.php b/plugins/system/t3/base/html/layouts/joomla/edit/global.php
new file mode 100644
index 0000000..6df535b
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/global.php
@@ -0,0 +1,72 @@
+getForm();
+$input = $app->input;
+$component = $input->getCmd('option', 'com_content');
+if ($component == 'com_categories')
+{
+ $extension = $input->getCmd('extension', 'com_content');
+ $parts = explode('.', $extension);
+ $component = $parts[0];
+}
+$saveHistory = JComponentHelper::getParams($component)->get('save_history', 0);
+
+$fields = $displayData->get('fields') ?: array(
+ array('category', 'catid'),
+ array('parent', 'parent_id'),
+ 'tags',
+ array('published', 'state', 'enabled'),
+ 'featured',
+ 'sticky',
+ 'access',
+ 'language',
+ 'note',
+ 'version_note'
+);
+
+$hiddenFields = $displayData->get('hidden_fields') ?: array();
+
+// Multilanguage check:
+/*if (!JLanguageMultilang::isEnabled())
+{
+ $hiddenFields[] = 'language';
+}*/
+if (!$saveHistory)
+{
+ $hiddenFields[] = 'version_note';
+}
+
+$html = array();
+$html[] = '';
+
+foreach ($fields as $field)
+{
+ $field = is_array($field) ? $field : array($field);
+ foreach ($field as $f)
+ {
+ if ($form->getField($f))
+ {
+ if (in_array($f, $hiddenFields))
+ {
+ $form->setFieldAttribute($f, 'type', 'hidden');
+ }
+
+ $html[] = $form->renderField($f);
+ break;
+ }
+ }
+}
+
+$html[] = ' ';
+
+echo implode('', $html);
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/index.html b/plugins/system/t3/base/html/layouts/joomla/edit/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/item_title.php b/plugins/system/t3/base/html/layouts/joomla/edit/item_title.php
new file mode 100644
index 0000000..1930253
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/item_title.php
@@ -0,0 +1,24 @@
+getForm()->getValue('title');
+$name = $displayData->getForm()->getValue('name');
+
+?>
+
+
+
+
+
+
+
+getForm();
+
+// JLayout for standard handling of metadata fields in the administrator content edit screens.
+$fieldSets = $form->getFieldsets('metadata');
+?>
+
+ $fieldSet) : ?>
+ description) && trim($fieldSet->description)) : ?>
+ escape(JText::_($fieldSet->description)); ?>
+
+
+ renderField('metadesc');
+ echo $form->renderField('metakey');
+ echo $form->renderField('xreference');
+ }
+
+ foreach ($form->getFieldset($name) as $field)
+ {
+ if ($field->name != 'jform[metadata][tags][]')
+ {
+ echo $field->renderField();
+ }
+ } ?>
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/params.php b/plugins/system/t3/base/html/layouts/joomla/edit/params.php
new file mode 100644
index 0000000..c62bd98
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/params.php
@@ -0,0 +1,98 @@
+getForm();
+
+$fieldSets = $form->getFieldsets('params');
+if (empty($fieldSets))
+{
+ $fieldSets = $form->getFieldsets('attribs');
+}
+
+if (empty($fieldSets))
+{
+ return;
+}
+
+$ignoreFieldsets = $displayData->get('ignore_fieldsets') ?: array();
+$ignoreFields = $displayData->get('ignore_fields') ?: array();
+$extraFields = $displayData->get('extra_fields') ?: array();
+
+if (!empty($displayData->hiddenFieldsets))
+{
+ // These are required to preserve data on save when fields are not displayed.
+ $hiddenFieldsets = $displayData->hiddenFieldsets ?: array();
+}
+
+if (!empty($displayData->configFieldsets))
+{
+ // These are required to configure showing and hiding fields in the editor.
+ $configFieldsets = $displayData->configFieldsets ?: array();
+}
+
+if ($displayData->get('show_options', 1))
+{
+ foreach ($fieldSets as $name => $fieldSet)
+ {
+ // Ensure any fieldsets we don't want to show are skipped (including repeating formfield fieldsets)
+ if (in_array($name, $ignoreFieldsets) || (!empty($configFieldsets) && in_array($name, $configFieldsets))
+ || !empty($hiddenFieldsets) && in_array($name, $hiddenFieldsets)
+ || (isset($fieldSet->repeat) && $fieldSet->repeat == true))
+ {
+ continue;
+ }
+
+ if (!empty($fieldSet->label))
+ {
+ $label = JText::_($fieldSet->label, true);
+ }
+ else
+ {
+ $label = strtoupper('JGLOBAL_FIELDSET_' . $name);
+ if (JText::_($label, true) == $label)
+ {
+ $label = strtoupper($app->input->get('option') . '_' . $name . '_FIELDSET_LABEL');
+ }
+ $label = JText::_($label, true);
+ }
+
+ echo JHtml::_('bootstrap.addTab', 'myTab', 'attrib-' . $name, $label);
+
+ $displayData->fieldset = $name;
+ echo JLayoutHelper::render('joomla.edit.fieldset', $displayData);
+
+ echo JHtml::_('bootstrap.endTab');
+ }
+}
+else
+{
+ $html = array();
+ $html[] = '';
+ foreach ($fieldSets as $name => $fieldSet)
+ {
+ if (in_array($name, $ignoreFieldsets))
+ {
+ continue;
+ }
+
+ if (in_array($name, $hiddenFieldsets))
+ {
+ foreach ($form->getFieldset($name) as $field)
+ {
+ echo $field->input;
+ }
+ }
+ }
+ $html[] = '
';
+
+ echo implode('', $html);
+}
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/publishingdata.php b/plugins/system/t3/base/html/layouts/joomla/edit/publishingdata.php
new file mode 100644
index 0000000..40e8441
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/publishingdata.php
@@ -0,0 +1,46 @@
+getForm();
+
+$fields = $displayData->get('fields') ?: array(
+ 'publish_up',
+ 'publish_down',
+ array('created', 'created_time'),
+ array('created_by', 'created_user_id'),
+ 'created_by_alias',
+ array('modified', 'modified_time'),
+ array('modified_by', 'modified_user_id'),
+ 'version',
+ 'hits',
+ 'id'
+);
+
+$hiddenFields = $displayData->get('hidden_fields') ?: array();
+
+foreach ($fields as $field)
+{
+ $field = is_array($field) ? $field : array($field);
+ foreach ($field as $f)
+ {
+ if ($form->getField($f))
+ {
+ if (in_array($f, $hiddenFields))
+ {
+ $form->setFieldAttribute($f, 'type', 'hidden');
+ }
+
+ echo $form->renderField($f);
+ break;
+ }
+ }
+}
diff --git a/plugins/system/t3/base/html/layouts/joomla/edit/title_alias.php b/plugins/system/t3/base/html/layouts/joomla/edit/title_alias.php
new file mode 100644
index 0000000..da19d5d
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/edit/title_alias.php
@@ -0,0 +1,22 @@
+getForm();
+
+$title = $form->getField('title') ? 'title' : ($form->getField('name') ? 'name' : '');
+
+?>
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/editors/buttons.php b/plugins/system/t3/base/html/layouts/joomla/editors/buttons.php
new file mode 100644
index 0000000..fa32b1c
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/editors/buttons.php
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/editors/buttons/button.php b/plugins/system/t3/base/html/layouts/joomla/editors/buttons/button.php
new file mode 100644
index 0000000..7d9d024
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/editors/buttons/button.php
@@ -0,0 +1,26 @@
+
+get('name')) : ?>
+ get('class')) ? $button->get('class') : null;
+ $class .= ($button->get('modal')) ? ' modal-button' : null;
+ $href = ($button->get('link')) ? ' href="' . JUri::base() . $button->get('link') . '"' : null;
+ $onclick = ($button->get('onclick')) ? ' onclick="' . $button->get('onclick') . '"' : ' onclick="IeCursorFix(); return false;"';
+ $title = ($button->get('title')) ? $button->get('title') : $button->get('text');
+ ?>
+ rel="get('options'); ?>">
+ get('text'); ?>
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/editors/index.html b/plugins/system/t3/base/html/layouts/joomla/editors/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/editors/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/form/index.html b/plugins/system/t3/base/html/layouts/joomla/form/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/form/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/form/renderfield.php b/plugins/system/t3/base/html/layouts/joomla/form/renderfield.php
new file mode 100644
index 0000000..c36c34e
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/form/renderfield.php
@@ -0,0 +1,35 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/index.html b/plugins/system/t3/base/html/layouts/joomla/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/groupclose.php b/plugins/system/t3/base/html/layouts/joomla/links/groupclose.php
new file mode 100644
index 0000000..1f2eb2b
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/groupclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/groupopen.php b/plugins/system/t3/base/html/layouts/joomla/links/groupopen.php
new file mode 100644
index 0000000..d51482c
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/groupopen.php
@@ -0,0 +1,13 @@
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/groupsclose.php b/plugins/system/t3/base/html/layouts/joomla/links/groupsclose.php
new file mode 100644
index 0000000..1f8eb24
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/groupsclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/groupseparator.php b/plugins/system/t3/base/html/layouts/joomla/links/groupseparator.php
new file mode 100644
index 0000000..f661627
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/groupseparator.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/groupsopen.php b/plugins/system/t3/base/html/layouts/joomla/links/groupsopen.php
new file mode 100644
index 0000000..5a74c90
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/groupsopen.php
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/index.html b/plugins/system/t3/base/html/layouts/joomla/links/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/links/link.php b/plugins/system/t3/base/html/layouts/joomla/links/link.php
new file mode 100644
index 0000000..402a2cd
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/links/link.php
@@ -0,0 +1,23 @@
+escape($displayData['title']) . '"');
+$text = empty($displayData['text']) ? '' : ('
' . $displayData['text'] . ' ')
+
+?>
+
>
+ >
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/pagination/index.html b/plugins/system/t3/base/html/layouts/joomla/pagination/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/pagination/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/pagination/link.php b/plugins/system/t3/base/html/layouts/joomla/pagination/link.php
new file mode 100644
index 0000000..bee0caf
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/pagination/link.php
@@ -0,0 +1,88 @@
+text;
+
+switch ((string) $item->text)
+{
+ // Check for "Start" item
+ case JText::_('JLIB_HTML_START') :
+ $icon = "icon-backward";
+ break;
+
+ // Check for "Prev" item
+ case $item->text == JText::_('JPREV') :
+ $item->text = JText::_('JPREVIOUS');
+ $icon = "icon-step-backward";
+ break;
+
+ // Check for "Next" item
+ case JText::_('JNEXT') :
+ $icon = "icon-step-forward";
+ break;
+
+ // Check for "End" item
+ case JText::_('JLIB_HTML_END') :
+ $icon = "icon-forward";
+ break;
+
+ default:
+ $icon = null;
+ break;
+}
+
+if ($icon !== null)
+{
+ $display = '
';
+}
+
+if ($displayData['active'])
+{
+ if ($item->base > 0)
+ {
+ $limit = 'limitstart.value=' . $item->base;
+ }
+ else
+ {
+ $limit = 'limitstart.value=0';
+ }
+
+ $cssClasses = array();
+
+ $title = '';
+
+ if (!is_numeric($item->text))
+ {
+ JHtml::_('bootstrap.tooltip');
+ $cssClasses[] = 'hasTooltip';
+ $title = ' title="' . $item->text . '" ';
+ }
+
+ $onClick = 'document.adminForm.' . $item->prefix . 'limitstart.value=' . ($item->base > 0 ? $item->base : '0') . '; Joomla.submitform();return false;';
+}
+else
+{
+ $class = (property_exists($item, 'active') && $item->active) ? 'active' : 'disabled';
+}
+?>
+
+
+ href="#" onclick="">
+
+
+
+
+
+
+
+get('showLimitBox', true);
+$showPagesLinks = $options->get('showPagesLinks', true);
+$showLimitStart = $options->get('showLimitStart', true);
+
+// Calculate to display range of pages
+$currentPage = 1;
+$range = 1;
+$step = 5;
+
+if (!empty($pages['pages']))
+{
+ foreach ($pages['pages'] as $k => $page)
+ {
+ if (!$page['active'])
+ {
+ $currentPage = $k;
+ }
+ }
+}
+
+if ($currentPage >= $step)
+{
+ if ($currentPage % $step == 0)
+ {
+ $range = ceil($currentPage / $step) + 1;
+ }
+ else
+ {
+ $range = ceil($currentPage / $step);
+ }
+}
+?>
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/quickicons/icon.php b/plugins/system/t3/base/html/layouts/joomla/quickicons/icon.php
new file mode 100644
index 0000000..caae785
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/quickicons/icon.php
@@ -0,0 +1,25 @@
+escape($displayData['title']) . '"');
+$text = empty($displayData['text']) ? '' : ('
' . $displayData['text'] . ' ')
+
+?>
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/quickicons/index.html b/plugins/system/t3/base/html/layouts/joomla/quickicons/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/quickicons/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/default.php b/plugins/system/t3/base/html/layouts/joomla/searchtools/default.php
new file mode 100644
index 0000000..4082d26
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/default.php
@@ -0,0 +1,46 @@
+ isset($data['options']['filtersHidden']) ? $data['options']['filtersHidden'] : empty($data['view']->activeFilters),
+ 'defaultLimit' => isset($data['options']['defaultLimit']) ? $data['options']['defaultLimit'] : JFactory::getApplication()->getCfg('list_limit', 20),
+ 'searchFieldSelector' => '#filter_search',
+ 'orderFieldSelector' => '#list_fullordering'
+);
+
+$data['options'] = array_unique(array_merge($customOptions, $data['options']));
+
+$formSelector = !empty($data['options']['formSelector']) ? $data['options']['formSelector'] : '#adminForm';
+
+// Load search tools
+JHtml::_('searchtools.form', $formSelector, $data['options']);
+
+?>
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/default/bar.php b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/bar.php
new file mode 100644
index 0000000..2bb11b6
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/bar.php
@@ -0,0 +1,53 @@
+get('filterButton', true);
+$searchButton = $data['options']->get('searchButton', true);
+
+$filters = $data['view']->filterForm->getGroup('filter');
+?>
+
+
+
+
+
+
+
+ input; ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+filterForm->getGroup('filter');
+?>
+
+ $field) : ?>
+
+
+ input; ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/default/index.html b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/default/list.php b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/list.php
new file mode 100644
index 0000000..5350f6d
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/default/list.php
@@ -0,0 +1,25 @@
+filterForm->getGroup('list');
+?>
+
+
+ $field) : ?>
+
+ input; ?>
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/index.html b/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/sort.php b/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/sort.php
new file mode 100644
index 0000000..2e0f4bd
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/grid/sort.php
@@ -0,0 +1,27 @@
+tip ? $data->tip : $data->title), JText::_('JGLOBAL_CLICK_TO_SORT_THIS_COLUMN'), 0);
+JHtml::_('bootstrap.tooltip');
+?>
+
+ icon)) : ?>
+
+
+ title)) : ?>
+ title); ?>
+
+ order == $data->selected) : ?>
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/searchtools/index.html b/plugins/system/t3/base/html/layouts/joomla/searchtools/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/searchtools/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/sidebars/index.html b/plugins/system/t3/base/html/layouts/joomla/sidebars/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/sidebars/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/sidebars/submenu.php b/plugins/system/t3/base/html/layouts/joomla/sidebars/submenu.php
new file mode 100644
index 0000000..99088f9
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/sidebars/submenu.php
@@ -0,0 +1,55 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/system/index.html b/plugins/system/t3/base/html/layouts/joomla/system/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/system/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/system/message.php b/plugins/system/t3/base/html/layouts/joomla/system/message.php
new file mode 100644
index 0000000..8d5178e
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/system/message.php
@@ -0,0 +1,35 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons.php b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons.php
new file mode 100644
index 0000000..4855d18
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons.php
@@ -0,0 +1,15 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/button.php b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/button.php
new file mode 100644
index 0000000..9ff8ce6
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/button.php
@@ -0,0 +1,15 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/index.html b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/buttons/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/index.html b/plugins/system/t3/base/html/layouts/joomla/tinymce/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/textarea.php b/plugins/system/t3/base/html/layouts/joomla/tinymce/textarea.php
new file mode 100644
index 0000000..d91cb79
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/textarea.php
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/tinymce/togglebutton.php b/plugins/system/t3/base/html/layouts/joomla/tinymce/togglebutton.php
new file mode 100644
index 0000000..f15b359
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/tinymce/togglebutton.php
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/base.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/base.php
new file mode 100644
index 0000000..1f0bb5d
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/base.php
@@ -0,0 +1,14 @@
+
+
>
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/batch.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/batch.php
new file mode 100644
index 0000000..65fd2d6
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/batch.php
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/confirm.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/confirm.php
new file mode 100644
index 0000000..cc63357
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/confirm.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/containerclose.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/containerclose.php
new file mode 100644
index 0000000..1f8eb24
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/containerclose.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/containeropen.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/containeropen.php
new file mode 100644
index 0000000..196ecae
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/containeropen.php
@@ -0,0 +1,12 @@
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/help.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/help.php
new file mode 100644
index 0000000..5c377c5
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/help.php
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/iconclass.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/iconclass.php
new file mode 100644
index 0000000..9785851
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/iconclass.php
@@ -0,0 +1,12 @@
+
+icon-
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/index.html b/plugins/system/t3/base/html/layouts/joomla/toolbar/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/link.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/link.php
new file mode 100644
index 0000000..eba13cc
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/link.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/popup.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/popup.php
new file mode 100644
index 0000000..5c76d9b
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/popup.php
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/separator.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/separator.php
new file mode 100644
index 0000000..e8bbb4c
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/separator.php
@@ -0,0 +1,16 @@
+
+
>
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/slider.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/slider.php
new file mode 100644
index 0000000..a639f9a
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/slider.php
@@ -0,0 +1,21 @@
+
+
>
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/standard.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/standard.php
new file mode 100644
index 0000000..8f5a0f5
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/standard.php
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/title.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/title.php
new file mode 100644
index 0000000..b1e24e8
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/title.php
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/joomla/toolbar/versions.php b/plugins/system/t3/base/html/layouts/joomla/toolbar/versions.php
new file mode 100644
index 0000000..6add897
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/joomla/toolbar/versions.php
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtab.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtab.php
new file mode 100644
index 0000000..1412206
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtab.php
@@ -0,0 +1,17 @@
+
+
+
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtabscript.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtabscript.php
new file mode 100644
index 0000000..1fe41eb
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/addtabscript.php
@@ -0,0 +1,24 @@
+
" . $title . " ');
+ $('#" . $selector . "Tabs').append(tab);
+ });
+ })(jQuery);";
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtab.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtab.php
new file mode 100644
index 0000000..370f8ce
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtab.php
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtabset.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtabset.php
new file mode 100644
index 0000000..370f8ce
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/endtabset.php
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/index.html b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabset.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabset.php
new file mode 100644
index 0000000..50d8963
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabset.php
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php
new file mode 100644
index 0000000..238cdd7
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/html/bootstrap/starttabsetscript.php
@@ -0,0 +1,20 @@
+
diff --git a/plugins/system/t3/base/html/layouts/libraries/cms/index.html b/plugins/system/t3/base/html/layouts/libraries/cms/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/cms/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/layouts/libraries/index.html b/plugins/system/t3/base/html/layouts/libraries/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/layouts/libraries/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/mod_breadcrumbs/default.php b/plugins/system/t3/base/html/mod_breadcrumbs/default.php
new file mode 100644
index 0000000..7850aba
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_breadcrumbs/default.php
@@ -0,0 +1,71 @@
+
+
+
+ get('showHere', 1)) {
+ echo '' . JText::_('MOD_BREADCRUMBS_HERE') . ' ';
+ } else {
+ echo ' ';
+ }
+
+ // Get rid of duplicated entries on trail including home page when using multilanguage
+ for ($i = 0; $i < $count; $i++)
+ {
+ if ($i == 1 && !empty($list[$i]->link) && !empty($list[$i - 1]->link) && $list[$i]->link == $list[$i - 1]->link)
+ {
+ unset($list[$i]);
+ }
+ }
+ // Find last and penultimate items in breadcrumbs list
+ end($list);
+ $last_item_key = key($list);
+ prev($list);
+ $penult_item_key = key($list);
+
+ // Generate the trail
+ foreach ($list as $key => $item) :
+ // Make a link if not the last item in the breadcrumbs
+ $show_last = $params->get('showLast', 1);
+ if ($key != $last_item_key)
+ {
+ // Render all but last item - along with separator
+ echo '';
+ if (!empty($item->link))
+ {
+ echo '' . $item->name . ' ';
+ }
+ else
+ {
+ echo '' . $item->name . ' ';
+ }
+
+ if (($key != $penult_item_key) || $show_last)
+ {
+ echo '' . $separator . ' ';
+ }
+
+ echo ' ';
+ }
+ elseif ($show_last)
+ {
+ // Render last item if reqd.
+ echo '';
+ echo '' . $item->name . ' ';
+ echo ' ';
+ }
+ endforeach; ?>
+
diff --git a/plugins/system/t3/base/html/mod_breadcrumbs/index.html b/plugins/system/t3/base/html/mod_breadcrumbs/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_breadcrumbs/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/mod_footer/default.php b/plugins/system/t3/base/html/mod_footer/default.php
new file mode 100644
index 0000000..ccc25f1
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_footer/default.php
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/mod_footer/index.html b/plugins/system/t3/base/html/mod_footer/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_footer/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/mod_login/default.php b/plugins/system/t3/base/html/mod_login/default.php
new file mode 100644
index 0000000..d7a1ae6
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_login/default.php
@@ -0,0 +1,140 @@
+
+
+
+
+
+
diff --git a/plugins/system/t3/base/html/mod_login/index.html b/plugins/system/t3/base/html/mod_login/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_login/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/base/html/mod_menu/default.php b/plugins/system/t3/base/html/mod_menu/default.php
new file mode 100644
index 0000000..7d7b13a
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_menu/default.php
@@ -0,0 +1,90 @@
+
+
+
get('tag_id') != null)
+ {
+ $tag = $params->get('tag_id').'';
+ echo ' id="'.$tag.'"';
+ }
+?>>
+ &$item) :
+ $class = 'item-'.$item->id;
+ if ($item->id == $active_id) {
+ $class .= ' current';
+ }
+
+ if (in_array($item->id, $path)) {
+ $class .= ' active';
+ }
+ elseif ($item->type == 'alias') {
+ $aliasToId = $item->params->get('aliasoptions');
+ if (count($path) > 0 && $aliasToId == $path[count($path)-1]) {
+ $class .= ' active';
+ }
+ elseif (in_array($aliasToId, $path)) {
+ $class .= ' alias-parent-active';
+ }
+ }
+
+ if ($item->deeper) {
+ if ($item->level > 1){
+ $class .= ' dropdown-submenu';
+ } else {
+ $class .= ' deeper dropdown';
+ }
+ }
+
+ if ($item->parent) {
+ $class .= ' parent';
+ }
+
+ if (!empty($class)) {
+ $class = ' class="'.trim($class) .'"';
+ }
+
+ echo '';
+
+ // Render the menu item.
+ switch ($item->type) :
+ case 'separator':
+ case 'url':
+ case 'component':
+ case 'heading':
+ require JModuleHelper::getLayoutPath('mod_menu', 'default_'.$item->type);
+ break;
+
+ default:
+ require JModuleHelper::getLayoutPath('mod_menu', 'default_url');
+ break;
+ endswitch;
+
+ // The next item is deeper.
+ if ($item->deeper) {
+ echo ' ';
+ echo str_repeat(' ', $item->level_diff);
+ }
+ // The next item is on the same level.
+ else {
+ echo '';
+ }
+ endforeach;
+endif;
+?>
diff --git a/plugins/system/t3/base/html/mod_menu/default_component.php b/plugins/system/t3/base/html/mod_menu/default_component.php
new file mode 100644
index 0000000..327c20f
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_menu/default_component.php
@@ -0,0 +1,49 @@
+anchor_css ? $item->anchor_css : '';
+$title = $item->anchor_title ? 'title="'.$item->anchor_title.'" ' : '';
+$dropdown = '';
+$caret = '';
+
+if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+}
+
+if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+}
+
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+} else {
+ $linktype = $item->title;
+}
+
+switch ($item->browserNav) :
+ default:
+ case 0:
+?>
href="flink; ?>" > href="flink; ?>" target="_blank" > href="flink; ?>" onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;" >
+
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/mod_menu/default_separator.php b/plugins/system/t3/base/html/mod_menu/default_separator.php
new file mode 100644
index 0000000..16d3b2d
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_menu/default_separator.php
@@ -0,0 +1,23 @@
+anchor_title ? ' title="'.$item->anchor_title.'" ' : '';
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+}
+else {
+ $linktype = $item->title;
+}
+
+?>
>
diff --git a/plugins/system/t3/base/html/mod_menu/default_url.php b/plugins/system/t3/base/html/mod_menu/default_url.php
new file mode 100644
index 0000000..709c8ea
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_menu/default_url.php
@@ -0,0 +1,53 @@
+anchor_css ? $item->anchor_css : '';
+$title = $item->anchor_title ? 'title="'.$item->anchor_title.'" ' : '';
+$dropdown = '';
+$caret = '';
+
+if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+}
+
+if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+}
+
+if ($item->menu_image) {
+ $item->params->get('menu_text', 1 ) ?
+ $linktype = '
'.$item->title.' ' :
+ $linktype = '
';
+} else {
+ $linktype = $item->title;
+}
+$flink = $item->flink;
+$flink = JFilterOutput::ampReplace(htmlspecialchars($flink));
+
+switch ($item->browserNav) :
+ default:
+ case 0:
+?>
+
href="" >
+
href="" target="_blank" > get('window_open');
+ ?>
href="" onclick="window.open(this.href,'targetWindow','');return false;" >
diff --git a/plugins/system/t3/base/html/mod_search/default.php b/plugins/system/t3/base/html/mod_search/default.php
new file mode 100644
index 0000000..2b1cf5b
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_search/default.php
@@ -0,0 +1,52 @@
+
+
+
+
diff --git a/plugins/system/t3/base/html/mod_search/index.html b/plugins/system/t3/base/html/mod_search/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/html/mod_search/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/html/modules.php b/plugins/system/t3/base/html/modules.php
new file mode 100644
index 0000000..99f9ac5
--- /dev/null
+++ b/plugins/system/t3/base/html/modules.php
@@ -0,0 +1,199 @@
+
+ *
+ * This gives template designers ultimate control over how modules are rendered.
+ *
+ * NOTICE: All chrome wrapping methods should be named: modChrome_{STYLE} and take the same
+ * three arguments.
+ */
+
+
+/*
+ * Default Module Chrome that has sematic markup and has best SEO support
+ */
+function modChrome_T3Xhtml($module, &$params, &$attribs)
+{
+ $badge = preg_match ('/badge/', $params->get('moduleclass_sfx'))? '
' : '';
+ $moduleTag = htmlspecialchars($params->get('module_tag', 'div'));
+ $headerTag = htmlspecialchars($params->get('header_tag', 'h3'));
+ $headerClass = $params->get('header_class');
+ $bootstrapSize = $params->get('bootstrap_size');
+ $moduleClass = !empty($bootstrapSize) ? ' span' . (int) $bootstrapSize . '' : '';
+ $moduleClassSfx = htmlspecialchars($params->get('moduleclass_sfx'));
+
+ if (!empty ($module->content)) {
+ $html = "<{$moduleTag} class=\"t3-module module{$moduleClassSfx} {$moduleClass}\" id=\"Mod{$module->id}\">" .
+ "
" . $badge;
+
+ if ($module->showtitle != 0) {
+ $html .= "<{$headerTag} class=\"module-title {$headerClass}\">
{$module->title} {$headerTag}>";
+ }
+
+ $html .= "
{$module->content}
{$moduleTag}>";
+
+ echo $html;
+ }
+}
+
+
+function modChrome_t3tabs($module, $params, $attribs)
+{
+ $area = isset($attribs['id']) ? (int) $attribs['id'] :'1';
+ $area = 'area-'.$area;
+
+ static $modulecount;
+ static $modules;
+
+ if ($modulecount < 1) {
+ $modulecount = count(JModuleHelper::getModules($attribs['name']));
+ $modules = array();
+ }
+
+ if ($modulecount == 1) {
+ $temp = new stdClass;
+ $temp->content = $module->content;
+ $temp->title = $module->title;
+ $temp->params = $module->params;
+ $temp->id = $module->id;
+ $modules[] = $temp;
+
+ // list of moduletitles
+ echo '
';
+ echo '
';
+ $counter = 0;
+ // modulecontent
+ foreach($modules as $rendermodule) {
+ $counter ++;
+
+ echo '
';
+ echo $rendermodule->content;
+
+ echo '
';
+ }
+ echo '
';
+ echo '';
+ $modulecount--;
+
+ } else {
+ $temp = new stdClass;
+ $temp->content = $module->content;
+ $temp->params = $module->params;
+ $temp->title = $module->title;
+ $temp->id = $module->id;
+ $modules[] = $temp;
+ $modulecount--;
+ }
+}
+
+
+function modChrome_t3slider($module, &$params, &$attribs)
+{
+ $badge = preg_match ('/badge/', $params->get('moduleclass_sfx'))?"
\n":"";
+ $headerLevel = isset($attribs['headerLevel']) ? (int) $attribs['headerLevel'] : 3;
+ ?>
+
+
+ >title; ?> >
+
+
+
content; ?>
+
+
+
+ content)) : ?>
+
+
+
+ get('moduleclass_sfx'))?"":"";
+ $headerLevel = isset($attribs['headerLevel']) ? (int) $attribs['headerLevel'] : 3;
+
+ if (!empty ($module->content)) : ?>
+
+ base : integer
+ * $item->link : string
+ * $item->text : string
+ *
+ * pagination_item_inactive
+ * Input variable $item is an object with fields:
+ * $item->base : integer
+ * $item->link : string
+ * $item->text : string
+ *
+ * This gives template designers ultimate control over how pagination is rendered.
+ *
+ * NOTE: If you override pagination_item_active OR pagination_item_inactive you MUST override them both
+ */
+
+function pagination_list_footer($list)
+{
+ $html = "";
+
+ return $html;
+}
+
+function pagination_list_render($list)
+{
+ // Initialize variables
+ $html = "";
+ return $html;
+
+}
+function pagination_item_active(&$item)
+{
+ $app = JFactory::getApplication();
+ if ($app->isAdmin())
+ {
+ if ($item->base > 0)
+ {
+ return "
text . "\" onclick=\"document.adminForm." . $this->prefix . "limitstart.value=" . $item->base
+ . "; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ else
+ {
+ return "
text . "\" onclick=\"document.adminForm." . $this->prefix
+ . "limitstart.value=0; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ }
+ else
+ {
+ return "
text . "\" href=\"" . $item->link . "\">" . $item->text . " ";
+ }
+}
+
+function pagination_item_inactive(&$item) {
+ $cls = (int)$item->text > 0 ? 'active': 'disabled';
+ return "
".$item->text." ";
+}
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/base/imgs/blank.gif b/plugins/system/t3/base/imgs/blank.gif
new file mode 100644
index 0000000..b8ac83f
Binary files /dev/null and b/plugins/system/t3/base/imgs/blank.gif differ
diff --git a/plugins/system/t3/base/index.html b/plugins/system/t3/base/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/base/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/index.php b/plugins/system/t3/base/index.php
new file mode 100644
index 0000000..fe1c5d3
--- /dev/null
+++ b/plugins/system/t3/base/index.php
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/base/js/cssjanus.js b/plugins/system/t3/base/js/cssjanus.js
new file mode 100644
index 0000000..4dd05fc
--- /dev/null
+++ b/plugins/system/t3/base/js/cssjanus.js
@@ -0,0 +1,277 @@
+/**
+ * Creates a CSSJanus object.
+ *
+ * CSSJanus transforms CSS rules with horizontal relevance so that a left-to-right stylesheet can
+ * become a right-to-left stylesheet automatically. Processing can be bypassed for an entire rule
+ * or a single property by adding a / * @noflip * / comment above the rule or property.
+ *
+ * @author "Trevor Parscal"
+ * @author "Roan Kattouw"
+ * @author "Lindsey Simon"
+ * @author "Roozbeh Pournader"
+ * @author "Bryon Engelhardt"
+ *
+ * @class
+ * @constructor
+ * @param {RegExp} regex Regular expression whose matches to replace by a token
+ * @param {String} token Placeholder text
+ */
+function CSSJanus() {
+
+ /* Private Members */
+
+ var prepared = false,
+ // Tokens
+ temporaryToken = '`TMP`',
+ noFlipSingleToken = '`NOFLIP_SINGLE`',
+ noFlipClassToken = '`NOFLIP_CLASS`',
+ commentToken = '`COMMENT`',
+ // Patterns
+ nonAsciiPattern = '[^\\u0020-\\u007e]',
+ unicodePattern = '(?:(?:\\[0-9a-f]{1,6})(?:\\r\\n|\\s)?)',
+ numPattern = '(?:[0-9]*\\.[0-9]+|[0-9]+)',
+ unitPattern = '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)',
+ directionPattern = 'direction\\s*:\\s*',
+ urlSpecialCharsPattern = '[!#$%&*-~]',
+ validAfterUriCharsPattern = '[\'"]?\\s*',
+ nonLetterPattern = '(^|[^a-zA-Z])',
+ charsWithinSelectorPattern = '[^\\}]*?',
+ noFlipPattern = '\\/\\*\\s*@noflip\\s*\\*\\/',
+ commentPattern = '\\/\\*[^*]*\\*+([^\\/*][^*]*\\*+)*\\/',
+ escapePattern = '(?:' + unicodePattern + '|\\\\[^\\r\\n\\f0-9a-f])',
+ nmstartPattern = '(?:[_a-z]|' + nonAsciiPattern + '|' + escapePattern + ')',
+ nmcharPattern = '(?:[_a-z0-9-]|' + nonAsciiPattern + '|' + escapePattern + ')',
+ identPattern = '-?' + nmstartPattern + nmcharPattern + '*',
+ quantPattern = numPattern + '(?:\\s*' + unitPattern + '|' + identPattern + ')?',
+ signedQuantPattern = '((?:-?' + quantPattern + ')|(?:inherit|auto))',
+ fourNotationQuantPropsPattern = '((?:margin|padding|border-width)\\s*:\\s*)',
+ fourNotationColorPropsPattern = '(-color\\s*:\\s*)',
+ colorPattern = '(#?' + nmcharPattern + '+)',
+ urlCharsPattern = '(?:' + urlSpecialCharsPattern + '|' + nonAsciiPattern + '|' + escapePattern + ')*',
+ lookAheadNotOpenBracePattern = '(?!(' + nmcharPattern + '|\\r?\\n|\\s|#|\\:|\\.|\\,|\\+|>)*?{)',
+ lookAheadNotClosingParenPattern = '(?!' + urlCharsPattern + '?' + validAfterUriCharsPattern + '\\))',
+ lookAheadForClosingParenPattern = '(?=' + urlCharsPattern + '?' + validAfterUriCharsPattern + '\\))',
+ // Regular expressions
+ temporaryTokenRegExp = new RegExp( '`TMP`', 'g' ),
+ commentRegExp = new RegExp( commentPattern, 'gi' ),
+ noFlipSingleRegExp = new RegExp( '(' + noFlipPattern + lookAheadNotOpenBracePattern + '[^;}]+;?)', 'gi' ),
+ noFlipClassRegExp = new RegExp( '(' + noFlipPattern + charsWithinSelectorPattern + '})', 'gi' ),
+ directionLtrRegExp = new RegExp( '(' + directionPattern + ')ltr', 'gi' ),
+ directionRtlRegExp = new RegExp( '(' + directionPattern + ')rtl', 'gi' ),
+ leftRegExp = new RegExp( nonLetterPattern + '(left)' + lookAheadNotClosingParenPattern + lookAheadNotOpenBracePattern, 'gi' ),
+ rightRegExp = new RegExp( nonLetterPattern + '(right)' + lookAheadNotClosingParenPattern + lookAheadNotOpenBracePattern, 'gi' ),
+ leftInUrlRegExp = new RegExp( nonLetterPattern + '(left)' + lookAheadForClosingParenPattern, 'gi' ),
+ rightInUrlRegExp = new RegExp( nonLetterPattern + '(right)' + lookAheadForClosingParenPattern, 'gi' ),
+ ltrInUrlRegExp = new RegExp( nonLetterPattern + '(ltr)' + lookAheadForClosingParenPattern, 'gi' ),
+ rtlInUrlRegExp = new RegExp( nonLetterPattern + '(rtl)' + lookAheadForClosingParenPattern, 'gi' ),
+ cursorEastRegExp = new RegExp( nonLetterPattern + '([ns]?)e-resize', 'gi' ),
+ cursorWestRegExp = new RegExp( nonLetterPattern + '([ns]?)w-resize', 'gi' ),
+ fourNotationQuantRegExp = new RegExp( fourNotationQuantPropsPattern + signedQuantPattern + '(\\s+)' + signedQuantPattern + '(\\s+)' + signedQuantPattern + '(\\s+)' + signedQuantPattern, 'gi' ),
+ fourNotationColorRegExp = new RegExp( fourNotationColorPropsPattern + colorPattern + '(\\s+)' + colorPattern + '(\\s+)' + colorPattern + '(\\s+)' + colorPattern, 'gi' ),
+ bgHorizontalPercentageRegExp = new RegExp( '(background(?:-position)?\\s*:\\s*[^%]*?)(-?' + numPattern + ')(%\\s*(?:' + quantPattern + '|' + identPattern + '))', 'gi' ),
+ bgHorizontalPercentageXRegExp = new RegExp( '(background-position-x\\s*:\\s*)(-?' + numPattern + ')(%)', 'gi' ),
+ borderRadiusRegExp = new RegExp( '(border-radius\\s*:\\s*)([^;]*)', 'gi' );
+
+ /* Private Methods */
+
+ /**
+ * Inverts the horizontal value of a background position property.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched property
+ * @param {String} pre Text before value
+ * @param {String} value Horizontal value
+ * @param {String} post Text after value
+ * @return {String} Inverted property
+ */
+ function calculateNewBackgroundPosition( match, pre, value, post ) {
+ return pre + ( 100 - Number( value ) ) + post;
+ }
+
+ /**
+ * Inverts the horizontal value of a background position property.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched property
+ * @param {String} pre Text before value
+ * @param {String} value Horizontal value
+ * @param {String} post Text after value
+ * @return {String} Inverted property
+ */
+ function calculateNewBorderRadius( match, pre, values ) {
+ values = values.split( /\s+/g );
+ switch ( values.length ) {
+ case 4:
+ values = [values[1], values[0], values[3], values[2]];
+ break;
+ case 3:
+ values = [values[1], values[0], values[2]];
+ break;
+ case 2:
+ values = [values[1], values[0]];
+ break;
+ }
+ return pre + values.join( ' ' );
+ }
+
+ /* Methods */
+
+ return {
+ /**
+ * Transform a left-to-right stylesheet to right-to-left.
+ *
+ * @method
+ * @param {String} css Stylesheet to transform
+ * @param {Boolean} swapLtrRtlInUrl Swap 'ltr' and 'rtl' in URLs
+ * @param {Boolean} swapLeftRightInUrl Swap 'left' and 'right' in URLs
+ * @return {String} Transformed stylesheet
+ */
+ 'transform': function( css, swapLtrRtlInUrl, swapLeftRightInUrl ) {
+ // Tokenizers
+ var noFlipSingleTokenizer = new Tokenizer( noFlipSingleRegExp, noFlipSingleToken ),
+ noFlipClassTokenizer = new Tokenizer( noFlipClassRegExp, noFlipClassToken ),
+ commentTokenizer = new Tokenizer( commentRegExp, commentToken );
+
+ // Tokenize
+ css = commentTokenizer.tokenize(
+ noFlipClassTokenizer.tokenize(
+ noFlipSingleTokenizer.tokenize(
+ // We wrap tokens in ` , not ~ like the original implementation does.
+ // This was done because ` is not a legal character in CSS and can only
+ // occur in URLs, where we escape it to %60 before inserting our tokens.
+ css.replace( '`', '%60' )
+ )
+ )
+ );
+
+ // Transform URLs
+ if ( swapLtrRtlInUrl ) {
+ // Replace 'ltr' with 'rtl' and vice versa in background URLs
+ css = css
+ .replace( ltrInUrlRegExp, '$1' + temporaryToken )
+ .replace( rtlInUrlRegExp, '$1ltr' )
+ .replace( temporaryTokenRegExp, 'rtl' );
+ }
+ if ( swapLeftRightInUrl ) {
+ // Replace 'left' with 'right' and vice versa in background URLs
+ css = css
+ .replace( leftInUrlRegExp, '$1' + temporaryToken )
+ .replace( rightInUrlRegExp, '$1left' )
+ .replace( temporaryTokenRegExp, 'right' );
+ }
+
+ // Transform rules
+ css = css
+ // Replace direction: ltr; with direction: rtl; and vice versa.
+ .replace( directionLtrRegExp, '$1' + temporaryToken )
+ .replace( directionRtlRegExp, '$1ltr' )
+ .replace( temporaryTokenRegExp, 'rtl' )
+ // Flip rules like left: , padding-right: , etc.
+ .replace( leftRegExp, '$1' + temporaryToken )
+ .replace( rightRegExp, '$1left' )
+ .replace( temporaryTokenRegExp, 'right' )
+ // Flip East and West in rules like cursor: nw-resize;
+ .replace( cursorEastRegExp, '$1$2' + temporaryToken )
+ .replace( cursorWestRegExp, '$1$2e-resize' )
+ .replace( temporaryTokenRegExp, 'w-resize' )
+ // Border radius
+ .replace( borderRadiusRegExp, calculateNewBorderRadius )
+ // Swap the second and fourth parts in four-part notation rules
+ // like padding: 1px 2px 3px 4px;
+ .replace( fourNotationQuantRegExp, '$1$2$3$8$5$6$7$4' )
+ .replace( fourNotationColorRegExp, '$1$2$3$8$5$6$7$4' )
+ // Flip horizontal background percentages
+ .replace( bgHorizontalPercentageRegExp, calculateNewBackgroundPosition )
+ .replace( bgHorizontalPercentageXRegExp, calculateNewBackgroundPosition );
+
+ // Detokenize
+ css = noFlipSingleTokenizer.detokenize(
+ noFlipClassTokenizer.detokenize(
+ commentTokenizer.detokenize( css )
+ )
+ );
+
+ return css;
+ }
+ };
+}
+
+/**
+ * Creates a tokenizer object.
+ *
+ * This utility class is used by CSSJanus to protect strings by replacing them temporarily with
+ * tokens and later transforming them back.
+ *
+ * @author Trevor Parscal
+ * @author Roan Kattouw
+ *
+ * @class
+ * @constructor
+ * @param {RegExp} regex Regular expression whose matches to replace by a token
+ * @param {String} token Placeholder text
+ */
+Tokenizer = function( regex, token ) {
+
+ /* Private Members */
+
+ var matches = [],
+ index = 0;
+
+ /* Private Methods */
+
+ /**
+ * Adds a match.
+ *
+ * @private
+ * @function
+ * @param {String} match Matched string
+ * @returns {String} Token to leave in the matched string's place
+ */
+ function tokenizeCallback( match ) {
+ matches.push( match );
+ return token;
+ }
+
+ /**
+ * Gets a match.
+ *
+ * @private
+ * @function
+ * @param {String} token Matched token
+ * @returns {String} Original matched string to restore
+ */
+ function detokenizeCallback( token ) {
+ return matches[index++];
+ }
+
+ /* Methods */
+
+ return {
+ /**
+ * Replace matching strings with tokens.
+ *
+ * @method
+ * @param {String} str String to tokenize
+ * @return {String} Tokenized string
+ */
+ 'tokenize': function( str ) {
+ return str.replace( regex, tokenizeCallback );
+ },
+ /**
+ * Restores tokens to their original values.
+ *
+ * @method
+ * @param {String} str String previously run through tokenize()
+ * @return {String} Original string
+ */
+ 'detokenize': function( str ) {
+ return str.replace( new RegExp( '(' + token + ')', 'g' ), detokenizeCallback );
+ }
+ };
+};
+
+/* Initialization */
+
+var cssjanus = new CSSJanus();
\ No newline at end of file
diff --git a/plugins/system/t3/base/js/frontend-edit.js b/plugins/system/t3/base/js/frontend-edit.js
new file mode 100644
index 0000000..996262b
--- /dev/null
+++ b/plugins/system/t3/base/js/frontend-edit.js
@@ -0,0 +1,51 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+
+!function($){
+
+ $(document).ready(function(){
+
+ //frontend edit radio on/off - auto convert on-off radio if applicable
+ $('fieldset.radio').filter(function(){
+
+ return $(this).find('input').length == 2 && $(this).find('input').filter(function(){
+ return $.inArray(this.value + '', ['0', '1']) !== -1;
+ }).length == 2;
+
+ }).addClass('t3onoff').removeClass('btn-group');
+
+ //add class on/off
+ $('fieldset.t3onoff').find('label').addClass(function(){
+ return $(this).hasClass('off') || $(this).prev('input').val() == '0' ? 'off' : 'on'
+ });
+
+ //listen to all
+ $('fieldset.radio').find('label').unbind('click').click(function() {
+ var label = $(this),
+ input = $('#' + label.attr('for'));
+
+ if (!input.prop('checked')){
+ label.addClass('active').siblings().removeClass('active');
+
+ input.prop('checked', true).trigger('change');
+ }
+ });
+
+ //initial state
+ $('.radio input[checked=checked]').each(function(){
+ $('label[for=' + $(this).attr('id') + ']').addClass('active');
+ });
+
+ });
+
+}(jQuery);
\ No newline at end of file
diff --git a/plugins/system/t3/base/js/jquery-1.8.3.js b/plugins/system/t3/base/js/jquery-1.8.3.js
new file mode 100644
index 0000000..8c24ffc
--- /dev/null
+++ b/plugins/system/t3/base/js/jquery-1.8.3.js
@@ -0,0 +1,9472 @@
+/*!
+ * jQuery JavaScript Library v1.8.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
+ */
+(function( window, undefined ) {
+var
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+ location = window.location,
+ navigator = window.navigator,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // Save a reference to some core methods
+ core_push = Array.prototype.push,
+ core_slice = Array.prototype.slice,
+ core_indexOf = Array.prototype.indexOf,
+ core_toString = Object.prototype.toString,
+ core_hasOwn = Object.prototype.hasOwnProperty,
+ core_trim = String.prototype.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
+
+ // Used for detecting and trimming whitespace
+ core_rnotwhite = /\S/,
+ core_rspace = /\s+/,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return ( letter + "" ).toUpperCase();
+ },
+
+ // The ready event handler and self cleanup method
+ DOMContentLoaded = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ } else if ( document.readyState === "complete" ) {
+ // we're here because readyState === "complete" in oldIE
+ // which is good enough for us to call the dom ready!
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ },
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = ( context && context.nodeType ? context.ownerDocument || context : document );
+
+ // scripts is true for back-compat
+ selector = jQuery.parseHTML( match[1], doc, true );
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ this.attr.call( selector, context, true );
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.8.3",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ i = +i;
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ),
+ "slice", core_slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ core_toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // scripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, scripts ) {
+ var parsed;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ scripts = context;
+ context = 0;
+ }
+ context = context || document;
+
+ // Single tag
+ if ( (parsed = rsingleTag.exec( data )) ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
+ return jQuery.merge( [],
+ (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
+ },
+
+ parseJSON: function( data ) {
+ if ( !data || typeof data !== "string") {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+
+ }
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && core_rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var name,
+ i = 0,
+ length = obj.length,
+ isObj = length === undefined || jQuery.isFunction( obj );
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in obj ) {
+ if ( callback.apply( obj[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( obj[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in obj ) {
+ if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var type,
+ ret = results || [];
+
+ if ( arr != null ) {
+ // The window, strings (and functions) also have 'length'
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ type = jQuery.type( arr );
+
+ if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
+ core_push.call( ret, arr );
+ } else {
+ jQuery.merge( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value, key,
+ ret = [],
+ i = 0,
+ length = elems.length,
+ // jquery objects are treated as arrays
+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( key in elems ) {
+ value = callback( elems[ key ], key, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+ var exec,
+ bulk = key == null,
+ i = 0,
+ length = elems.length;
+
+ // Sets many values
+ if ( key && typeof key === "object" ) {
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+ }
+ chainable = 1;
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = pass === undefined && jQuery.isFunction( value );
+
+ if ( bulk ) {
+ // Bulk operations only iterate when executing function values
+ if ( exec ) {
+ exec = fn;
+ fn = function( elem, key, value ) {
+ return exec.call( jQuery( elem ), value );
+ };
+
+ // Otherwise they run against the entire set
+ } else {
+ fn.call( elems, value );
+ fn = null;
+ }
+ }
+
+ if ( fn ) {
+ for (; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+ }
+
+ chainable = 1;
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready, 1 );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.split( core_rspace ), function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ return jQuery.inArray( fn, list ) > -1;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( list && ( !fired || stack ) ) {
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
+ function() {
+ var returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ }
+ } :
+ newDefer[ action ]
+ );
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ] = list.fire
+ deferred[ tuple[0] ] = list.fire;
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function() {
+
+ var support,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ fragment,
+ eventName,
+ i,
+ isSupported,
+ clickFn,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " a ";
+
+ // Support tests won't run in some limited or non-browser environments
+ all = div.getElementsByTagName("*");
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !all || !a || !all.length ) {
+ return {};
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+ support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.5/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: ( input.value === "on" ),
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // Tests for enctype support on a form (#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
+
+ // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+ boxModel: ( document.compatMode === "CSS1Compat" ),
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ boxSizingReliable: true,
+ pixelPosition: false
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent( "onclick", clickFn = function() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ support.noCloneEvent = false;
+ });
+ div.cloneNode( true ).fireEvent("onclick");
+ div.detachEvent( "onclick", clickFn );
+ }
+
+ // Check if a radio maintains its value
+ // after being appended to the DOM
+ input = document.createElement("input");
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ input.setAttribute( "checked", "checked" );
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.lastChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ fragment.removeChild( input );
+ fragment.appendChild( div );
+
+ // Technique from Juriy Zaytsev
+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for ( i in {
+ submit: true,
+ change: true,
+ focusin: true
+ }) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
+ }
+ }
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, div, tds, marginDiv,
+ divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ div.innerHTML = "";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE <= 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+ support.boxSizing = ( div.offsetWidth === 4 );
+ support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+ // NOTE: To any future maintainer, we've window.getComputedStyle
+ // because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = document.createElement("div");
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "
";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ container.style.zoom = 1;
+ }
+
+ // Null elements to avoid leaks in IE
+ body.removeChild( container );
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ fragment.removeChild( div );
+ all = a = select = opt = input = fragment = div = null;
+
+ return support;
+})();
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+ cache: {},
+
+ deletedIds: [],
+
+ // Remove at next major release (1.9/2.0)
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( !name.indexOf( "data-" ) ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ parts = key.split( ".", 2 );
+ parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ }
+
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
+
+ self.triggerHandler( "setData" + part, parts );
+ jQuery.data( this, key, value );
+ self.triggerHandler( "changeData" + part, parts );
+ });
+ }, null, value, arguments.length > 1, null, false );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery.removeData( elem, type + "queue", true );
+ jQuery.removeData( elem, key, true );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook, fixSpecified,
+ rclass = /[\t\r\n]/g,
+ rreturn = /\r/g,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea|)$/i,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classNames, i, l, elem,
+ setClass, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ classNames = value.split( core_rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className && classNames.length === 1 ) {
+ elem.className = value;
+
+ } else {
+ setClass = " " + elem.className + " ";
+
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
+ setClass += classNames[ c ] + " ";
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var removes, className, elem, c, cl, i, l;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call(this, j, this.className) );
+ });
+ }
+ if ( (value && typeof value === "string") || value === undefined ) {
+ removes = ( value || "" ).split( core_rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+ if ( elem.nodeType === 1 && elem.className ) {
+
+ className = (" " + elem.className + " ").replace( rclass, " " );
+
+ // loop over each item in the removal list
+ for ( c = 0, cl = removes.length; c < cl; c++ ) {
+ // Remove until there is nothing to remove,
+ while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
+ className = className.replace( " " + removes[ c ] + " " , " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( className ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( core_rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val,
+ self = jQuery(this);
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
+ attrFn: {},
+
+ attr: function( elem, name, value, pass ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+
+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ ret = elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret === null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, isBool,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+
+ attrNames = value.split( core_rspace );
+
+ for ( ; i < attrNames.length; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
+ elem.removeAttribute( getSetAttribute ? name : propName );
+
+ // Set corresponding property to false for boolean attributes
+ if ( isBool && propName in elem ) {
+ elem[ propName ] = false;
+ }
+ }
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to it's default in case type is set after value
+ // This is for element creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ },
+ // Use the value property for back compat
+ // Use the nodeHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.set( elem, value, name );
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true,
+ coords: true
+ };
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
+ ret.value :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
+ }
+ return ( ret.value = value + "" );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret === null ? undefined : ret;
+ }
+ });
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Normalize to lowercase since IE uppercases css property names
+ return elem.style.cssText.toLowerCase() || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+var rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, handlers, special;
+
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+ eventHandle = elemData.handle;
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
+
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var t, tns, type, origType, namespaces, origCount,
+ j, events, special, eventType, handleObj,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
+
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, "events", true );
+ }
+ },
+
+ // Events that are safe to short-circuit if no handlers are attached.
+ // Native DOM events should not be added, they may have inline handlers.
+ customEvent: {
+ "getData": true,
+ "setData": true,
+ "changeData": true
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
+ // Event object or event type
+ var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
+ type = event.type || event,
+ namespaces = [];
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "!" ) >= 0 ) {
+ // Exclusive events trigger only for the exact event (no namespaces)
+ type = type.slice(0, -1);
+ exclusive = true;
+ }
+
+ if ( type.indexOf( "." ) >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+
+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+ // No jQuery handlers for this event type, and it can't have inline handlers
+ return;
+ }
+
+ // Caller can pass in an Event, Object, or just an event type string
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ new jQuery.Event( type, event ) :
+ // Just the event type (string)
+ new jQuery.Event( type );
+
+ event.type = type;
+ event.isTrigger = true;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+ // Handle a global trigger
+ if ( !elem ) {
+
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+ }
+ }
+ return;
+ }
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data != null ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ for ( old = elem; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old === (elem.ownerDocument || document) ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event || window.event );
+
+ var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
+ handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = core_slice.call( arguments ),
+ run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
+ handlerQueue = [];
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.disabled !== true || event.type !== "click" ) {
+ selMatch = {};
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = jQuery.Event( originalEvent );
+
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Target should not be a text node (#504, Safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === "undefined" ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "_submit_attached" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "_submit_attached", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "_change_attached", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) { // && selector != null
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ return jQuery.event.trigger( type, data, this[0], true );
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var cachedruns,
+ assertGetIdNotName,
+ Expr,
+ getText,
+ isXML,
+ contains,
+ compile,
+ sortOrder,
+ hasDuplicate,
+ outermostContext,
+
+ baseHasDuplicate = true,
+ strundefined = "undefined",
+
+ expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
+
+ Token = String,
+ document = window.document,
+ docElem = document.documentElement,
+ dirruns = 0,
+ done = 0,
+ pop = [].pop,
+ push = [].push,
+ slice = [].slice,
+ // Use a stripped-down indexOf if a native one is unavailable
+ indexOf = [].indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ // Augment a function for special use by Sizzle
+ markFunction = function( fn, value ) {
+ fn[ expando ] = value == null || value;
+ return fn;
+ },
+
+ createCache = function() {
+ var cache = {},
+ keys = [];
+
+ return markFunction(function( key, value ) {
+ // Only keep the most recent entries
+ if ( keys.push( key ) > Expr.cacheLength ) {
+ delete cache[ keys.shift() ];
+ }
+
+ // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157)
+ return (cache[ key + " " ] = value);
+ }, cache );
+ },
+
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+
+ // Regex
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ operators = "([*^$|!~]?=)",
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments not in parens/brackets,
+ // then attribute selectors and non-pseudos (denoted by :),
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
+
+ // For matchExpr.POS and matchExpr.needsContext
+ pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+ rpseudo = new RegExp( pseudos ),
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
+
+ rnot = /^:not/,
+ rsibling = /[\x20\t\r\n\f]*[+~]/,
+ rendsWithNot = /:not\($/,
+
+ rheader = /h\d/i,
+ rinputs = /input|select|textarea|button/i,
+
+ rbackslash = /\\(?!\\)/g,
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "POS": new RegExp( pos, "i" ),
+ "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ // For use in libraries implementing .is()
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
+ },
+
+ // Support
+
+ // Used for testing something on an element
+ assert = function( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // release memory in IE
+ div = null;
+ }
+ },
+
+ // Check if getElementsByTagName("*") returns only elements
+ assertTagNameNoComments = assert(function( div ) {
+ div.appendChild( document.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ }),
+
+ // Check if getAttribute returns normalized href attributes
+ assertHrefNotNormalized = assert(function( div ) {
+ div.innerHTML = " ";
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+ div.firstChild.getAttribute("href") === "#";
+ }),
+
+ // Check if attributes should be retrieved by attribute nodes
+ assertAttributes = assert(function( div ) {
+ div.innerHTML = " ";
+ var type = typeof div.lastChild.getAttribute("multiple");
+ // IE8 returns a string for some attributes even when not present
+ return type !== "boolean" && type !== "string";
+ }),
+
+ // Check if getElementsByClassName can be trusted
+ assertUsableClassName = assert(function( div ) {
+ // Opera can't find a second classname (in 9.6)
+ div.innerHTML = "
";
+ if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+ return false;
+ }
+
+ // Safari 3.2 caches class attributes and doesn't catch changes
+ div.lastChild.className = "e";
+ return div.getElementsByClassName("e").length === 2;
+ }),
+
+ // Check if getElementById returns elements by name
+ // Check if getElementsByName privileges form controls or returns elements by ID
+ assertUsableName = assert(function( div ) {
+ // Inject content
+ div.id = expando + 0;
+ div.innerHTML = "
";
+ docElem.insertBefore( div, docElem.firstChild );
+
+ // Test
+ var pass = document.getElementsByName &&
+ // buggy browsers will return fewer than the correct 2
+ document.getElementsByName( expando ).length === 2 +
+ // buggy browsers will return more than the correct 0
+ document.getElementsByName( expando + 0 ).length;
+ assertGetIdNotName = !document.getElementById( expando );
+
+ // Cleanup
+ docElem.removeChild( div );
+
+ return pass;
+ });
+
+// If slice is not available, provide a backup
+try {
+ slice.call( docElem.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+ slice = function( i ) {
+ var elem,
+ results = [];
+ for ( ; (elem = this[i]); i++ ) {
+ results.push( elem );
+ }
+ return results;
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+ var match, elem, xml, m,
+ nodeType = context.nodeType;
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( nodeType !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ xml = isXML( context );
+
+ if ( !xml && !seed ) {
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
+ push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+ return results;
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
+}
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+};
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ }
+ return ret;
+};
+
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Element contains another
+contains = Sizzle.contains = docElem.contains ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
+ } :
+ docElem.compareDocumentPosition ?
+ function( a, b ) {
+ return b && !!( a.compareDocumentPosition( b ) & 16 );
+ } :
+ function( a, b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+Sizzle.attr = function( elem, name ) {
+ var val,
+ xml = isXML( elem );
+
+ if ( !xml ) {
+ name = name.toLowerCase();
+ }
+ if ( (val = Expr.attrHandle[ name ]) ) {
+ return val( elem );
+ }
+ if ( xml || assertAttributes ) {
+ return elem.getAttribute( name );
+ }
+ val = elem.getAttributeNode( name );
+ return val ?
+ typeof elem[ name ] === "boolean" ?
+ elem[ name ] ? name : null :
+ val.specified ? val.value : null :
+ null;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ // IE6/7 return a modified href
+ attrHandle: assertHrefNotNormalized ?
+ {} :
+ {
+ "href": function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ },
+ "type": function( elem ) {
+ return elem.getAttribute("type");
+ }
+ },
+
+ find: {
+ "ID": assertGetIdNotName ?
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ } :
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+
+ return m ?
+ m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+ [m] :
+ undefined :
+ [];
+ }
+ },
+
+ "TAG": assertTagNameNoComments ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ var elem,
+ tmp = [],
+ i = 0;
+
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ },
+
+ "NAME": assertUsableName && function( tag, context ) {
+ if ( typeof context.getElementsByName !== strundefined ) {
+ return context.getElementsByName( name );
+ }
+ },
+
+ "CLASS": assertUsableClassName && function( className, context, xml ) {
+ if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
+ return context.getElementsByClassName( className );
+ }
+ }
+ },
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( rbackslash, "" );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 3 xn-component of xn+y argument ([+-]?\d*n|)
+ 4 sign of xn-component
+ 5 x of xn-component
+ 6 sign of y-component
+ 7 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1] === "nth" ) {
+ // nth-child requires argument
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
+ match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var unquoted, excess;
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ if ( match[3] ) {
+ match[2] = match[3];
+ } else if ( (unquoted = match[4]) ) {
+ // Only check arguments that contain a pseudo
+ if ( rpseudo.test(unquoted) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ unquoted = unquoted.slice( 0, excess );
+ match[0] = match[0].slice( 0, excess );
+ }
+ match[2] = unquoted;
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+ "ID": assertGetIdNotName ?
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ return elem.getAttribute("id") === id;
+ };
+ } :
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === id;
+ };
+ },
+
+ "TAG": function( nodeName ) {
+ if ( nodeName === "*" ) {
+ return function() { return true; };
+ }
+ nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
+
+ return function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ expando ][ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem, context ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.substr( result.length - check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, argument, first, last ) {
+
+ if ( type === "nth" ) {
+ return function( elem ) {
+ var node, diff,
+ parent = elem.parentNode;
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ if ( parent ) {
+ diff = 0;
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ diff++;
+ if ( elem === node ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset (or cast to NaN), then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ };
+ }
+
+ return function( elem ) {
+ var node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ var nodeType;
+ elem = elem.firstChild;
+ while ( elem ) {
+ if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
+ return false;
+ }
+ elem = elem.nextSibling;
+ }
+ return true;
+ },
+
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "text": function( elem ) {
+ var type, attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ (type = elem.type) === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
+ },
+
+ // Input types
+ "radio": createInputPseudo("radio"),
+ "checkbox": createInputPseudo("checkbox"),
+ "file": createInputPseudo("file"),
+ "password": createInputPseudo("password"),
+ "image": createInputPseudo("image"),
+
+ "submit": createButtonPseudo("submit"),
+ "reset": createButtonPseudo("reset"),
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "focus": function( elem ) {
+ var doc = elem.ownerDocument;
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ "active": function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ },
+
+ // Positional types
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 0; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 1; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+function siblingCheck( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+}
+
+sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
+ a.compareDocumentPosition :
+ a.compareDocumentPosition(b) & 4
+ ) ? -1 : 1;
+ } :
+ function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+// Always assume the presence of duplicates if sort doesn't
+// pass them to our comparison function (as in Google Chrome).
+[0, 0].sort( sortOrder );
+baseHasDuplicate = !hasDuplicate;
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ i = 1,
+ j = 0;
+
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem === results[ i - 1 ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ expando ][ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+
+ // Cast descendant combinators to space
+ matched.type = match[0].replace( rtrim, " " );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+ matched.type = type;
+ matched.matches = match;
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && combinator.dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( !xml ) {
+ var cache,
+ dirkey = dirruns + " " + doneName + " ",
+ cachedkey = dirkey + cachedruns;
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( (cache = elem[ expando ]) === cachedkey ) {
+ return elem.sizset;
+ } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
+ if ( elem.sizset ) {
+ return elem;
+ }
+ } else {
+ elem[ expando ] = cachedkey;
+ if ( matcher( elem, context, xml ) ) {
+ elem.sizset = true;
+ return elem;
+ }
+ elem.sizset = false;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( matcher( elem, context, xml ) ) {
+ return elem;
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && tokens.join("")
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Nested matchers should use non-integer dirruns
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = superMatcher.el;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++superMatcher.el;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ for ( j = 0; (matcher = setMatchers[j]); j++ ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ superMatcher.el = 0;
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ expando ][ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed, xml ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector ),
+ j = match.length;
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ context.nodeType === 9 && !xml &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
+ if ( !context ) {
+ return results;
+ }
+
+ selector = selector.slice( tokens.shift().length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( rbackslash, "" ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context,
+ xml
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && tokens.join("");
+ if ( !selector ) {
+ push.apply( results, slice.call( seed, 0 ) );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ xml,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+if ( document.querySelectorAll ) {
+ (function() {
+ var disconnectedMatch,
+ oldSelect = select,
+ rescape = /'|\\/g,
+ rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+ // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA
+ // A support test would require too much code (would include document ready)
+ rbuggyQSA = [ ":focus" ],
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ // A support test would require too much code (would include document ready)
+ // just skip matchesSelector for :active
+ rbuggyMatches = [ ":active" ],
+ matches = docElem.matchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.webkitMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector;
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explictly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = " ";
+
+ // IE8 - Some boolean attributes are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here (do not put tests after this one)
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Opera 10-12/IE9 - ^= $= *= and empty values
+ // Should not select anything
+ div.innerHTML = "
";
+ if ( div.querySelectorAll("[test^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here (do not put tests after this one)
+ div.innerHTML = " ";
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push(":enabled", ":disabled");
+ }
+ });
+
+ // rbuggyQSA always contains :focus, so no need for a length check
+ rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
+
+ select = function( selector, context, results, seed, xml ) {
+ // Only use querySelectorAll when not filtering,
+ // when this is not xml,
+ // and when no QSA bugs apply
+ if ( !seed && !xml && !rbuggyQSA.test( selector ) ) {
+ var groups, i,
+ old = true,
+ nid = expando,
+ newContext = context,
+ newSelector = context.nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + groups[i].join("");
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results, slice.call( newContext.querySelectorAll(
+ newSelector
+ ), 0 ) );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+
+ return oldSelect( selector, context, results, seed, xml );
+ };
+
+ if ( matches ) {
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ try {
+ matches.call( div, "[test!='']:sizzle" );
+ rbuggyMatches.push( "!=", pseudos );
+ } catch ( e ) {}
+ });
+
+ // rbuggyMatches always contains :active and :focus, so no need for a length check
+ rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
+
+ Sizzle.matchesSelector = function( elem, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ // rbuggyMatches always contains :active, so no need for an existence check
+ if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) {
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+ };
+ }
+ })();
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Back-compat
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ rneedsContext = jQuery.expr.match.needsContext,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i, l, length, n, r, ret,
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return jQuery( selector ).filter(function() {
+ for ( i = 0, l = self.length; i < l; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ });
+ }
+
+ ret = this.pushStack( "", "find", selector );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( n = length; n < ret.length; n++ ) {
+ for ( r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ rneedsContext.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ ret = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+ }
+ cur = cur.parentNode;
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( this.length > 1 && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( elem === qualifier ) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+ });
+}
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = / ]", "i"),
+ rcheckableType = /^(?:checkbox|radio)$/,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*\s*$/g,
+ wrapMap = {
+ option: [ 1, "", " " ],
+ legend: [ 1, "", " " ],
+ thead: [ 1, "" ],
+ tr: [ 2, "" ],
+ td: [ 3, "" ],
+ col: [ 2, "" ],
+ area: [ 1, "", " " ],
+ _default: [ 0, "", "" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+// unless wrapped in a div with non-breaking characters in front of it.
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "X", "
" ];
+}
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( !isDisconnected( this[0] ) ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ }
+
+ if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
+ }
+ },
+
+ after: function() {
+ if ( !isDisconnected( this[0] ) ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ }
+
+ if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1>$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function( value ) {
+ if ( !isDisconnected( this[0] ) ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ }
+
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+
+ // Flatten any nested arrays
+ args = [].concat.apply( [], args );
+
+ var results, first, fragment, iNoClone,
+ i = 0,
+ value = args[0],
+ scripts = [],
+ l = this.length;
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call( this, i, table ? self.html() : undefined );
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ results = jQuery.buildFragment( args, this, scripts );
+ fragment = results.fragment;
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ // Fragments from the fragment cache must always be cloned and never used in place.
+ for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
+ callback.call(
+ table && jQuery.nodeName( this[i], "table" ) ?
+ findOrAppend( this[i], "tbody" ) :
+ this[i],
+ i === iNoClone ?
+ fragment :
+ jQuery.clone( fragment, true, true )
+ );
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ if ( jQuery.ajax ) {
+ jQuery.ajax({
+ url: elem.src,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ } else {
+ jQuery.error("no ajax");
+ }
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
+ }
+ }
+
+ return this;
+ }
+});
+
+function findOrAppend( elem, tag ) {
+ return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ if ( nodeName === "object" ) {
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, context, scripts ) {
+ var fragment, cacheable, cachehit,
+ first = args[ 0 ];
+
+ // Set context from what may come in as undefined or a jQuery collection or a node
+ // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
+ // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put or elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+ // Mark cacheable and look for a hit
+ cacheable = true;
+ fragment = jQuery.fragments[ first ];
+ cachehit = fragment !== undefined;
+ }
+
+ if ( !fragment ) {
+ fragment = context.createDocumentFragment();
+ jQuery.clean( args, context, fragment, scripts );
+
+ // Update the cache, but only store false
+ // unless this is a second parsing of the same content
+ if ( cacheable ) {
+ jQuery.fragments[ first ] = cachehit && fragment;
+ }
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ l = insert.length,
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+ } else {
+ for ( ; i < l; i++ ) {
+ elems = ( i > 0 ? this.clone(true) : this ).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var srcElements,
+ destElements,
+ i,
+ clone;
+
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
+ safe = context === document && safeFragment,
+ ret = [];
+
+ // Ensure that context is a document
+ if ( !context || typeof context.createDocumentFragment === "undefined" ) {
+ context = document;
+ }
+
+ // Use the already-created safe fragment if context permits
+ for ( i = 0; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Ensure a safe container in which to render the html
+ safe = safe || createSafeFragment( context );
+ div = context.createElement("div");
+ safe.appendChild( div );
+
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1>$2>");
+
+ // Go to html and back, then peel off extra wrappers
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ depth = wrap[0];
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a , *may* have spurious
+ hasBody = rtbody.test(elem);
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare or
+ wrap[1] === "" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+
+ // Take out of fragment container (we need a fresh div each time)
+ div.parentNode.removeChild( div );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ jQuery.merge( ret, elem );
+ }
+ }
+
+ // Fix #11356: Clear elements from safeFragment
+ if ( div ) {
+ elem = div = safe = null;
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ fixDefaultChecked( elem );
+ } else if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+ }
+ }
+
+ // Append elements to a provided document fragment
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var data, id, elem, type,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ jQuery.deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+// Limit scope pollution from any deprecated API
+(function() {
+
+var matched, browser;
+
+// Use of jQuery.browser is frowned upon.
+// More details: http://api.jquery.com/jQuery.browser
+// jQuery.uaMatch maintained for back-compat
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+matched = jQuery.uaMatch( navigator.userAgent );
+browser = {};
+
+if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+}
+
+// Chrome is Webkit, but Webkit is also Safari.
+if ( browser.chrome ) {
+ browser.webkit = true;
+} else if ( browser.webkit ) {
+ browser.safari = true;
+}
+
+jQuery.browser = browser;
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+};
+
+})();
+var curCSS, iframe, iframeDoc,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
+
+ eventsToggle = jQuery.fn.toggle;
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+ var elem, display,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && elem.style.display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ display = curCSS( elem, "display" );
+
+ if ( !values[ index ] && display !== "none" ) {
+ jQuery._data( elem, "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state, fn2 ) {
+ var bool = typeof state === "boolean";
+
+ if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
+ return eventsToggle.apply( this, arguments );
+ }
+
+ return this.each(function() {
+ if ( bool ? state : isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, numeric, extra ) {
+ var val, num, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( numeric || extra !== undefined ) {
+ num = parseFloat( val );
+ return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// NOTE: To any future maintainer, we've window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ curCSS = function( elem, name ) {
+ var ret, width, minWidth, maxWidth,
+ computed = window.getComputedStyle( elem, null ),
+ style = elem.style;
+
+ if ( computed ) {
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ curCSS = function( elem, name ) {
+ var left, rsLeft,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ // we use jQuery.css instead of curCSS here
+ // because of the reliableMarginRight CSS hook!
+ val += jQuery.css( elem, extra + cssExpand[ i ], true );
+ }
+
+ // From this point on we use curCSS for maximum performance (relevant in animations)
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ valueIsBorderBox = true,
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox
+ )
+ ) + "px";
+}
+
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ if ( elemdisplay[ nodeName ] ) {
+ return elemdisplay[ nodeName ];
+ }
+
+ var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
+ display = elem.css("display");
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // Use the already-created iframe if possible
+ iframe = document.body.appendChild(
+ iframe || jQuery.extend( document.createElement("iframe"), {
+ frameBorder: 0,
+ width: 0,
+ height: 0
+ })
+ );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write("");
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
+
+ display = curCSS( elem, "display" );
+ document.body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ });
+ } else {
+ return getWidthOrHeight( elem, name, extra );
+ }
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ return curCSS( elem, "marginRight" );
+ }
+ });
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ var ret = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ rselectTextarea = /^(?:select|textarea)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /@siu'
+ ), array(
+ '',
+ ''
+ ), $buffer);
+
+ //output the megamenu key to save
+ echo $buffer . '';
+ }
+
+ public static function delete(){
+ $input = JFactory::getApplication()->input;
+ $template = $input->get('template');
+ $mmkey = $input->get('mmkey', $input->get('menutype', 'mainmenu'));
+ $tplparams = T3::getTplParams();
+
+ $currentconfig = $tplparams instanceof JRegistry ? json_decode($tplparams->get('mm_config', ''), true) : null;
+
+ if (!is_array($currentconfig)) {
+ $currentconfig = array();
+ }
+
+ //delete it
+ if(isset($currentconfig[$mmkey])){
+ unset($currentconfig[$mmkey]);
+ }
+ $currentconfig = json_encode($currentconfig);
+
+ //get all other styles that have the same template
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query
+ ->select('*')
+ ->from('#__template_styles')
+ ->where('template=' . $db->quote($template));
+
+ $db->setQuery($query);
+ $themes = $db->loadObjectList();
+ $return = true;
+
+ foreach($themes as $theme){
+ $registry = new JRegistry;
+ $registry->loadString($theme->params);
+
+ //overwrite with new value
+ $registry->set('mm_config', $currentconfig);
+
+ $query = $db->getQuery(true);
+ $query
+ ->update('#__template_styles')
+ ->set('params =' . $db->quote($registry->toString()))
+ ->where('id =' . (int)$theme->id);
+
+ $db->setQuery($query);
+ $return = $db->execute() && $return;
+ }
+
+ die(json_encode(array(
+ 'status' => $return,
+ 'message' => JText::_($return ? 'T3_NAVIGATION_DELETE_SUCCESSFULLY' : 'T3_NAVIGATION_DELETE_FAILED')
+ )
+ )
+ );
+ }
+
+ public static function save()
+ {
+ $input = JFactory::getApplication()->input;
+ $template = $input->get('template');
+ $mmconfig = $input->getString('config');
+ $mmkey = $input->get('mmkey', $input->get('menutype', 'mainmenu'));
+ $tplparams = T3::getTplParams();
+
+ if(get_magic_quotes_gpc() && !is_null($mmconfig)){
+ $mmconfig = stripslashes($mmconfig);
+ }
+
+ $currentconfig = $tplparams instanceof JRegistry ? json_decode($tplparams->get('mm_config', ''), true) : null;
+
+ if (!is_array($currentconfig)) {
+ $currentconfig = array();
+ }
+
+ $currentconfig[$mmkey] = json_decode($mmconfig, true);
+ $currentconfig = json_encode($currentconfig);
+
+ //get all other styles that have the same template
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query
+ ->select('*')
+ ->from('#__template_styles')
+ ->where('template=' . $db->quote($template));
+
+ $db->setQuery($query);
+ $themes = $db->loadObjectList();
+ $return = true;
+
+ foreach($themes as $theme){
+ $registry = new JRegistry;
+ $registry->loadString($theme->params);
+
+ //overwrite with new value
+ $registry->set('mm_config', $currentconfig);
+
+ $query = $db->getQuery(true);
+ $query
+ ->update('#__template_styles')
+ ->set('params =' . $db->quote($registry->toString()))
+ ->where('id =' . (int)$theme->id);
+
+ $db->setQuery($query);
+ $return = $db->execute() && $return;
+ }
+
+ die(json_encode(array(
+ 'status' => $return,
+ 'message' => JText::_($return ? 'T3_NAVIGATION_SAVE_SUCCESSFULLY' : 'T3_NAVIGATION_SAVE_FAILED')
+ )
+ )
+ );
+ }
+
+ /**
+ *
+ * Ge all available modules
+ */
+ public static function menus()
+ {
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true)
+ ->select('menutype AS value, title AS text')
+ ->from($db->quoteName('#__menu_types'))
+ ->order('title');
+ $db->setQuery($query);
+ $menus = $db->loadObjectList();
+
+ $query = $db->getQuery(true)
+ ->select('menutype, language')
+ ->from($db->quoteName('#__menu'))
+ ->where('published = 1')
+ ->group('menutype');
+ $db->setQuery($query);
+ $menulangs = $db->loadAssocList('menutype');
+
+ $query = $db->getQuery(true)
+ ->select('menutype, language')
+ ->from($db->quoteName('#__menu'))
+ ->where('home = 1 and published = 1');
+ $db->setQuery($query);
+ $homelangs = $db->loadAssocList('menutype');
+
+ if(is_array($menulangs) && is_array($homelangs)){
+ $menulangs = array_merge($menulangs, $homelangs);
+ }
+
+ if(is_array($menus) && is_array($menulangs)){
+ foreach ($menus as $menu) {
+ $menu->text = $menu->text . ' [' . $menu->value . ']';
+ $menu->language = isset($menulangs[$menu->value]) ? $menulangs[$menu->value]['language'] : '*';
+ }
+ }
+
+ return is_array($menus) ? $menus : array();
+ }
+
+ /**
+ *
+ * Ge all support access levels
+ */
+ public static function access()
+ {
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+
+ $query->select('a.id AS value, a.title AS text');
+ $query->from('#__viewlevels AS a');
+ $query->group('a.id, a.title, a.ordering');
+ $query->order('a.ordering ASC');
+ $query->order($query->qn('title') . ' ASC');
+ $query->where('a.id in (1,2,3) or a.title = ' . $db->quote('Guest')); //we only support Public, Registered, Special, Guest
+
+ // Get the options.
+ $db->setQuery($query);
+ $options = $db->loadObjectList();
+
+ return is_array($options) ? $options : array();
+ }
+
+ /**
+ *
+ * Ge all available modules
+ */
+ public static function modules()
+ {
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('id, title, module, position')
+ ->from('#__modules')
+ ->where('published = 1')
+ ->where('client_id = 0')
+ ->order('title');
+ $db->setQuery($query);
+ $modules = $db->loadObjectList();
+
+ return is_array($modules) ? $modules : array();
+ }
+
+ /**
+ *
+ * Show thememagic form
+ */
+ public static function megamenu()
+ {
+ $tplparams = T3::getTplParams();
+
+ $url = JFactory::getURI();
+ $url->delVar('t3action');
+ $url->delVar('t3task');
+ $referer = $url->toString();
+ $template = T3_TEMPLATE;
+ $styleid = JFactory::getApplication()->input->getCmd('id');
+
+ $mm_type = ($tplparams && $tplparams instanceof JRegistry) ? $tplparams->get('mm_type', '') : null;
+
+ //Keepalive
+ $config = JFactory::getConfig();
+ $lifetime = ($config->get('lifetime') * 60000);
+ $refreshTime = ($lifetime <= 60000) ? 30000 : $lifetime - 60000;
+
+ // Refresh time is 1 minute less than the liftime assined in the configuration.php file.
+ // The longest refresh period is one hour to prevent integer overflow.
+ if ($refreshTime > 3600000 || $refreshTime <= 0) {
+ $refreshTime = 3600000;
+ }
+
+ //check config
+ $currentconfig = ($tplparams && $tplparams instanceof JRegistry) ? $tplparams->get('mm_config', '') : null;
+ if(!$currentconfig){
+ $currentconfig = '"{}"';
+ }
+
+ include T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php';
+
+ exit;
+ }
+
+ /**
+ * Copy from Joomla 3.x
+ */
+ public static function tooltipText($title = '', $content = '', $translate = 1, $escape = 1)
+ {
+ // Return empty in no title or content is given.
+ if ($title == '' && $content == '')
+ {
+ return '';
+ }
+
+ // Split title into title and content if the title contains '::' (old Mootools format).
+ if ($content == '' && !(strpos($title, '::') === false))
+ {
+ list($title, $content) = explode('::', $title, 2);
+ }
+
+ // Pass texts through the JText.
+ if ($translate)
+ {
+ $title = JText::_($title);
+ $content = JText::_($content);
+ }
+
+ // Escape the texts.
+ if ($escape)
+ {
+ $title = str_replace('"', '"', $title);
+ $content = str_replace('"', '"', $content);
+ }
+
+ // Return only the content if no title is given.
+ if ($title == '')
+ {
+ return $content;
+ }
+
+ // Return only the title if title and text are the same.
+ if ($title == $content)
+ {
+ return '' . $title . ' ';
+ }
+
+ // Return the formated sting combining the title and content.
+ if ($content != '')
+ {
+ return '' . $title . ' ' . $content;
+ }
+
+ // Return only the title.
+ return $title;
+ }
+}
diff --git a/plugins/system/t3/includes/admin/theme.php b/plugins/system/t3/includes/admin/theme.php
new file mode 100644
index 0000000..9f2908f
--- /dev/null
+++ b/plugins/system/t3/includes/admin/theme.php
@@ -0,0 +1,514 @@
+= 0) {
+ T3::import('format/less3.3');
+}
+
+/**
+ *
+ * Admin helper module class
+ * @author JoomlArt
+ *
+ */
+class T3AdminTheme
+{
+ /**
+ *
+ * save Profile
+ */
+
+ public static function response($data){
+ die(json_encode($data));
+ }
+
+ public static function error($msg){
+ return self::response(array('error' => $msg));
+ }
+
+ public static function save($path)
+ {
+ $result = array();
+
+ if(empty($path)){
+ return self::error(JText::_('T3_TM_UNKNOWN_THEME'));
+ }
+
+ $theme = JFactory::getApplication()->input->getCmd('theme');
+ $from = JFactory::getApplication()->input->getCmd('from');
+ if (!$theme) {
+ return self::error(JText::_('T3_TM_INVALID_DATA_TO_SAVE'));
+ }
+
+ //incase empty from
+ if(!$from){
+ $from = 'base';
+ }
+
+ // $file = $path . '/less/themes/' . $theme . '/variables-custom.less';
+ $file =T3Path::getLocalPath('less/themes/' . $theme . '/variables-custom.less');
+
+ if(!class_exists('JRegistryFormatLESS')){
+ T3::import('format/less');
+ }
+ $variables = new JRegistry();
+ $variables->loadObject($_POST);
+
+ $data = $variables->toString('LESS');
+ $type = 'new';
+ if (JFile::exists($file)) {
+ $type = 'overwrite';
+ } else {
+ if($theme != $from && JFolder::exists($path . '/less/themes/' . $from)){
+ $source = $path . '/less/themes/' . $from;
+ if (!JFolder::exists($source)) {
+ // try to find the source in local
+ $source = T3Path::getPath('less/themes/' . $from);
+ if (!$source) {
+ return self::error(JText::sprintf('T3_TM_NOT_FOUND', $from));
+ }
+ }
+ $desc = T3Path::getLocalPath('less/themes/' . $theme);
+ if(@JFolder::copy($source, $desc) != true){
+ return self::error(JText::_('T3_TM_NOT_FOUND'));
+ }
+
+ // detect & copy rtl
+ $rtlsource = $path . '/less/rtl/' . $from;
+ if (!JFolder::exists($rtlsource)) {
+ // try to find the source in local
+ $rtlsource = T3Path::getPath('less/rtl/' . $from);
+ }
+
+ if ($rtlsource) {
+ $rtldest = T3Path::getLocalPath('less/rtl/' . $theme);
+ // copy $from to $theme
+ @JFolder::copy($rtlsource, $rtldest);
+ }
+ }
+ }
+
+ $return = @JFile::write($file, $data);
+
+ if (!$return) {
+ return self::error(JText::_('T3_TM_OPERATION_FAILED'));
+ } else {
+ $result['success'] = JText::sprintf('T3_TM_SAVE_SUCCESSFULLY', $theme);
+ $result['theme'] = $theme;
+ $result['type'] = $type;
+ }
+
+ //LessHelper::compileForTemplate(T3_TEMPLATE_PATH, $theme);
+ T3::import ('core/less');
+ T3Less::compileAll($theme);
+ return self::response($result);
+ }
+
+ /**
+ *
+ * Clone Profile
+ */
+ public static function duplicate($path)
+ {
+ $theme = JFactory::getApplication()->input->getCmd('theme');
+ $from = JFactory::getApplication()->input->getCmd('from');
+ $result = array();
+
+ if (empty($theme) || empty($from)) {
+ return self::error(JText::_('T3_TM_INVALID_DATA_TO_SAVE'));
+ }
+
+ $source = $path . '/less/themes/' . $from;
+ if (!JFolder::exists($source)) {
+ // try to find the source in local
+ $source = T3Path::getPath('less/themes/' . $from);
+ if (!$source) {
+ return self::error(JText::sprintf('T3_TM_NOT_FOUND', $from));
+ }
+ }
+
+ // $dest = $path . '/less/themes/' . $theme;
+ // clone to local
+ $dest = T3Path::getLocalPath('less/themes/' . $theme);
+ if (JFolder::exists($dest)) {
+ return self::error(JText::sprintf('T3_TM_EXISTED', $theme));
+ }
+
+ // copy $from to $theme
+ $status = @JFolder::copy($source, $dest);
+
+ $rtlsource = $path . '/less/rtl/' . $from;
+ if (!JFolder::exists($rtlsource)) {
+ // try to find the source in local
+ $rtlsource = T3Path::getPath('less/rtl/' . $from);
+ }
+
+ if ($rtlsource) {
+ $rtldest = T3Path::getLocalPath('less/rtl/' . $theme);
+ // copy $from to $theme
+ @JFolder::copy($rtlsource, $rtldest);
+ }
+
+ $result = array();
+ if ($status) {
+ $result['success'] = JText::_('T3_TM_CLONE_SUCCESSFULLY');
+ $result['theme'] = $theme;
+ $result['reset'] = true;
+ $result['type'] = 'duplicate';
+ } else {
+ return self::error(JText::_('T3_TM_OPERATION_FAILED'));
+ }
+
+ //LessHelper::compileForTemplate(T3_TEMPLATE_PATH , $theme);
+ T3::import ('core/less');
+ T3Less::compileAll($theme);
+ return self::response($result);
+ }
+
+ /**
+ *
+ * Delete a profile
+ */
+ public static function delete($path)
+ {
+ // Initialize some variables
+ $theme = JFactory::getApplication()->input->getCmd('theme');
+ $result = array();
+
+ if (!$theme) {
+ return self::error(JText::_('T3_TM_UNKNOWN_THEME'));
+ }
+
+ // delete custom theme
+ $paths = array();
+ $paths = array_merge($paths, T3Path::getAllPath('less/themes/' . $theme));
+ $paths = array_merge($paths, T3Path::getAllPath('css/themes/' . $theme));
+ $paths = array_merge($paths, T3Path::getAllPath('less/rtl/' . $theme));
+ $paths = array_merge($paths, T3Path::getAllPath('css/rtl/' . $theme));
+
+ $errors = array();
+ foreach ($paths as $path) {
+ if (is_dir ($path) && !@JFolder::delete($path)) {
+ $errors[] = $path;
+ }
+ }
+
+ if (count($errors)) {
+ return self::error(JText::sprintf('T3_TM_DELETE_FAIL', implode(' - ', $errors)));
+ } else {
+ $result['template'] = '0';
+ $result['success'] = JText::sprintf('T3_TM_DELETE_SUCCESSFULLY', $theme);
+ $result['theme'] = $theme;
+ $result['type'] = 'delete';
+ }
+
+ return self::response($result);
+ }
+
+ /**
+ *
+ * Show thememagic form
+ */
+ public static function thememagic($path)
+ {
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $isadmin = $app->isAdmin();
+
+ if($isadmin){
+ $tplparams = T3::getTplParams();
+ } else {
+ $tplparams = $app->getTemplate(true)->params;
+ }
+
+ $url = $isadmin ? JUri::root(true).'/index.php' : JUri::current();
+ $url .= (preg_match('/\?/', $url) ? '&' : '?') . 'themer=1';
+ $url .= ($tplparams->get('theme', -1) != -1 ? ('&t3style=' . $tplparams->get('theme')) : '');
+ if($isadmin){
+ $url .= '&t3tmid=' . $input->getCmd('id');
+ }
+
+ $assetspath = T3_TEMPLATE_PATH;
+ $themepath = $assetspath . '/less/themes';
+ if(!class_exists('JRegistryFormatLESS')){
+ include_once T3_ADMIN_PATH . '/includes/format/less.php';
+ }
+
+ $themes = array();
+ $jsondata = array();
+
+ //push a default theme
+ $tobj = new stdClass();
+ $tobj->id = 'base';
+ $tobj->title = JText::_('JDEFAULT');
+
+ $themes['base'] = $tobj;
+
+ $varfile = $assetspath . '/less/variables.less';
+ if(file_exists($varfile)){
+ $params = new JRegistry;
+ $params->loadString(JFile::read($varfile), 'LESS');
+ $jsondata['base'] = $params->toArray();
+ }
+
+ // if (JFolder::exists($themepath)) {
+ foreach (T3Path::getAllPath('/less/themes') as $themepath) {
+ $listthemes = JFolder::folders($themepath);
+ if (count($listthemes)) {
+ foreach ($listthemes as $theme) {
+ $varsfile = $themepath . '/' . $theme . '/variables-custom.less';
+ if(file_exists($varsfile)){
+
+ $tobj = new stdClass();
+ $tobj->id = $theme;
+ $tobj->title = $theme;
+
+ //check for all less file in theme folder
+ $params = false;
+ $others = JFolder::files($themepath . '/' . $theme, '.less', false, true);
+ foreach($others as $other){
+ $otherrel = T3Path::relativePath('less/', str_replace (T3_TEMPLATE_PATH . '/', '', $other));
+
+ //get those developer custom values
+ if($other == 'variables.less'){
+ $params = new JRegistry;
+ $params->loadString(JFile::read($themepath . '/' . $theme . '/variables.less'), 'LESS');
+ }
+
+ if($other != 'variables-custom.less'){
+ $tobj->$other = $otherrel;
+ }
+ }
+
+ $cparams = new JRegistry;
+ $cparams->loadString(JFile::read($varsfile), 'LESS');
+ if($params){
+ foreach ($cparams->toArray() as $key => $value) {
+ $params->set($key, $value);
+ }
+ } else {
+ $params = $cparams;
+ }
+
+ $themes[$theme] = $tobj;
+ $jsondata[$theme] = $params->toArray();
+ }
+ }
+ }
+ }
+
+ // get active theme
+ $active_theme = $tplparams->get('theme', 'base');
+ if (!isset($themes[$active_theme])) $active_theme = 'base';
+
+ $langs = array (
+ 'addTheme' => JText::_('T3_TM_ASK_ADD_THEME'),
+ 'delTheme' => JText::_('T3_TM_ASK_DEL_THEME'),
+ 'overwriteTheme' => JText::_('T3_TM_ASK_OVERWRITE_THEME'),
+ 'correctName' => JText::_('T3_TM_ASK_CORRECT_NAME'),
+ 'themeExist' => JText::_('T3_TM_EXISTED'),
+ 'saveChange' => JText::_('T3_TM_ASK_SAVE_CHANGED'),
+ 'previewError' => JText::_('T3_TM_PREVIEW_ERROR'),
+ 'unknownError' => JText::_('T3_MSG_UNKNOWN_ERROR'),
+ 'lblCancel' => JText::_('JCANCEL'),
+ 'lblOk' => JText::_('T3_TM_LABEL_OK'),
+ 'lblNo' => JText::_('JNO'),
+ 'lblYes' => JText::_('JYES'),
+ 'lblDefault' => JText::_('JDEFAULT')
+ );
+
+ //Keepalive
+ $config = JFactory::getConfig();
+ $lifetime = ($config->get('lifetime') * 60000);
+ $refreshTime = ($lifetime <= 60000) ? 30000 : $lifetime - 60000;
+
+ // Refresh time is 1 minute less than the liftime assined in the configuration.php file.
+ // The longest refresh period is one hour to prevent integer overflow.
+ if ($refreshTime > 3600000 || $refreshTime <= 0){
+ $refreshTime = 3600000;
+ }
+
+ $backurl = JFactory::getURI();
+ $backurl->delVar('t3action');
+ $backurl->delVar('t3task');
+
+ if(!$isadmin){
+ $backurl->delVar('tm');
+ $backurl->delVar('themer');
+ }
+
+ T3::import('depend/t3form');
+
+ $form = new T3Form('thememagic.themer', array('control' => 't3form'));
+ $form->load(JFile::read(JFile::exists(T3_TEMPLATE_PATH . '/thememagic.xml') ? T3_TEMPLATE_PATH . '/thememagic.xml' : T3_PATH . '/params/thememagic.xml'));
+ $form->loadFile(T3_TEMPLATE_PATH . '/templateDetails.xml', true, '//config');
+
+ $tplform = new T3Form('thememagic.overwrite', array('control' => 't3form'));
+ $tplform->loadFile(T3_TEMPLATE_PATH . '/templateDetails.xml', true, '//config');
+
+ $fieldSets = $form->getFieldsets('thememagic');
+ $tplFieldSets = $tplform->getFieldsets('thememagic');
+
+ $disabledFieldSets = array();
+ foreach ($tplFieldSets as $name => $fieldSet){
+ if(isset($fieldSet->disabled)){
+ $disabledFieldSets[] = $name;
+ }
+ }
+
+ include T3_ADMIN_PATH.'/admin/thememagic/thememagic.tpl.php';
+
+ exit();
+ }
+
+ public static function addAssets(){
+ $japp = JFactory::getApplication();
+ $user = JFactory::getUser();
+
+ //do nothing when site is offline and user has not login (the offline page is only show login form)
+ if ($japp->getCfg('offline') && !$user->authorise('core.login.offline')) {
+ return;
+ }
+
+ $jdoc = JFactory::getDocument();
+ $params = $japp->getTemplate(true)->params;
+ $devmode = $params->get('devmode', 0);
+
+ if(defined('T3_THEMER') && $params->get('themermode', 1)){
+
+ $jdoc->addStyleSheet(T3_URL.'/css/thememagic.css');
+ $jdoc->addScript(T3_URL.'/js/thememagic.js');
+
+ $theme = $params->get('theme');
+ $params = new JRegistry;
+ $themeinfo = new stdClass;
+
+ if($theme){
+ foreach (T3Path::getAllPath('less/themes/' . $theme) as $themepath) {
+ //$themepath = T3_TEMPLATE_PATH . '/less/themes/' . $theme;
+
+ if(file_exists($themepath . '/variables-custom.less')){
+ if(!class_exists('JRegistryFormatLESS')){
+ include_once T3_ADMIN_PATH . '/includes/format/less.php';
+ }
+
+ //default variables
+ $varfile = T3_TEMPLATE_PATH . '/less/variables.less';
+ if(file_exists($varfile)){
+ $params->loadString(JFile::read($varfile), 'LESS');
+
+ //get all less files in "theme" folder
+ $others = JFolder::files($themepath, '.less');
+ foreach($others as $other){
+ //get those developer custom values
+ if($other == 'variables.less'){
+ $devparams = new JRegistry;
+ $devparams->loadString(JFile::read($themepath . '/variables.less'), 'LESS');
+
+ //overwrite the default variables
+ foreach ($devparams->toArray() as $key => $value) {
+ $params->set($key, $value);
+ }
+ }
+
+ //ok, we will import it later
+ if($other != 'variables-custom.less' && $other != 'variables.less'){
+ $themeinfo->$other = true;
+ }
+ }
+
+ //load custom variables
+ if (file_exists($themepath . '/variables-custom.less')) {
+ $cparams = new JRegistry;
+ $cparams->loadString(JFile::read($themepath . '/variables-custom.less'), 'LESS');
+
+ //and overwrite those defaults variables
+ foreach ($cparams->toArray() as $key => $value) {
+ $params->set($key, $value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $cache = array();
+
+ // a little security
+ if($user->authorise('core.manage', 'com_templates') || (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], JUri::base() . 'administrator') !== false)){
+ T3::import('core/path');
+ $baseurl = JUri::base();
+
+ //should we provide a list of less path
+ foreach (array(T3_TEMPLATE_PATH . '/less', T3_PATH . '/bootstrap/less', T3_PATH . '/less') as $lesspath) {
+ if(is_dir($lesspath)){
+ $lessfiles = JFolder::files($lesspath, '.less', true, true);
+ if(is_array($lessfiles)){
+ foreach ($lessfiles as $less) {
+ $path = ltrim(str_replace(array(JPATH_ROOT, '\\'), array('', '/'), $less), '/');
+ $path = T3Path::cleanPath($path);
+ $fullurl = $baseurl . preg_replace('@(\\+)|(/+)@', '/', $path);
+ $cache[$fullurl] = JFile::read($less);
+ }
+ }
+ }
+ }
+ }
+
+ //workaround for bootstrap icon path
+ $sparams = new JRegistry;
+ if(defined('T3_BASE_RSP_IN_CLASS') && T3_BASE_RSP_IN_CLASS){
+ $sparams->set('icon-font-path', '"' . JUri::base() . 'plugins/system/t3/base-bs3/bootstrap/fonts/"');
+ }
+
+ // enable development mode for less.js
+ if ($devmode) {
+ $jdoc->addScriptDeclaration('
+ var less = window.less || {};
+ less.env = \'development\';
+ ');
+ }
+
+ $jdoc->addScriptDeclaration('
+ var T3Theme = window.T3Theme || {};
+ T3Theme.vars = ' . json_encode($params->toArray()) . ';
+ T3Theme.svars = ' . json_encode($sparams->toArray()) . ';
+ T3Theme.others = ' . json_encode($themeinfo) . ';
+ T3Theme.theme = \'' . $theme . '\';
+ T3Theme.template = \'' . T3_TEMPLATE . '\';
+ T3Theme.base = \'' . JURI::base() . '\';
+ T3Theme.cache = ' . json_encode($cache) . ';
+ if(typeof less != \'undefined\'){
+
+ //we need to build one - cause the js will have unexpected behavior
+ try{
+ if(window.parent != window &&
+ window.parent.T3Theme &&
+ window.parent.T3Theme.applyLess){
+
+ window.parent.T3Theme.applyLess(true);
+ } else {
+ less.refresh();
+ }
+ } catch(e){
+
+ }
+ }'
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/core/action.php b/plugins/system/t3/includes/core/action.php
new file mode 100644
index 0000000..5f6a99d
--- /dev/null
+++ b/plugins/system/t3/includes/core/action.php
@@ -0,0 +1,246 @@
+input->getCmd('view'));
+
+ if(!defined('JPATH_COMPONENT')){
+ define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
+ }
+
+ if(!defined('JPATH_COMPONENT_SITE')){
+ define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
+ }
+
+ if(!defined('JPATH_COMPONENT_ADMINISTRATOR')){
+ define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
+ }
+
+ T3Action::$action();
+ }
+ exit;
+ }
+
+ public static function lessc () {
+ $path = JFactory::getApplication()->input->getString ('s');
+
+ T3::import ('core/less');
+ $css = T3Less::getCss($path);
+
+ header("Content-Type: text/css");
+ header("Content-length: ".strlen($css));
+ echo $css;
+ }
+
+ public static function lesscall(){
+ T3::import ('core/less');
+
+ $input = JFactory::getApplication()->input;
+ $result = array();
+
+ try{
+ T3Less::compileAll($input->get('theme', ''));
+ $result['successful'] = JText::_('T3_MSG_COMPILE_SUCCESS');
+ }catch(Exception $e){
+ // $result['error'] = JText::sprintf('T3_MSG_COMPILE_FAILURE', $e->__toString());
+ $result['error'] = JText::sprintf('T3_MSG_COMPILE_FAILURE', $e->getMessage());
+ }
+
+ echo json_encode($result);
+ }
+
+ public static function theme(){
+
+ JFactory::getLanguage()->load('tpl_' . T3_TEMPLATE, JPATH_SITE);
+
+ if(!defined('T3')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
+ )));
+ }
+
+ $user = JFactory::getUser();
+ $action = JFactory::getApplication()->input->getCmd('t3task', '');
+
+ if ($action != 'thememagic' && !$user->authorise('core.manage', 'com_templates')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_NO_PERMISSION')
+ )));
+ }
+
+ if(empty($action)){
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+
+ T3::import('admin/theme');
+
+ if(method_exists('T3AdminTheme', $action)){
+ T3AdminTheme::$action(T3_TEMPLATE_PATH);
+ } else {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+ }
+
+ public static function layout(){
+ self::cloneParam('t3layout');
+
+ if(!defined('T3')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
+ )));
+ }
+
+ $action = JFactory::getApplication()->input->get('t3task', '');
+ if(empty($action)){
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+
+ if($action != 'display'){
+ $user = JFactory::getUser();
+ if (!$user->authorise('core.manage', 'com_templates')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_NO_PERMISSION')
+ )));
+ }
+ }
+
+ T3::import('admin/layout');
+
+ if(method_exists('T3AdminLayout', $action)){
+ T3AdminLayout::$action(T3_TEMPLATE_PATH);
+ } else {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+ }
+
+ public static function megamenu() {
+ self::cloneParam('t3menu');
+
+ JFactory::getLanguage()->load('tpl_' . T3_TEMPLATE, JPATH_SITE);
+
+ if(!defined('T3')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
+ )));
+ }
+
+ $action = JFactory::getApplication()->input->get('t3task', '');
+ if(empty($action)){
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+
+ if($action != 'display'){
+ $user = JFactory::getUser();
+ if (!$user->authorise('core.manage', 'com_templates')) {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_NO_PERMISSION')
+ )));
+ }
+ }
+
+ T3::import('admin/megamenu');
+
+ if(method_exists('T3AdminMegamenu', $action)){
+ T3AdminMegamenu::$action();
+ exit;
+ } else {
+ die(json_encode(array(
+ 'error' => JText::_('T3_MSG_UNKNOW_ACTION')
+ )));
+ }
+ }
+
+ public static function module () {
+ $user = JFactory::getUser();
+ $input = JFactory::getApplication()->input;
+ $id = $input->getInt('mid');
+ $t3acl = (int)$input->get('t3acl', 1);
+ $groups = $user->getAuthorisedViewLevels();
+ $module = null;
+ $buffer = null;
+
+ array_push($groups, $t3acl);
+
+ if (is_array($groups) && in_array(3, $groups)) {
+ //we assume, if a user is special, they should be registered also
+ $groups[] = 2;
+ }
+
+ if ($id) {
+ // load module
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params')
+ ->from('#__modules AS m')
+ ->where('m.id = '.$id)
+ ->where('m.published = 1')
+ ->where('m.access IN ('.implode(',', array_unique($groups)).')');
+ $db->setQuery($query);
+ $module = $db->loadObject();
+ }
+
+ if (!empty ($module)) {
+ $style = $input->getCmd ('style', 'T3Xhtml');
+ $buffer = JModuleHelper::renderModule($module, array('style'=>$style));
+
+ // replace relative images url
+ $base = JURI::base(true).'/';
+ $protocols = '[a-zA-Z0-9]+:'; //To check for all unknown protocals (a protocol must contain at least one alpahnumeric fillowed by :
+ $regex = '#(src)="(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
+ $buffer = preg_replace($regex, "$1=\"$base\$2\"", $buffer);
+ }
+
+ if($buffer){
+ //remove invisibile content, there are more ... but ...
+ $buffer = preg_replace(array( '@@siu', '@@siu'), array('', ''), $buffer);
+
+ echo $buffer;
+ } else {
+ die(json_encode(array(
+ 'message' => JText::_('T3_MSG_MODULE_NOT_AVAIL')
+ )));
+ }
+
+ }
+
+ //translate param name to new name, from jvalue => to desired param name
+ public static function cloneParam($param = '', $from = 'jvalue'){
+ $input = JFactory::getApplication()->input;
+
+ if(!empty($param) && $input->getWord($param, '') == ''){
+ $input->set($param, $input->getCmd($from));
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/core/admin.php b/plugins/system/t3/includes/core/admin.php
new file mode 100644
index 0000000..9fefb3c
--- /dev/null
+++ b/plugins/system/t3/includes/core/admin.php
@@ -0,0 +1,339 @@
+input;
+ $body = JResponse::getBody();
+ $layout = T3_ADMIN_PATH . '/admin/tpls/default.php';
+
+ if(file_exists($layout) && 'style' == $input->getCmd('view')){
+
+ ob_start();
+ $this->renderAdmin();
+ $buffer = ob_get_clean();
+
+ //this cause backtrack_limit in some server
+ //$body = preg_replace('@@msU', $buffer, $body);
+ $opentags = explode('
+ ';
+ $xml = simplexml_load_string($_xml);
+ $form->load ($xml, false);
+ }
+ }
+
+ public static function extraFields(&$form, $data, $tplpath){
+
+ if ($form->getName() == 'com_categories.categorycom_content' || $form->getName() == 'com_content.article') {
+
+ jimport('joomla.filesystem.folder');
+ jimport('joomla.filesystem.file');
+
+ // check for extrafields overwrite
+ $path = $tplpath . '/etc/extrafields';
+ if (!is_dir ($path)) return ;
+
+ $files = JFolder::files($path, '.xml');
+ if (!$files || !count($files)){
+ return ;
+ }
+
+ $extras = array();
+ foreach ($files as $file) {
+ $extras[] = JFile::stripExt($file);
+ }
+ if (count($extras)) {
+
+ if ($form->getName() == 'com_categories.categorycom_content'){
+
+ //load languages
+ if(!defined('T3_TEMPLATE')){
+ JFactory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);
+ }
+
+ $_xml =
+ '
+
+ ';
+ $xml = simplexml_load_string($_xml);
+ $form->load ($xml, false);
+
+ } else {
+
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $fdata = empty($data) ? $input->post->get('jform', array(), 'array') : (is_object($data) ? $data->getProperties() : $data);
+ $catid = $input->getInt('catid', $app->getUserState('com_content.articles.filter.category_id'));
+
+ if(!$catid && is_array($fdata) && !empty($fdata)){
+ $catid = $fdata['catid'];
+ }
+
+ if($catid){
+
+ if(version_compare(JVERSION, '3.0', 'lt')){
+ jimport('joomla.application.categories');
+ }
+
+ $categories = JCategories::getInstance('Content', array('countItems' => 0 ));
+ $category = $categories->get($catid);
+ $params = $category->params;
+ if(!$params instanceof JRegistry) {
+ $params = new JRegistry;
+ $params->loadString($category->params);
+ }
+
+ if($params instanceof JRegistry){
+ $extrafile = $path . '/' . $params->get('t3_extrafields') . '.xml';
+ if(is_file($extrafile)){
+ JForm::addFormPath($path);
+ $form->loadFile($params->get('t3_extrafields'), false);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/core/defines.php b/plugins/system/t3/includes/core/defines.php
new file mode 100644
index 0000000..d898a34
--- /dev/null
+++ b/plugins/system/t3/includes/core/defines.php
@@ -0,0 +1,38 @@
+ 1440
+ ));
+
+ // get cache
+ $data = $cache->get($key, $group);
+ if ($data) {
+ return $data;
+ }
+
+ // not cached, build & store it
+ $data = self::compileCss($path) . "\n";
+ $cache->store($data, $key, $group);
+
+ return $data;
+ }
+
+ /**
+ * Compile LESS to CSS
+ * @param $path the less file to compile
+ * @return string url to css file
+ */
+ public static function buildCss ($path, $return = false) {
+ $rtpl_check = '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i';
+ $rtpl_less_check = '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/less/@i';
+
+ $app = JFactory::getApplication();
+ $doc = JFactory::getDocument();
+ $theme = $app->getUserState('current_theme', '');
+ $is_rtl = ($app->getUserState('current_direction') == 'rtl');
+
+ $ie8 = preg_match('/MSIE 8\./', $_SERVER['HTTP_USER_AGENT']);
+
+ // get css cached file
+ $subdir = ($is_rtl ? 'rtl/' : '') . ($theme ? $theme . '/' : '');
+ $cssdir = T3_DEV_FOLDER . ($ie8 ? '/ie8' : '') . '/' . $subdir;
+ $cssfile = $cssdir . str_replace('/', '.', $path) . '.css';
+
+ // modified time
+ $less_lm = @filemtime (JPATH_ROOT . '/' . $path);
+ $css_lm = @filemtime ($cssfile);
+ $vars_lm = self::getState('vars_last_modified', 0);
+
+ $list = self::parse($path);
+
+ if (empty ($list)) return false;
+
+ // prepare output list
+ $split = !$ie8 && !$return && preg_match ($rtpl_less_check, $path) && !preg_match ('/bootstrap/', $path);
+ $output_files = array();
+
+ foreach ($list as $f => $import) {
+ if ($import) {
+ $css = $cssdir . str_replace('/', '.', $f) . '.css';
+ if ($split) $output_files[] = $css;
+ $less_lm = max ($less_lm, @filemtime(JPATH_ROOT . '/' . $f));
+ $css_lm = max ($css_lm, @filemtime(JPATH_ROOT . '/' . $css));
+ }
+ }
+
+ // itself
+ $output_files [] = $cssfile;
+
+ // check modified
+ $rebuild = $vars_lm > $css_lm || $less_lm > $css_lm;
+ if ($rebuild) {
+ if ($split) {
+ self::compileCss($path, $cssfile, true, $list);
+ } else {
+ self::compileCss($path, $cssfile, false, $list);
+ }
+ }
+
+ if (!$return) {
+ // add css
+ foreach ($output_files as $css) {
+ $doc->addStylesheet($css);
+ }
+ } else {
+ return $cssfile;
+ }
+ }
+
+ public static function relativePath($topath, $path, $default = null){
+ $rel = T3Path::relativePath($topath, $path);
+ return $rel ? $rel . '/' : './';
+ }
+
+ /**
+ * @param string $path file path of less file to compile
+ * @param string $topath file path of output css file
+ * @return bool|mixed compile result or the css compiled content
+ */
+ public static function compileCss($path, $topath = '', $split = false, $list = null) {
+ $fromdir = dirname($path);
+ $app = JFactory::getApplication();
+ $is_rtl = ($app->getUserState('current_direction') == 'rtl');
+
+ if (empty ($list)) $list = self::parse($path);
+ if (empty ($list)) {
+ return false;
+ }
+ // join $list
+ $content = '';
+ $importdirs = array();
+ $todir = $topath ? dirname($topath) : $fromdir;
+
+ if (!is_dir(JPATH_ROOT . '/' . $todir)) {
+ JFolder::create(JPATH_ROOT . '/' . $todir);
+ }
+ $importdirs[JPATH_ROOT . '/' . $fromdir] = './';
+ foreach ($list as $f => $import) {
+ if ($import) {
+ $importdirs[JPATH_ROOT . '/' . dirname($f)] = self::relativePath($fromdir, dirname($f));
+ $content .= "\n#".self::$kfilepath."{content: \"{$f}\";}\n";
+ // $content .= "@import \"$import\";\n\n";
+ if (is_file(JPATH_ROOT . '/' . $f)) {
+ $less_content = file_get_contents(JPATH_ROOT . '/' . $f);
+ // remove vars/mixins for template & t3 less
+ if (preg_match ('@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i', $f) || preg_match ('@'.preg_quote(T3_REL, '@') . '/@i', $f)) {
+ $less_content = preg_replace(self::$rimportvars, '', $less_content);
+ }
+ self::$_path = T3Path::relativePath($fromdir, dirname($f)) . '/';
+ $less_content = preg_replace_callback(self::$rimport, array('T3Less', 'cb_import_path'), $less_content);
+ $content .= $less_content;
+ }
+ } else {
+ $content .= "\n#".self::$kfilepath."{content: \"{$path}\";}\n";
+ $content .= $f . "\n\n";
+ }
+ }
+
+ // get vars
+ $vars_files = explode('|', self::getVars('urls'));
+
+ // build source
+ $source = '';
+ // build import vars
+ foreach ($vars_files as $var) {
+ $var_file = T3Path::relativePath($fromdir, $var);
+ $source .= "@import \"" . $var_file . "\";\n";
+ }
+
+ // less content
+ $source .= "\n#" . self::$kvarsep . "{content: \"separator\";}\n" . $content;
+
+ // call Less to compile,
+ // temporary compile into source path, then update url to destination later
+ try {
+ $output = T3LessCompiler::compile($source, $importdirs);
+ } catch (Exception $e) {
+ // echo 'Caught exception: ', $e->getMessage(), "\n";
+ throw new Exception($path . " \n" . $e->getMessage());
+ }
+
+ // process content
+ //use cssjanus to transform the content
+ if ($is_rtl) {
+ $output = preg_split(self::$rsplitbegin . self::$krtlsep . self::$rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $rtlcontent = isset($output[2]) ? $output[2] : false;
+ $output = $output[0];
+
+ T3::import('jacssjanus/ja.cssjanus');
+ $output = JACSSJanus::transform($output, true);
+
+ // join with rtl content
+ if($rtlcontent){
+ $output = $output . "\n" . $rtlcontent;
+ }
+ }
+ // skip duplicate clearfix
+ $arr = preg_split(self::$rsplitbegin . self::$kvarsep . self::$rsplitend, $output, 2);
+ if (preg_match ('/bootstrap.less/', $path)) {
+ $output = implode ("\n", $arr);
+ } else {
+ $output = count($arr) > 1 ? $arr[1] : $arr[0];
+ }
+
+ //remove comments and clean up
+ $output = preg_replace(self::$rcomment, '', $output);
+ $output = preg_replace(self::$rspace, "\n\n", $output);
+
+ // update url for output
+ $file_contents = self::updateUrl ($output, $path, $todir, $split);
+
+ // split if needed
+ if ($split) {
+ if(!empty($file_contents)){
+ //output the file to content and add to document
+ foreach ($file_contents as $file => $content) {
+ if ($file) {
+ $content = trim($content);
+ $filename = str_replace('/', '.', $file) . '.css';
+ JFile::write(JPATH_ROOT . '/' . $todir . '/' . $filename, $content);
+ }
+ }
+ }
+ } else {
+ if ($topath) {
+ JFile::write(JPATH_ROOT . '/' . $topath, $file_contents);
+ } else {
+ return $output;
+ }
+ }
+ // write to path
+ return true;
+ }
+
+ /**
+ * Update url for background, import according to output path
+ *
+ * @param $css the compiled css
+ * @param $path the source less path
+ * @param $output_dir destination of css file
+ * @param $split split into small files or not
+ * @return if $split then return an array of sub file, else return the whole css
+ */
+ public static function updateUrl ($css, $path, $output_dir, $split) {
+ //update path and store to files
+ $split_contents = preg_split(self::$rsplitbegin . self::$kfilepath . self::$rsplitend, $css, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $file_contents = array();
+ $file = $path;
+ $isfile = false;
+ $output = '';
+
+ // split
+ foreach ($split_contents as $chunk) {
+ if ($isfile) {
+ $isfile = false;
+ $file = $chunk;
+ } else {
+ $content = T3Path::updateUrl (trim($chunk), T3Path::relativePath($output_dir, dirname($file)));
+ $file_contents[$file] = (isset($file_contents[$file]) ? $file_contents[$file] : '') . "\n" . $content . "\n\n";
+ $output .= $content . "\n";
+ $isfile = true;
+ }
+ }
+
+ return $split ? $file_contents : trim($output);
+ }
+
+ /**
+ * Get less variables
+ * @return mixed
+ */
+ public static function getVars($name = '')
+ {
+ return self::getState('vars_' . ($name ? $name.'_' : '') . 'content');
+ }
+
+ /**
+ * get value from cache
+ */
+ public static function getState ($key, $default = null) {
+ $app = JFactory::getApplication();
+ $keysfx = $app->getUserState('current_key_sufix');
+ // cache key
+ $ckey = $key.$keysfx;
+ $group = 't3';
+ $cache = JCache::getInstance('output', array(
+ 'lifetime' => 25200,
+ 'caching' => true,
+ 'cachebase' => JPATH_ROOT.'/'.T3_DEV_FOLDER
+ ));
+
+ // get cache
+ $data = $cache->get($ckey, $group);
+ return $data===false ? $app->getUserState($ckey, $default) : $data;
+ }
+
+ /**
+ * store value to cache
+ */
+ public static function setState ($key, $value) {
+ $app = JFactory::getApplication();
+ $keysfx = $app->getUserState('current_key_sufix');
+ // cache key
+ $ckey = $key.$keysfx;
+ $group = 't3';
+ $cache = JCache::getInstance('output', array(
+ 'lifetime' => 25200,
+ 'caching' => true,
+ 'cachebase' => JPATH_ROOT.'/'.T3_DEV_FOLDER
+ ));
+ if (!$cache->store($value, $ckey, $group)) {
+ $app->setUserState($ckey, $value);
+ }
+ }
+
+ /**
+ * @param string $theme template theme
+ * @param string $dir direction (ltr or rtl)
+ * @return mixed
+ */
+ public static function buildVars($theme = null, $dir = null)
+ {
+ $app = JFactory::getApplication();
+ $params = null;
+ if ($app->isAdmin()) {
+ $params = $app->getUserState ('current_template_params');
+ } else {
+ $tpl = $app->getTemplate(true);
+ $params = $tpl->params;
+ }
+ if (!$params) {
+ T3::error(JText::_('T3_MSG_CANNOT_DETECT_TEMPLATE'));
+ exit;
+ }
+
+ $responsive = $params->get('responsive', 1);
+ // theme style
+ if ($theme === null) {
+ $theme = $params->get('theme');
+ }
+ // detect RTL
+ if ($dir === null) {
+ $doc = JFactory::getDocument();
+ $dir = $doc->direction;
+ }
+ $app->setUserState('current_theme', $theme);
+ $app->setUserState('current_direction', $dir);
+ $app->setUserState('current_key_sufix', "_{$theme}_{$dir}");
+
+ $path = T3_TEMPLATE_PATH . '/less/vars.less';
+ if(!is_file($path)){
+ T3::error(JText::_('T3_MSG_LESS_NOT_VALID'));
+ exit;
+ }
+
+ // force re-build less if switch responsive mode and get last modified time
+ if ($responsive !== self::getState('current_responsive')) {
+ self::setState('current_responsive', $responsive);
+ $last_modified = time();
+ touch($path, $last_modified);
+ } else {
+ $last_modified = filemtime($path);
+ }
+
+ $vars_content = file_get_contents($path);
+ $vars_urls = array();
+
+ preg_match_all('#^\s*@import\s+"([^"]*)"#im', $vars_content, $matches);
+ if (count($matches[0])) {
+ foreach ($matches[1] as $url) {
+ $path = T3Path::cleanPath(T3_TEMPLATE_PATH . '/less/' . $url);
+ if (file_exists($path)) {
+ $last_modified = max($last_modified, filemtime($path));
+ $vars_urls[] = T3Path::cleanPath(T3_TEMPLATE_REL . '/less/' . $url);
+ }
+ }
+ }
+
+ // add override variables
+ $paths = array();
+ if ($theme) {
+ $paths[] = T3_TEMPLATE_REL . "/less/themes/{$theme}/variables.less";
+ $paths[] = T3_TEMPLATE_REL . "/less/themes/{$theme}/variables-custom.less";
+ }
+ if ($dir == 'rtl') {
+ $paths[] = T3_TEMPLATE_REL . "/less/rtl/variables.less";
+ if ($theme) $paths[] = T3_TEMPLATE_REL . "/less/rtl/themes/{$theme}/variables.less";
+ }
+ if (!defined('T3_LOCAL_DISABLED')) {
+ $paths[] = T3_LOCAL_REL . "/less/variables.less";
+ if ($theme) {
+ $paths[] = T3_LOCAL_REL . "/less/themes/{$theme}/variables.less";
+ $paths[] = T3_LOCAL_REL . "/less/themes/{$theme}/variables-custom.less";
+ }
+ if ($dir == 'rtl') {
+ $paths[] = T3_LOCAL_REL . "/less/rtl/variables.less";
+ if ($theme) $paths[] = T3_LOCAL_REL . "/less/rtl/themes/{$theme}/variables.less";
+ }
+ }
+ if (!$responsive) {
+ $paths[] = T3_REL . '/less/non-responsive-variables.less';
+ $paths[] = T3_TEMPLATE_REL . '/less/non-responsive-variables.less';
+ }
+
+ foreach ($paths as $file) {
+ if (is_file(JPATH_ROOT . '/' . $file)) {
+ $last_modified = max($last_modified, filemtime(JPATH_ROOT . '/' . $file));
+ $vars_urls[] = $file;
+ }
+ }
+
+ if (self::getState('vars_last_modified') != $last_modified) {
+ self::setState('vars_last_modified', $last_modified);
+ }
+ self::setState('vars_urls_content', implode('|', $vars_urls));
+ }
+
+ /**
+ * Build vars only one per request
+ */
+ public static function buildVarsOnce(){
+ // build less vars, once only
+ static $vars_built = false;
+ if (!$vars_built) {
+ self::buildVars();
+ $vars_built = true;
+ }
+ }
+
+ /**
+ * Wrapper function to add a stylesheet to html document
+ * @param string $lesspath the less file to add
+ */
+ public static function addStylesheet($lesspath)
+ {
+ //build vars once
+ self::buildVarsOnce();
+
+ $app = JFactory::getApplication();
+ $doc = JFactory::getDocument();
+ $tpl = $app->getTemplate(true);
+ $theme = $tpl->params->get('theme');
+
+ if (defined('T3_THEMER') && $tpl->params->get('themermode', 1)) {
+ // in Themer mode, using js to parse less, so we will use 'text/less' content type
+ $doc->addStylesheet(JURI::base(true) . '/' . T3Path::cleanPath($lesspath), 'text/less');
+
+ // just to make sure this function is call once
+ if(!defined('T3_LESS_JS')){
+ // Add lessjs to process lesscss
+ $doc->addScript(T3_URL . '/js/less.js?v=2');
+
+ if($doc->direction == 'rtl'){
+ $doc->addScript(T3_URL . '/js/cssjanus.js');
+ }
+
+ define('T3_LESS_JS', 1);
+ }
+ } else {
+ self::buildCss(T3Path::cleanPath($lesspath));
+ }
+ }
+
+
+ public static function getOutputCssPath ($lessPath, $theme = '', $is_rtl = false) {
+ $cssPath = '';
+ $extraPath = '';
+ $extraPath .= $is_rtl ? 'rtl/' : '';
+ $extraPath .= $theme ? ($is_rtl ? '' : 'themes/') . $theme . '/' : '';
+
+ if (preg_match ('/(^|\/)less\//i', $lessPath)) {
+ $cssPath = preg_replace ('/(^|\/)less\//i', '\1css/' . $extraPath, $lessPath);
+ } else {
+ $cssPath = dirname ($lessPath) . '/' . $extraPath . basename($lessPath);
+ }
+ $cssPath = str_replace('.less', '.css', $cssPath);
+ return $cssPath;
+ }
+
+
+ /**
+ * Compile LESS to CSS for a specific theme or all themes
+ * @param string $theme the specific theme
+ */
+ public static function compileAll($theme = null)
+ {
+ $params = T3::getTplParams();
+ JFactory::getApplication()->setUserState ('current_template_params', $params);
+
+ // get files need to compile
+ $files = array();
+ $toPath = T3Path::getLocalPath('', true);
+
+ // t3 core plugin files
+ $t3files = array('less/frontend-edit.less', 'less/legacy-grid.less', 'less/legacy-navigation.less', 'less/megamenu.less', 'less/off-canvas.less');
+
+ // all less file in the template folder
+ $lessFiles = JFolder::files(T3_TEMPLATE_PATH, '.less', true, true, array('rtl', 'themes', '.svn', 'CVS', '.DS_Store', '__MACOSX'));
+
+ $relLessFiles = array();
+
+ $importedFiles = array();
+
+ foreach ($lessFiles as $file) {
+ $file = str_replace('\\', '/', $file);
+ $lessContent = file_get_contents($file);
+ $rel = ltrim(str_replace(T3_TEMPLATE_PATH, '', $file), '/');
+ $reldir = dirname ($rel);
+ $ignore = true;
+ if (preg_match_all('#^\s*@import\s+"([^"]*)"#im', $lessContent, $matches)) {
+ foreach ($matches[1] as $if) {
+ $if = T3Path::cleanPath($reldir . '/' . $if);
+ if (!in_array($if, $importedFiles)) $importedFiles[] = $if;
+ // check if this file import anything in main less folder. if yes, put it in the compile list
+ if (preg_match ('@^less/@', $if)) $ignore = false;
+ }
+ }
+ if (!$ignore) $relLessFiles[] = $rel;
+ }
+
+ $lessFiles = $relLessFiles;
+
+ // ignore files which are imported in other file
+ foreach ($lessFiles as $f) {
+ if (!in_array($f, $importedFiles) && !preg_match ('@^less/(themes|rtl)/@i', $f)) {
+ $files[] = $f;
+ }
+ }
+
+ //build t3files
+ foreach ($t3files as $key => $file) {
+ if(in_array($file, $files)){
+ unset($t3files[$key]);
+ }
+ }
+
+ // build default
+ if (!$theme || $theme == 'default') {
+ self::buildVars('', 'ltr');
+
+ // compile all less files in template "less" folder
+ foreach ($files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath);
+ self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+
+ // if the template not overwrite the t3 core, we will compile those missing files
+ if(!empty($t3files)){
+ foreach ($t3files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath);
+ self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+ }
+ }
+
+ // build themes
+ if (!$theme) {
+ // get themes
+ $themes = JFolder::folders(T3_TEMPLATE_PATH . '/less/themes');
+ } else {
+ $themes = $theme != 'default' ? (array)($theme) : array();
+ }
+
+ if (is_array($themes)) {
+ foreach ($themes as $t) {
+ self::buildVars($t, 'ltr');
+
+ // compile
+ foreach ($files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, $t);
+ self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+
+ if(!empty($t3files)){
+ foreach ($t3files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, $t);
+ self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+ }
+ }
+ }
+
+ // compile rtl css
+ if($params && $params->get('build_rtl', 0)){
+ // compile default
+ if (!$theme || $theme == 'default') {
+ self::buildVars('', 'rtl');
+
+ // compile
+ foreach ($files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, '', true);
+ self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+
+ if(!empty($t3files)){
+ foreach ($t3files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, '', true);
+ self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+ }
+ }
+
+ if (is_array($themes)) {
+ // rtl for themes
+ foreach ($themes as $t) {
+ self::buildVars($t, 'rtl');
+
+ // compile
+ foreach ($files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, $t, true);
+ self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+
+ if(!empty($t3files)){
+ foreach ($t3files as $lessPath) {
+ $cssPath = self::getOutputCssPath($lessPath, $t, true);
+ self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse a less file to get all its overrides before compile
+ * @param string $path the less file
+ */
+ public static function parse($path) {
+ $rtpl_check = '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i';
+ $rtpl_less_check = '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/less/@i';
+
+ $app = JFactory::getApplication();
+ $theme = $app->getUserState('current_theme');
+ $dir = $app->getUserState('current_direction');
+ $is_rtl = ($dir == 'rtl');
+
+ $rel_path = preg_replace($rtpl_check, '', $path);
+ $rel_dir = dirname($rel_path);
+ // check path
+ $realpath = realpath(JPATH_ROOT . '/' . $path);
+ if (!is_file($realpath)) {
+ return false;
+ }
+
+ // get file content
+ $content = file_get_contents($realpath);
+
+ //remove vars.less
+ $content = preg_replace(self::$rimportvars, '', $content);
+
+ // split into array, separated by the import
+ $arr = preg_split(self::$rimport, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $arr[] = basename($rel_path);
+ $arr[] = '';
+
+ $list = array();
+ $rtl_list = array();
+ $list[$path] = '';
+ $import = false;
+
+ foreach ($arr as $chunk) {
+ if ($import) {
+ $import = false;
+ $import_url = T3Path::cleanPath(T3_TEMPLATE_REL . '/' . $rel_dir . '/' .$chunk);
+ // if $url in less folder, get all its overrides
+ if (preg_match ($rtpl_less_check, $import_url)) {
+ $less_rel_url = preg_replace($rtpl_less_check, '', $import_url);
+ $array = T3Path::getAllPath('less/' . $less_rel_url, true);
+ if ($theme) {
+ $array = array_merge($array, T3Path::getAllPath('less/themes/'.$theme.'/'.$less_rel_url, true));
+ }
+
+ foreach ($array as $f) {
+ // add file in template only
+ if (preg_match ($rtpl_check, $f)) {
+ $list [$f] = T3Path::relativePath(dirname($path), $f);
+ }
+ }
+
+ // rtl overrides
+ if ($is_rtl) {
+ $array = T3Path::getAllPath('less/rtl/'.$less_rel_url, true);
+ if ($theme) {
+ $array = array_merge($array, T3Path::getAllPath('less/rtl/themes/'.$theme.'/'.$less_rel_url, true));
+ }
+
+ foreach ($array as $f) {
+ // add file in template only
+ if (preg_match ($rtpl_check, $f)) {
+ $rtl_list [$f] = T3Path::relativePath(dirname($path), $f);
+ }
+ }
+ }
+ } else {
+ $list [$import_url] = T3Path::cleanPath($chunk);
+ // rtl override
+ if ($is_rtl) {
+ $rtl_url = preg_replace ('/\/less\//', '/less/rtl/', $import_url);
+ if (is_file(JPATH_ROOT.'/'.$rtl_url)) {
+ $rtl_list [$rtl_url] = T3Path::relativePath(dirname($path), $rtl_url);
+ }
+ }
+ }
+ } else {
+ $import = true;
+ $list [$chunk] = false;
+ }
+ }
+
+ // remove itself
+ unset($list[$path]);
+
+ // join rtl
+ if ($is_rtl) {
+ $list ["\n\n#" . self::$krtlsep . "{content: \"separator\";}\n\n"] = false;
+ $list = array_merge($list, $rtl_list);
+ }
+
+ return $list;
+ }
+
+ public static function cb_import_path ($match) {
+ $f = $match[1];
+ $newf = T3Path::cleanPath(self::$_path . $f);
+ return str_replace($f, $newf, $match[0]);
+ }
+}
diff --git a/plugins/system/t3/includes/core/minify.php b/plugins/system/t3/includes/core/minify.php
new file mode 100644
index 0000000..60658af
--- /dev/null
+++ b/plugins/system/t3/includes/core/minify.php
@@ -0,0 +1,517 @@
+ 'JSMin',
+ 'closurecompiler' => 'Minify_JS_ClosureCompiler'
+ );
+
+ public static $jstool = 'jsmin';
+
+ public static $exclude = '';
+
+ public static function prepare($tpl){
+ //set the compress tool
+ self::$exclude = $tpl->getParam('minify_exclude', '');
+ self::$jstool = $tpl->getParam('minify_js_tool', 'jsmin');
+
+ if(self::$exclude){
+ self::$exclude = '@' . preg_replace('@[,]+@', '|', preg_quote(self::$exclude)) . '@';
+ }
+ }
+
+ /**
+ * @param $css
+ * @return string
+ */
+ public static function minifyCss( $css ) {
+ //T3::import('minify/csscompressor');
+
+ $css = preg_replace( '#\s+#', ' ', $css );
+ $css = preg_replace( '#/\*.*?\*/#s', '', $css );
+ $css = str_replace( '; ', ';', $css );
+ $css = str_replace( ': ', ':', $css );
+ $css = str_replace( ' {', '{', $css );
+ $css = str_replace( '{ ', '{', $css );
+ $css = str_replace( ', ', ',', $css );
+ $css = str_replace( '} ', '}', $css );
+ $css = str_replace( ';}', '}', $css );
+
+ return trim( $css );
+ }
+
+ /**
+ * @param $js
+ * @return string
+ */
+ public static function minifyJs( $js ){
+
+ T3::import('minify/' . self::$jstool);
+ return call_user_func_array(array(self::$jstools[self::$jstool], 'minify'), array($js));
+ }
+
+ /**
+ *
+ * Check and convert to css real path
+ * @param string $url url to check
+ * @return mixed the css file path or false if not exist in server
+ */
+ public static function cssPath($url = '') {
+
+ //exclude
+ if(self::$exclude && preg_match(self::$exclude, $url)){
+ return false;
+ }
+
+ $url = preg_replace('#[?\#]+.*$#', '', $url);
+ $base = JURI::base();
+ $root = JURI::root(true);
+ $ret = false;
+
+ if(substr($url, 0, 2) === '//'){ //check and append if url is omit http
+ $url = JURI::getInstance()->getScheme() . ':' . $url;
+ }
+
+ //check for css file extensions
+ foreach ( self::$cssexts as $ext ) {
+ if (strlen($ext) <= strlen($url) && substr_compare($url, $ext, -strlen($ext), strlen($ext)) === 0) {
+ $ret = true;
+ break;
+ }
+ }
+
+ if($ret){
+ if (preg_match('/^https?\:/', $url)) { //is full link
+ if (strpos($url, $base) === false){
+ // external css
+ return false;
+ }
+
+ $path = JPath::clean(JPATH_ROOT . '/' . substr($url, strlen($base)));
+ } else {
+ $path = JPath::clean(JPATH_ROOT . '/' . ($root && strpos($url, $root) === 0 ? substr($url, strlen($root)) : $url));
+ }
+
+ return is_file($path) ? $path : false;
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ * Check and convert to css real path
+ * @param string $url url to check
+ * @return mixed the css file path or false if not exist in server
+ */
+ public static function jsPath($url = '') {
+
+ //leave any javascript file that have parameter (K2 is an example)
+ if(preg_match('@[?#]+.*$@', $url)){
+ return false;
+ }
+
+ //exclude
+ if(self::$exclude && preg_match(self::$exclude, $url)){
+ return false;
+ }
+
+ //clean
+ $url = preg_replace('@[?#]+.*$@', '', $url);
+ $base = JURI::base();
+ $root = JURI::root(true);
+ $ret = false;
+
+ if(substr($url, 0, 2) === '//'){ //check and append if url is omit http
+ $url = JURI::getInstance()->getScheme() . ':' . $url;
+ }
+
+ //check for css file extensions
+ foreach ( self::$jsexts as $ext ) {
+ if (strlen($ext) <= strlen($url) && substr_compare($url, $ext, -strlen($ext), strlen($ext)) === 0) {
+ $ret = true;
+ break;
+ }
+ }
+
+ if($ret){
+ if (preg_match('/^https?\:/', $url)) { //is full link
+ if (strpos($url, $base) === false){
+ // external css
+ return false;
+ }
+
+ $path = JPath::clean(JPATH_ROOT . '/' . substr($url, strlen($base)));
+ } else {
+ $path = JPath::clean(JPATH_ROOT . '/' . ($root && strpos($url, $root) === 0 ? substr($url, strlen($root)) : $url));
+ }
+
+ return is_file($path) ? $path : false;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $url url to refine
+ * @return string the refined url
+ */
+ public static function fixUrl($url = ''){
+ return ($url[0] === '/' || strpos($url, '://') !== false) ? $url : JURI::base(true) . '/' . $url;
+ }
+
+ /**
+ * @param $tpl template object
+ * @return bool optimize success or not
+ */
+ public static function optimizecss($tpl)
+ {
+ $outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css';
+ $outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css';
+
+ if (!JFile::exists($outputpath)){
+ JFolder::create($outputpath);
+ @chmod($outputpath, 0755);
+ }
+
+ if (!is_writeable($outputpath)) {
+ return false;
+ }
+
+ //prepare config
+ self::prepare($tpl);
+
+ $doc = JFactory::getDocument();
+
+ //======================= Group css ================= //
+ $mediagroup = array();
+ $cssgroups = array();
+ $stylesheets = array();
+ $ielimit = 4095;
+ $selcounts = 0;
+ $regex = '/\{.+?\}|,/s'; //selector counter
+ $csspath = '';
+
+ // group css into media
+ $mediagroup['all'] = array();
+ $mediagroup['screen'] = array();
+ foreach ($doc->_styleSheets as $url => $stylesheet) {
+ $media = $stylesheet['media'] ? $stylesheet['media'] : 'all';
+ if (empty($mediagroup[$media])) {
+ $mediagroup[$media] = array();
+ }
+ $mediagroup[$media][$url] = $stylesheet;
+ }
+
+ foreach ($mediagroup as $media => $group) {
+ $stylesheets = array(); // empty - begin a new group
+ foreach ($group as $url => $stylesheet) {
+ $url = self::fixUrl($url);
+
+ if ($stylesheet['mime'] == 'text/css' && ($csspath = self::cssPath($url))) {
+ $stylesheet['path'] = $csspath;
+ $stylesheet['data'] = file_get_contents($csspath);
+
+ $selcount = preg_match_all($regex, $stylesheet['data'], $matched);
+ if(!$selcount) {
+ $selcount = 1; //just for sure
+ }
+
+ //if we found an @import rule or reach IE limit css selector count, break into the new group
+ if (preg_match('#@import\s+.+#', $stylesheet['data']) || $selcounts + $selcount >= $ielimit) {
+ if(count($stylesheets)){
+ $cssgroup = array();
+ $groupname = array();
+ foreach ( $stylesheets as $gurl => $gsheet ) {
+ $cssgroup[$gurl] = $gsheet;
+ $groupname[] = $gurl;
+ }
+
+ $cssgroup['groupname'] = implode('', $groupname);
+ $cssgroup['media'] = $media;
+ $cssgroups[] = $cssgroup;
+ }
+
+ $stylesheets = array($url => $stylesheet); // empty - begin a new group
+ $selcounts = $selcount;
+ } else {
+
+ $stylesheets[$url] = $stylesheet;
+ $selcounts += $selcount;
+ }
+
+ } else {
+ // first get all the stylsheets up to this point, and get them into
+ // the items array
+ if(count($stylesheets)){
+ $cssgroup = array();
+ $groupname = array();
+ foreach ( $stylesheets as $gurl => $gsheet ) {
+ $cssgroup[$gurl] = $gsheet;
+ $groupname[] = $gurl;
+ }
+
+ $cssgroup['groupname'] = implode('', $groupname);
+ $cssgroup['media'] = $media;
+ $cssgroups[] = $cssgroup;
+ }
+
+ //mark ignore current stylesheet
+ $cssgroup = array($url => $stylesheet, 'ignore' => true);
+ $cssgroups[] = $cssgroup;
+
+ $stylesheets = array(); // empty - begin a new group
+ }
+ }
+
+ if(count($stylesheets)){
+ $cssgroup = array();
+ $groupname = array();
+ foreach ( $stylesheets as $gurl => $gsheet ) {
+ $cssgroup[$gurl] = $gsheet;
+ $groupname[] = $gurl;
+ }
+
+ $cssgroup['groupname'] = implode('', $groupname);
+ $cssgroup['media'] = $media;
+ $cssgroups[] = $cssgroup;
+ }
+ }
+
+ //======================= Group css ================= //
+
+ $output = array();
+ foreach ($cssgroups as $cssgroup) {
+ if(isset($cssgroup['ignore'])){
+ unset($cssgroup['ignore']);
+ unset($cssgroup['groupname']);
+ unset($cssgroup['media']);
+ foreach ($cssgroup as $furl => $fsheet) {
+ $output[$furl] = $fsheet;
+ }
+ } else {
+ $media = $cssgroup['media'];
+ $groupname = 'css-' . substr(md5($cssgroup['groupname']), 0, 5) . '.css';
+ $groupfile = $outputpath . '/' . $groupname;
+ $grouptime = JFile::exists($groupfile) ? @filemtime($groupfile) : -1;
+ $rebuild = $grouptime < 0; //filemtime == -1 => rebuild
+
+ unset($cssgroup['groupname']);
+ unset($cssgroup['media']);
+ foreach ($cssgroup as $furl => $fsheet) {
+ if(!$rebuild && @filemtime($fsheet['path']) > $grouptime){
+ $rebuild = true;
+ }
+ }
+
+ if($rebuild){
+ $cssdata = array();
+ foreach ($cssgroup as $furl => $fsheet) {
+ $cssdata[] = "\n\n/*===============================";
+ $cssdata[] = $furl;
+ $cssdata[] = "================================================================================*/";
+
+ $cssmin = self::minifyCss($fsheet['data']);
+ $cssmin = T3Path::updateUrl($cssmin, T3Path::relativePath($outputurl, dirname($furl)));
+
+ $cssdata[] = $cssmin;
+ }
+
+ $cssdata = implode("\n", $cssdata);
+ if (!JFile::write($groupfile, $cssdata)) {
+ // cannot write file, ignore minify
+ return false;
+ }
+ $grouptime = @filemtime($groupfile);
+ @chmod($groupfile, 0644);
+ }
+
+ $output[$outputurl . '/' . $groupname.'?t='.($grouptime % 1000)] = array(
+ 'mime' => 'text/css',
+ 'media' => $media == 'all' ? NULL : $media,
+ 'attribs' => array()
+ );
+ }
+ }
+
+ //apply the change make change
+ $doc->_styleSheets = $output;
+ }
+
+ /**
+ * Optimize javascript
+ * @param $tpl
+ * @return bool
+ */
+ public static function optimizejs($tpl){
+ $outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/js';
+ $outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/js';
+
+ if (!JFile::exists($outputpath)){
+ JFolder::create($outputpath);
+ @chmod($outputpath, 0755);
+ }
+
+ if (!is_writeable($outputpath)) {
+ return false;
+ }
+
+ //prepare config
+ self::prepare($tpl);
+
+ $doc = JFactory::getDocument();
+
+ //======================= Group css ================= //
+ $jsgroups = array();
+ $scripts = array();
+
+ foreach ($doc->_scripts as $url => $script) {
+
+ $url = self::fixUrl($url);
+
+ if ($script['mime'] == 'text/javascript' && ($jspath = self::jsPath($url))) {
+
+ $script['path'] = $jspath;
+ $script['data'] = file_get_contents($jspath);
+
+ $scripts[$url] = $script;
+
+ } else {
+ // first get all the stylsheets up to this point, and get them into
+ // the items array
+ if(count($scripts)){
+ $jsgroup = array();
+ $groupname = array();
+ foreach ( $scripts as $gurl => $gsheet ) {
+ $jsgroup[$gurl] = $gsheet;
+ $groupname[] = $gurl;
+ }
+
+ $jsgroup['groupname'] = implode('', $groupname);
+ $jsgroups[] = $jsgroup;
+ }
+
+ //mark ignore current script
+ $jsgroup = array($url => $script, 'ignore' => true);
+ $jsgroups[] = $jsgroup;
+
+ $scripts = array(); // empty - begin a new group
+ }
+ }
+
+ if(count($scripts)){
+ $jsgroup = array();
+ $groupname = array();
+ foreach ( $scripts as $gurl => $gsheet ) {
+ $jsgroup[$gurl] = $gsheet;
+ $groupname[] = $gurl;
+ }
+
+ $jsgroup['groupname'] = implode('', $groupname);
+ $jsgroups[] = $jsgroup;
+ }
+
+ //======================= Group js ================= //
+
+ $output = array();
+ foreach ($jsgroups as $jsgroup) {
+ if(isset($jsgroup['ignore'])){
+
+ unset($jsgroup['ignore']);
+ foreach ($jsgroup as $furl => $fsheet) {
+ $output[$furl] = $fsheet;
+ }
+
+ } else {
+
+ $groupname = 'js-' . substr(md5($jsgroup['groupname']), 0, 5) . '.js';
+ $groupfile = $outputpath . '/' . $groupname;
+ $grouptime = JFile::exists($groupfile) ? @filemtime($groupfile) : -1;
+ $rebuild = $grouptime < 0; //filemtime == -1 => rebuild
+
+ unset($jsgroup['groupname']);
+ foreach ($jsgroup as $furl => $fsheet) {
+ if(!$rebuild && @filemtime($fsheet['path']) > $grouptime){
+ $rebuild = true;
+ }
+ }
+
+ if($rebuild){
+
+ $jsdata = array();
+ foreach ($jsgroup as $furl => $fsheet) {
+ $jsdata[] = "\n\n/*===============================";
+ $jsdata[] = $furl;
+ $jsdata[] = "================================================================================*/;";
+
+ $jsmin = $fsheet['data'];
+
+ //already minify?
+ if(!preg_match('@.*\.min\.js.*@', $furl)){
+ $jsmin = self::minifyJs($fsheet['data']);
+ //$jsmin = T3Path::updateUrl($jsmin, T3Path::relativePath($outputurl, dirname($furl)));
+ }
+
+ $jsdata[] = $jsmin;
+ }
+
+ $jsdata = implode("\n", $jsdata);
+ if (!JFile::write($groupfile, $jsdata)) {
+ // cannot write file, ignore optimize
+ return false;
+ }
+ $grouptime = @filemtime($groupfile);
+ @chmod($groupfile, 0644);
+ }
+
+ $output[$outputurl . '/' . $groupname.'?t='.($grouptime % 1000)] = array(
+ 'mime' => 'text/javascript',
+ 'defer' => false,
+ 'async' => false
+ );
+ }
+ }
+
+ //apply the change make change
+ $doc->_scripts = $output;
+ }
+}
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/includes/core/path.php b/plugins/system/t3/includes/core/path.php
new file mode 100644
index 0000000..77f2092
--- /dev/null
+++ b/plugins/system/t3/includes/core/path.php
@@ -0,0 +1,219 @@
+ $sub) {
+ $sub++;
+ }
+ }
+ }
+ }
+
+ if (empty($root)) {
+ $root = str_repeat('../', $sub);
+ }
+
+ return $root . implode('/', array_slice($newDirs, 0, $offset));
+ }
+
+ public static function relativePath($path1, $path2 = '')
+ {
+ // config params
+ if ($path2 == '') {
+ $path2 = $path1;
+ $path1 = getcwd();
+ }
+
+ // absolute path //has protocol //data protocol
+ if ($path2[0] === '/' || strpos($path2, '://') !== false || strpos($path2, 'data:') === 0) {
+ return $path2;
+ }
+
+ //Remove starting, ending, and double / in paths
+ $path1 = trim($path1, '/');
+ $path2 = trim($path2, '/');
+ while (substr_count($path1, '//')) $path1 = str_replace('//', '/', $path1);
+ while (substr_count($path2, '//')) $path2 = str_replace('//', '/', $path2);
+
+ //create arrays
+ $arr1 = explode('/', $path1);
+ if ($arr1 == array('')) $arr1 = array();
+ $arr2 = explode('/', $path2);
+ if ($arr2 == array('')) $arr2 = array();
+ $size1 = count($arr1);
+ $size2 = count($arr2);
+
+ //now the hard part :-p
+ $path = '';
+ for ($i = 0; $i < min($size1, $size2); $i++) {
+ if ($arr1[$i] == $arr2[$i]) continue;
+ else break;
+ }
+ for ($j=$i; $j $size2)
+ for ($i = $size2; $i < $size1; $i++)
+ $path = '../' . $path;
+ else if ($size2 > $size1)
+ for ($i = $size1; $i < $size2; $i++)
+ $path .= $arr2[$i] . '/';
+
+ return rtrim($path, '/');
+ }
+
+ public static function updateUrl($css, $src)
+ {
+ self::$srcurl = rtrim($src, '/');
+
+ $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/', array('T3Path', 'replaceurl'), $css);
+ $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/', array('T3Path', 'replaceurl'), $css);
+
+ return $css;
+ }
+
+ public static function replaceurl($matches)
+ {
+ $isImport = ($matches[0][0] === '@');
+ // determine URI and the quote character (if any)
+ if ($isImport) {
+ $quoteChar = $matches[1];
+ $uri = $matches[2];
+ } else {
+ // $matches[1] is either quoted or not
+ $quoteChar = ($matches[1][0] === "'" || $matches[1][0] === '"')
+ ? $matches[1][0]
+ : '';
+ $uri = ($quoteChar === '')
+ ? $matches[1]
+ : substr($matches[1], 1, strlen($matches[1]) - 2);
+ }
+
+ // root-relative protocol (non-data) data protocol
+ if ($uri[0] !== '/' && strpos($uri, '://') === false && strpos($uri, 'data:') !== 0) {
+ $uri = self::cleanPath(self::$srcurl . '/' . $uri);
+ }
+
+ return $isImport
+ ? "@import {$quoteChar}{$uri}{$quoteChar}"
+ : "url({$quoteChar}{$uri}{$quoteChar})";
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/core/t3.php b/plugins/system/t3/includes/core/t3.php
new file mode 100644
index 0000000..c5400c0
--- /dev/null
+++ b/plugins/system/t3/includes/core/t3.php
@@ -0,0 +1,480 @@
+isAdmin() ? self::getAdmin() : self::getSite($tpl);
+ }
+
+ return self::$t3app;
+ }
+
+ /**
+ * initialize T3
+ */
+ public static function init ($xml) {
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $coretheme = isset($xml->t3) && isset($xml->t3->base) ? trim((string)$xml->t3->base) : 'base';
+
+ // check coretheme in media/t3/themes folder
+ // if not exists, use default base theme in T3
+ if (!$coretheme){
+ $coretheme = 'base';
+ }
+
+ foreach(array(T3_EX_BASE_PATH, T3_ADMIN_PATH) as $basedir){
+ if(is_dir($basedir . '/' . $coretheme)){
+
+ if(is_file($basedir . '/' . $coretheme . '/define.php')){
+ include_once ($basedir . '/' . $coretheme . '/define.php');
+ }
+
+ break;
+ }
+ }
+
+ if(!defined('T3')){
+ // get ready for the t3 core base theme
+ include_once (T3_CORE_BASE_PATH . '/define.php');
+ }
+
+ if(!defined('T3')){
+ T3::error(JText::sprintf('T3_MSG_FAILED_INIT_BASE', $coretheme));
+ exit;
+ }
+
+ define ('T3_TEMPLATE', $xml->tplname);
+ define ('T3_TEMPLATE_URL', JURI::root(true).'/templates/'.T3_TEMPLATE);
+ define ('T3_TEMPLATE_PATH', str_replace ('\\', '/', JPATH_ROOT) . '/templates/' . T3_TEMPLATE);
+ define ('T3_TEMPLATE_REL', 'templates/' . T3_TEMPLATE);
+
+ define ('T3_LOCAL_URL', T3_TEMPLATE_URL . '/' . T3_LOCAL_DIR);
+ define ('T3_LOCAL_PATH', T3_TEMPLATE_PATH . '/' . T3_LOCAL_DIR);
+ define ('T3_LOCAL_REL', T3_TEMPLATE_REL . '/' . T3_LOCAL_DIR);
+
+ if ($input->getCmd('themer', 0)){
+ define ('T3_THEMER', 1);
+ }
+
+ if (!$app->isAdmin()) {
+ $params = $app->getTemplate(true)->params;
+ define ('T3_DEV_FOLDER', $params->get ('t3-assets', 't3-assets') . '/dev');
+ define ('T3_DEV_MODE', $params->get ('devmode', 0));
+ } else {
+ $params = self::getTemplate()->params;
+ define ('T3_DEV_FOLDER', $params->get ('t3-assets', 't3-assets') . '/dev');
+ }
+ if (!is_dir(JPATH_ROOT.'/'.T3_DEV_FOLDER)) {
+ jimport('joomla.filesystem.folder');
+ JFolder::create(JPATH_ROOT.'/'.T3_DEV_FOLDER);
+ }
+
+ if($input->getCmd('t3lock', '')){
+ JFactory::getSession()->set('T3.t3lock', $input->getCmd('t3lock', ''));
+ $input->set('t3lock', null);
+ }
+
+ // load core library
+ T3::import ('core/path');
+ T3::import ('core/t3j');
+
+ if (!$app->isAdmin()) {
+ if(version_compare(JVERSION, '3.0', 'ge')){
+ // override core joomla class
+ // JViewLegacy
+ T3::register('JViewLegacy', T3_ADMIN_PATH . '/includes/joomla30/viewlegacy.php');
+ // JModuleHelper
+ T3::register('JModuleHelper', T3_ADMIN_PATH . '/includes/joomla30/modulehelper.php');
+ // JPagination
+ T3::register('JPagination', T3_ADMIN_PATH . '/includes/joomla30/pagination.php');
+ // Register T3 Layout File to put a t3 base layer for layout files
+ T3::register('JLayoutFile', T3_ADMIN_PATH . '/includes/joomla25/layout/file.php');
+ } else {
+ // override core joomla class
+ // JView
+ T3::register('JView', T3_ADMIN_PATH . '/includes/joomla25/view.php', 'joomla.application.component.view');
+ // JModuleHelper
+ T3::register('JModuleHelper', T3_ADMIN_PATH . '/includes/joomla25/modulehelper.php', 'joomla.application.module.helper');
+ // JPagination
+ T3::register('JPagination', T3_ADMIN_PATH . '/includes/joomla25/pagination.php', 'joomla.html.pagination');
+
+ //register layout
+ T3::register('JLayout', T3_ADMIN_PATH . '/includes/joomla25/layout/layout.php');
+ T3::register('JLayoutBase', T3_ADMIN_PATH . '/includes/joomla25/layout/base.php');
+ T3::register('JLayoutFile', T3_ADMIN_PATH . '/includes/joomla25/layout/file.php');
+ T3::register('JLayoutHelper', T3_ADMIN_PATH . '/includes/joomla25/layout/helper.php');
+ T3::register('JHtmlBootstrap', T3_ADMIN_PATH . '/includes/joomla25/html/bootstrap.php');
+ T3::register('JHtmlBehavior', T3_ADMIN_PATH . '/includes/joomla25/html/behavior.php');
+ T3::register('JHtmlString', T3_ADMIN_PATH . '/includes/joomla25/html/string.php');
+
+ // load j25 compat language
+ JFactory::getLanguage()->load('plg_system_t3.j25.compat', JPATH_ADMINISTRATOR);
+ }
+
+ // import renderer
+ T3::import('renderer/pageclass');
+ T3::import('renderer/megamenu');
+ T3::import('renderer/t3bootstrap');
+ } else {
+
+ }
+
+ // capture for tm=1 => show theme magic
+ if ($input->getCmd('tm') == 1) {
+ $input->set('t3action', 'theme');
+ $input->set('t3task', 'thememagic');
+ }
+ }
+
+ public static function checkAction () {
+ // excute action by T3
+ if ($action = JFactory::getApplication()->input->getCmd ('t3action')) {
+ T3::import ('core/action');
+ T3Action::run ($action);
+ }
+ }
+
+ /**
+ * check for t3ajax action
+ */
+ public static function checkAjax () {
+ // excute action by T3
+ $input = JFactory::getApplication()->input;
+
+ if ($input->getCmd ('t3ajax')) {
+ T3::import('core/ajax');
+ T3::import('renderer/t3ajax');
+
+ //T3Ajax::processAjaxRule();
+
+ JFactory::getApplication()->getTemplate(true)->params->set('mainlayout', 'ajax.' . $input->getCmd('f', 'html'));
+ }
+ }
+
+ /**
+ * get T3Admin object
+ * @return T3Admin
+ */
+ public static function getAdmin(){
+ T3::import ('core/admin');
+ return new T3Admin();
+ }
+
+ /**
+ * get T3Template object for frontend
+ * @param $tpl
+ * @return bool
+ */
+ public static function getSite($tpl){
+ //when on site, the JDocumentHTML parameter must be pass
+ if(empty($tpl)){
+ return false;
+ }
+
+ $type = 'Template'. JFactory::getApplication()->input->getCmd ('t3tp', '');
+ T3::import ('core/' . $type);
+
+ // create global t3 template object
+ $class = 'T3' . $type;
+ return new $class($tpl);
+ }
+
+ /**
+ * @param $msg
+ * @param int $code
+ * @throws Exception
+ */
+ public static function error($msg, $code = 500){
+ if (JError::$legacy) {
+ JError::setErrorHandling(E_ERROR, 'die');
+ JError::raiseError($code, $msg);
+
+ exit;
+ } else {
+ throw new Exception($msg, $code);
+ }
+ }
+
+ /**
+ * detect function to check a current template is T3 template
+ * @return bool|SimpleXMLElement
+ */
+ public static function detect(){
+ static $t3;
+
+ if (!isset($t3)) {
+ $t3 = false; // set false
+ $app = JFactory::getApplication();
+ $input = $app->input;
+
+ // get template name
+ $tplname = '';
+
+ if($input->getCmd ('t3action') && $input->getInt('styleid', '')) {
+
+ $tplname = self::getTemplate(true);
+
+ } elseif ($app->isAdmin()) {
+ // if not login, do nothing
+ $user = JFactory::getUser();
+ if (!$user->id){
+ return false;
+ }
+
+ if($input->getCmd('option') == 'com_templates' &&
+ (preg_match('/style\./', $input->getCmd('task')) ||
+ $input->getCmd('view') == 'style' ||
+ $input->getCmd('view') == 'template')){
+
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $id = $input->getInt('id');
+
+ //when in POST the view parameter does not set
+ if ($input->getCmd('view') == 'template') {
+ $query
+ ->select('element')
+ ->from('#__extensions')
+ ->where('extension_id='.(int)$id . ' AND type=' . $db->quote('template'));
+ } else {
+ $query
+ ->select('template')
+ ->from('#__template_styles')
+ ->where('id='.(int)$id);
+ }
+
+ $db->setQuery($query);
+ $tplname = $db->loadResult();
+ }
+
+ } else {
+ $tplname = $app->getTemplate(false);
+ }
+
+ if ($tplname) {
+ // parse xml
+ $filePath = JPath::clean(JPATH_ROOT.'/templates/'.$tplname.'/templateDetails.xml');
+ if (is_file ($filePath)) {
+ $xml = $xml = simplexml_load_file($filePath);
+ // check t3 or group=t3 (compatible with previous definition)
+ if (isset($xml->t3) || (isset($xml->group) && strtolower($xml->group) == 't3')) {
+ $xml->tplname = $tplname;
+ $t3 = $xml;
+ }
+ }
+ }
+ }
+ return $t3;
+ }
+
+ /**
+ * get default template style
+ */
+ public static function getDefaultTemplate($name = false){
+ static $template;
+
+ if (!isset($template)) {
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('id, home, template, s.params')
+ ->from('#__template_styles as s')
+ ->where('s.client_id = 0')
+ ->where('s.home = 1')
+ ->where('e.enabled = 1')
+ ->leftJoin('#__extensions as e ON e.element=s.template AND e.type='.$db->quote('template').' AND e.client_id=s.client_id');
+
+ $db->setQuery($query);
+ $result = $db->loadObject();
+
+ $template = !empty($result) ? $result : false;
+ }
+
+ if($name && $template){
+ return $template->template;
+ }
+
+ return $template;
+ }
+
+ /**
+ * get the template object or template name
+ * @param bool $name
+ * @return mixed template object or template name
+ */
+ public static function getTemplate($name = false)
+ {
+ if(!isset(self::$tmpl) || !self::$tmpl){
+
+ $app = JFactory::getApplication();
+ $input = $app->input;
+ $id = $input->getInt('styleid', $input->getInt('id'));
+
+ if($id){
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('template, params')
+ ->from('#__template_styles')
+ ->where('client_id = 0');
+
+ if($app->isAdmin() && $input->get('view') == 'template' && defined('T3_TEMPLATE')){
+ $query->where('template='. $db->quote(T3_TEMPLATE));
+ } else {
+ $query->where('id='. $id);
+ }
+
+ $db->setQuery($query);
+ $template = $db->loadObject();
+
+ if ($template) {
+ $registry = new JRegistry;
+ $registry->loadString($template->params);
+ $template->params = $registry;
+ }
+
+ self::$tmpl = $template;
+ }
+ }
+
+ if($name && self::$tmpl){
+ return self::$tmpl->template;
+ }
+
+ return self::$tmpl;
+ }
+
+ /**
+ * set caching template and its parameters
+ * @param string $name
+ * @param string $params
+ */
+ public static function setTemplate($name = '', $params = ''){
+ if(!self::$tmpl){
+ self::$tmpl = new stdClass;
+ }
+
+ if($name && $params){
+ self::$tmpl->template = $name;
+ self::$tmpl->params = $params;
+ }
+ }
+
+ /**
+ * get template parameters
+ * @return JRegistry
+ */
+ public static function getTplParams()
+ {
+ $tmpl = self::getTemplate();
+ return $tmpl ? $tmpl->params : new JRegistry; //empty registry ? or throw error
+ }
+
+ /**
+ * check if current page is homepage
+ */
+ public static function isHome(){
+ $active = JFactory::getApplication()->getMenu()->getActive();
+ return (!$active || $active->home);
+ }
+
+ /**
+ * fix ja back link
+ * @param $buffer
+ * @return mixed
+ */
+ public static function fixJALink($buffer){
+
+ if(!self::isHome()){
+ $buffer = preg_replace_callback('@]*>JoomlArt.com @i', array('T3', 'removeBacklink'), $buffer);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * fix t3-framework.org back link
+ * @param $buffer
+ * @return mixed
+ */
+ public static function fixT3Link($buffer){
+ if(!self::isHome()){
+ $buffer = preg_replace_callback('@]*>([^>]*)>T3 Framework @mi', array('T3', 'removeBacklink'), $buffer);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * check nofollow attribute
+ * @param $match
+ * @return mixed
+ */
+ public static function removeBacklink($match){
+
+ if($match && isset($match[0]) && strpos($match[0], 'rel="nofollow"') === false){
+ $match[0] = str_replace('' . $title . '';
+ }
+
+ // Return the formated sting combining the title and content.
+ if ($content != '')
+ {
+ return '' . $title . ' ' . $content;
+ }
+
+ // Return only the title.
+ return $title;
+ }
+}
diff --git a/plugins/system/t3/includes/core/template.php b/plugins/system/t3/includes/core/template.php
new file mode 100644
index 0000000..96a2bf9
--- /dev/null
+++ b/plugins/system/t3/includes/core/template.php
@@ -0,0 +1,1253 @@
+ 6, 'wide' => 6, 'normal' => 6, 'xtablet' => 4, 'tablet' => 3, 'mobile' => 2);
+ protected $minspan = array('default' => 2, 'wide' => 2, 'normal' => 2, 'xtablet' => 3, 'tablet' => 4, 'mobile' => 6);
+ protected $prefixes = array('span');
+
+ /**
+ * Current template instance
+ */
+ public $_tpl = null;
+
+
+ /**
+ * Store layout settings if exist
+ */
+ protected $_layoutsettings = null;
+
+
+ /**
+ * page class
+ */
+ protected $_pageclass = array();
+
+
+ /**
+ * Class constructor
+ *
+ * @param object $template Current template instance
+ */
+ public function __construct($template = null)
+ {
+ // merge the base theme information
+ $this->maxgrid = T3_BASE_MAX_GRID;
+ $this->widthprefix = T3_BASE_WIDTH_PREFIX;
+ $this->nonrspprefix = T3_BASE_NONRSP_WIDTH_PREFIX;
+ $this->spancls = T3_BASE_WIDTH_REGEX;
+ $this->responcls = T3_BASE_RSP_IN_CLASS;
+ $this->rowfluidcls = T3_BASE_ROW_FLUID_PREFIX;
+ $this->defdv = T3_BASE_DEFAULT_DEVICE;
+ $this->devices = json_decode(T3_BASE_DEVICES, true);
+ $this->maxcol = json_decode(T3_BASE_DV_MAXCOL, true);
+ $this->minspan = json_decode(T3_BASE_DV_MINWIDTH, true);
+ $this->prefixes = json_decode(T3_BASE_DV_PREFIX, true);
+
+ // layout settings
+ $this->_layoutsettings = new JRegistry;
+
+ if ($template) {
+ $this->_tpl = $template;
+ $this->_extend(array($template));
+
+ // merge layout setting
+ $layout = JFactory::getApplication()->input->getCmd('t3layout', '');
+ if (empty($layout)) {
+ $layout = $template->params->get('mainlayout', 'default');
+ }
+
+ $fconfig = T3Path::getPath('etc/layout/' . $layout . '.ini');
+ if (is_file($fconfig)) {
+ jimport('joomla.filesystem.file');
+ $this->_layoutsettings->loadString(JFile::read($fconfig), 'INI', array('processSections' => true));
+ }
+ }
+
+ JDispatcher::getInstance()->trigger('onT3TplInit', array($this));
+ }
+
+
+ /**
+ * Get template parameter
+ * @param string $name parameter name
+ * @param mixed $default parameter default value
+ *
+ * @return mixed parameter value
+ */
+ public function getParam($name, $default = null)
+ {
+ return $this->_tpl->params->get($name, $default);
+ }
+
+
+ /**
+ * Set template parameter. It will not store to database. This should not be used
+ * @param string $name parameter name
+ * @param mixed $value parameter value
+ *
+ * @return null
+ */
+ public function setParam($name, $value)
+ {
+ return $this->_tpl->params->set($name, $value);
+ }
+
+
+ /**
+ * Get current layout tpls
+ *
+ * @return string Layout name
+ */
+ public function getLayout()
+ {
+ $input = JFactory::getApplication()->input;
+ return $input->getCmd('tmpl') ? $input->getCmd('tmpl') : $this->getParam('mainlayout', 'default');
+ }
+
+
+ /**
+ * Get layout settings (Layout Tab)
+ * @param string $name parameter name
+ * @param mixed $default parameter default value
+ *
+ * @return string Layout name
+ */
+ public function getLayoutSetting($name, $default = null)
+ {
+ return isset($this->_layoutsettings) ? $this->_layoutsettings->get($name, $default) : $default;
+ }
+
+
+ /**
+ * Load block content
+ * @param string $block Block name - the real block is tpls/blocks/[block].php
+ * @param array $vars information of block (used in template layout)
+ *
+ * @return string Block content
+ */
+ function loadBlock($block, $vars = array())
+ {
+ $path = T3Path::getPath('tpls/blocks/' . $block . '.php');
+ if ($path) {
+ if($block == 'footer'){
+
+ ob_start();
+ include $path;
+ $buffer = ob_get_contents();
+ ob_end_clean();
+ $buffer = T3::fixT3Link($buffer);
+ echo $buffer;
+
+ } else {
+ include $path;
+ }
+ } else {
+ echo "Block [$block] not found!
";
+ }
+ }
+
+
+ /**
+ * Load block layout
+ *
+ * @param string &layout Block name - the real block is tpls/[layout].php
+ *
+ * @return null
+ */
+ function loadLayout($layout)
+ {
+ $path = T3Path::getPath('tpls/' . $layout . '.php', 'tpls/default.php');
+
+ JDispatcher::getInstance()->trigger('onT3LoadLayout', array(&$path, $layout));
+
+ if (is_file($path)) {
+
+ ob_start();
+ include $path;
+ $buffer = ob_get_contents();
+ ob_end_clean();
+ if($this->responcls && !$this->getParam('responsive', 1)){
+ //replace
+ $buffer = preg_replace_callback('@class\s?=\s?(\'|")(([^\'"]*)(' . implode('|', $this->prefixes) . ')+([^\'"]*))(\'|")@m', array($this, 'responCls'), $buffer);
+ }
+ // check if exist megamenu renderer, place megamenurender on the top to render megamenu before render head
+ if (preg_match_all ('/(]*>)/i', $buffer, $match)) {
+ foreach ($match[1] as $m) {
+ $buffer = str_replace ('type="megamenu"', 'type="megamenurender"', $m).$buffer;
+ T3::import('renderer/megamenurender');
+ }
+ }
+ //output
+ echo $buffer;
+
+ } else {
+ echo "Layout [$layout] or [Default] not found!
";
+ }
+ }
+
+ /**
+ * Load spotlight block
+ * @param string $name Name of the spotlight. Default will load positions base on this name: [name]-1, [name]-2...
+ * @param string $positions The positions of spotlight, separated by comma
+ * @param array $info Other information of spotlight
+ *
+ * @return null
+ */
+ function spotlight($name, $positions, array $info = array())
+ {
+ $defdv = $this->defdv;
+ $defpos = preg_split('/\s*,\s*/', $positions);
+ $vars = is_array($info) ? $info : array();
+ $cols = count($defpos);
+ $poss = $defpos;
+
+ $splparams = array();
+ for ($i = 1; $i <= $this->maxgrid; $i++) {
+ $param = $this->getLayoutSetting('block' . $i . '@' . $name);
+ if (empty($param)) {
+ break;
+ } else {
+ $splparams[] = $param;
+ }
+ }
+
+ //we have configuration in setting file
+ if (!empty($splparams)) {
+ $poss = array();
+ foreach ($splparams as $idx => $splparam) {
+ $param = (object)$splparam;
+ $poss[] = isset($param->position) ? $param->position : $defpos[$idx];
+ }
+
+ $cols = count($poss);
+ }
+
+ // check if there's any modules
+ if (!$this->countModules(implode(' or ', $poss))) {
+ return;
+ }
+
+ //empty - so we will use default configuration
+ if (empty($splparams)) {
+ //generate a optimize default width
+ $default = $this->genWidth($defdv, $cols);
+
+ foreach ($poss as $i => $pos) {
+ //is there any configuration param
+ $var = isset($vars[$pos]) ? $vars[$pos] : '';
+
+ $param = new stdClass;
+ $param->position = $pos;
+
+ $param->$defdv = ($var && isset($var[$defdv])) ? $var[$defdv] : $this->widthprefix . $default[$i];
+ if ($var) {
+ foreach($this->devices as $device){
+ if (isset($var[$device])) {
+ $param->$device = $var[$device];
+ }
+ }
+
+ }
+
+ $splparams[$i] = $param;
+ }
+ }
+
+ //build data
+ $responsive = $this->getParam('responsive', 1);
+ $datas = array();
+ foreach ($splparams as $splparam) {
+ $param = (object)$splparam;
+
+ $data = '';
+
+ if($responsive){
+
+ foreach($this->devices as $device){
+
+ if(isset($param->$device)){
+ $prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
+ $posfix = $this->responcls ? '' : '"';
+
+ if(strpos(' ' . $param->$device . ' ', ' hidden ') !== false){
+ $param->$device = str_replace(' hidden ', ' hidden-' . $device . ' ', ' ' . $param->$device . ' ');
+ }
+
+ $data .= $prefix . $param->$device . $posfix;
+ }
+ }
+ } else {
+ $data = isset($param->$defdv) ? ' ' . $param->$defdv : '';
+
+ if($this->nonrspprefix && ($this->nonrspprefix != $this->widthprefix)){
+ $data = str_replace($this->widthprefix, $this->nonrspprefix, $data);
+ }
+ }
+
+ $datas[] = $data;
+ }
+
+ //pack to single variable
+ $vars['name'] = $name;
+ $vars['splparams'] = $splparams;
+ $vars['datas'] = $datas;
+ $vars['cols'] = $cols;
+
+ JDispatcher::getInstance()->trigger('onT3Spotlight', array(&$vars, $name, $positions));
+
+ $this->loadBlock('spotlight', $vars);
+ }
+
+
+ /**
+ * Render megamenu markup
+ * @param string $menutype The menutype to render
+ *
+ * @deprecated Use instead
+ */
+ function megamenu($menutype)
+ {
+ echo " ";
+ }
+
+ /**
+ * Get data property for layout - responsive layout
+ * @param object $layout Layout configuration object
+ * @param number $col Column number, start from 0
+ * @param boolean $array Return array or string
+ *
+ * @return mixed Block content
+ */
+ function getData($layout, $col, $array = false)
+ {
+ if ($array) {
+ $data = array();
+ foreach ($layout as $device => $width) {
+ if (!isset ($width[$col]) || !$width[$col]) continue;
+ $data[$device] = $width[$col];
+ }
+
+ } else {
+ $data = '';
+ foreach ($layout as $device => $width) {
+ if (!isset ($width[$col]) || !$width[$col]) continue;
+ $data .= " data-$device=\"{$width[$col]}\"";
+ }
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * Get layout column class
+ * @param object $layout Layout configuration object
+ * @param number $col Column number, start from 0
+ *
+ * @return string Block content
+ */
+ function getClass($layout, $col)
+ {
+ $defdv = $this->defdv;
+
+ if($this->responcls){
+ $result = '';
+ $responsive = $this->getParam('responsive', 1);
+
+ if($responsive){
+ foreach ($layout as $width) {
+ if (!isset ($width[$col]) || !$width[$col]) {
+ continue;
+ }
+
+ $result .= ' ' . $width[$col];
+ }
+
+ } else {
+ //remove all width classes
+ $width = $this->maxgrid;
+ $clayout = isset($layout->$defdv) ? $layout->$defdv : false;
+
+ if($clayout && !empty($clayout[$col])){
+ $defcls = $clayout[$col];
+ if(preg_match($this->spancls, $defcls, $match)){
+ $width = array_pop(array_filter($match, 'is_numeric'));
+ $width = ($width ? $width : $this->maxgrid);
+ }
+ }
+
+ $result = ' ' . $this->nonrspprefix . $width;
+ }
+
+ return $result;
+
+ } else {
+
+ $width = $layout->$defdv;
+ if (!isset ($width[$col]) || !$width[$col]){
+ return '';
+ }
+
+ return $width[$col];
+ }
+ }
+
+ /**
+ * Get layout column class
+ * @param object $layout Layout configuration object
+ * @param number $col Column number, start from 0
+ *
+ * @return string Block content
+ */
+ function responCls($class)
+ {
+ $result = $class[2];
+ $queue = array();
+
+ //remove all width classes
+ foreach ($this->prefixes as $prefix) {
+ if($result && preg_match_all('@' . preg_quote($prefix) . '[^\s]*@', $result, $match)){
+ $result = preg_replace('@' . preg_quote($prefix) . '[^\s]*@', ' ', $result);
+
+ foreach ($match[0] as $m) {
+ $parts = preg_split('@(\d+)@', $m, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $parts[0] = str_replace($prefix, $this->nonrspprefix, $parts[0]);
+ if(!isset($queue[$parts[0]])){
+ $queue[$parts[0]] = $parts[1];
+ }
+ }
+ }
+ }
+
+ if(!empty($queue)){
+ $result = trim($result); //would be better than preg_replace ?
+ foreach ($queue as $key => $value) {
+ $result .= ' ' . $key . $value;
+ }
+ }
+
+ return 'class="' . trim($result) . '"';
+ }
+
+
+ /**
+ * Add page class
+ */
+ function addPageClass($class)
+ {
+ $this->_pageclass = array_merge($this->_pageclass, (array)($class));
+ }
+
+ /**
+ * Add page class
+ *
+ * @deprecated
+ */
+ function addBodyClass($class)
+ {
+ $this->_pageclass = array_merge($this->_pageclass, (array)($class));
+ }
+
+ /**
+ * get page class
+ */
+ function getPageClass()
+ {
+ return $this->_pageclass;
+ }
+
+
+ /**
+ * Render page class
+ *
+ * @deprecated Use instead
+ */
+ function bodyClass()
+ {
+ $input = JFactory::getApplication()->input;
+
+ if ($input->getCmd('option', '')) {
+ $this->_pageclass[] = $input->getCmd('option', '');
+ }
+ if ($input->getCmd('view', '')) {
+ $this->_pageclass[] = 'view-' . $input->getCmd('view', '');
+ }
+ if ($input->getCmd('layout', '')) {
+ $this->_pageclass[] = 'layout-' . $input->getCmd('layout', '');
+ }
+ if ($input->getCmd('task', '')) {
+ $this->_pageclass[] = 'task-' . $input->getCmd('task', '');
+ }
+ if ($input->getCmd('Itemid', '')) {
+ $this->_pageclass[] = 'itemid-' . $input->getCmd('Itemid', '');
+ }
+
+ $menu = JFactory::getApplication()->getMenu();
+ if ($menu) {
+ $active = $menu->getActive();
+ $default = $menu->getDefault();
+
+ if ($active) {
+ if ($default && $active->id == $default->id) {
+ $this->_pageclass[] = 'home';
+ }
+
+ if ($active->params && $active->params->get('pageclass_sfx')) {
+ $this->_pageclass[] = $active->params->get('pageclass_sfx');
+ }
+ }
+ }
+
+ // hover trigger for megamenu
+ if ($this->getParam('navigation_trigger', 'hover') == 'hover') {
+ $this->_pageclass[] = 'mm-hover';
+ }
+
+ $this->_pageclass[] = 'j' . str_replace('.', '', (number_format((float)JVERSION, 1, '.', '')));
+ $this->_pageclass = array_unique($this->_pageclass);
+
+ JDispatcher::getInstance()->trigger('onT3BodyClass', array(&$this->_pageclass));
+
+ echo implode(' ', $this->_pageclass);
+ }
+
+
+ /**
+ * Render snippet
+ *
+ * @return null
+ */
+ function snippet()
+ {
+
+ $places = array();
+ $contents = array();
+
+ if (($openhead = $this->getParam('snippet_open_head', ''))) {
+ $places[] = ''; //not sure that any attritube can be place in head open tag, profile is not support in html5
+ $contents[] = "\n" . $openhead;
+ }
+ if (($closehead = $this->getParam('snippet_close_head', ''))) {
+ $places[] = '';
+ $contents[] = $closehead . "\n";
+ }
+ if (($openbody = $this->getParam('snippet_open_body', ''))) {
+ $body = JResponse::getBody();
+
+ if(strpos($body, '') !== false){
+ $places[] = '';
+ $contents[] = "\n" . $openbody;
+ } else { //in case the body has other attribute
+ $body = preg_replace('@]*?>@msU', "$0\n" . $openbody, $body);
+ JResponse::setBody($body);
+ }
+ }
+
+ // append modules in debug position
+ if ($this->getParam('snippet_debug', 0) && $this->countModules('debug')) {
+ $places[] = '';
+ $contents[] = '' . $this->getBuffer('modules', 'debug') . "
\n";
+ }
+
+ if (($closebody = $this->getParam('snippet_close_body', ''))) {
+ $places[] = '';
+ $contents[] = $closebody . "\n";
+ }
+
+ if (count($places)) {
+ $body = JResponse::getBody();
+ $body = str_replace($places, $contents, $body);
+
+ JResponse::setBody($body);
+ }
+ }
+
+
+ /**
+ * Wrap of document countModules function, get position from configuration before calculate
+ * @param string $positions Positions string
+ * @return boolean The position key is available or not
+ */
+ function countModules($positions)
+ {
+ $pos = $this->getPosname($positions);
+ return $this->_tpl && method_exists($this->_tpl, 'countModules') ? $this->_tpl->countModules($pos) : 0;
+ }
+
+
+ /**
+ * Wrap of document countModules function, used to detect if a spotlight is available to render or not
+ * @param string $name The spotlight name
+ * @param string $positions The positions name separated by comma
+ *
+ * @return boolean The spotlight is available or not
+ */
+ function checkSpotlight($name, $positions)
+ {
+ $poss = array();
+
+ for ($i = 1; $i <= $this->maxgrid; $i++) {
+ $param = $this->getLayoutSetting('block' . $i . '@' . $name);
+ if (empty($param)) {
+ break;
+ } else {
+ $param = (object)$param;
+ $poss[] = isset($param->position) ? $param->position : '';
+ }
+ }
+
+ if (empty($poss)) {
+ $poss = preg_split('/\s*,\s*/', $positions);
+ }
+
+ return $this->_tpl && method_exists($this->_tpl, 'countModules') ? $this->_tpl->countModules(implode(' or ', $poss)) : 0;
+ }
+
+
+ /**
+ * Check system messages
+ *
+ * @return boolean The system message queue has any message or not
+ */
+ function hasMessage()
+ {
+ // Get the message queue
+ $app = JFactory::getApplication();
+ $input = $app->input;
+
+ if($input->getCmd('option') == 'com_content'){
+ $messages = $app->getMessageQueue();
+
+ return !empty($messages);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Get mapped position name
+ * @param string $condition The position key(name)
+ *
+ * @return string The mapped position
+ */
+ function getPosname($condition)
+ {
+ $operators = '(,|\+|\-|\*|\/|==|\!=|\<\>|\<|\>|\<=|\>=|and|or|xor)';
+ $words = preg_split('# ' . $operators . ' #', $condition, null, PREG_SPLIT_DELIM_CAPTURE);
+ for ($i = 0, $n = count($words); $i < $n; $i += 2) {
+ // odd parts (modules)
+ $name = strtolower($words[$i]);
+ $words[$i] = $this->getLayoutSetting($name, $name);
+ }
+
+ $poss = '';
+ foreach ($words as $word) {
+ if (is_string($word)) {
+ $poss .= ' ' . $word;
+ } else {
+ $poss .= ' ' . (is_array($word) ? $word['position'] : (isset($word->position) ? $word->position : $name));
+ }
+ }
+ $poss = trim($poss);
+
+ return $poss;
+ }
+
+
+ /**
+ * Render position name
+ * @param string $condition The key used in block
+ *
+ * @return null
+ */
+ function posname($condition)
+ {
+ echo $this->getPosname($condition);
+ }
+
+ /**
+ * Alias of posname
+ * @param string $condition
+ * @return null
+ */
+ function _p($condition)
+ {
+ $this->posname($condition);
+ }
+
+
+ /**
+ * Add position additional class (show/hide)
+ * @param string $name The position name
+ * @param array $cls The responsive array style for responsive layout [lg, md, ...]
+ *
+ * @return null
+ */
+ function _c($name, $cls = array())
+ {
+ $data = '';
+ $param = $this->getLayoutSetting($name, '');
+
+ if (empty($param)) {
+ if (is_string($cls)) {
+ $data = ' ' . $cls;
+ } else if (is_array($cls)) {
+ $param = (object)$cls;
+ }
+ }
+
+ if (!empty($param)) {
+
+ foreach ($this->maxcol as $device => $span) {
+ //convert hidden class
+ if(!empty($param->$device) && strpos(' ' . $param->$device . ' ', ' hidden ') !== false){
+ $param->$device = str_replace(' hidden ', ' hidden-' . $device . ' ', ' ' . $param->$device . ' ');
+ }
+
+ if(!empty($param->$device)){
+ $prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
+ $posfix = $this->responcls ? '' : '"';
+ $data .= $prefix . trim($param->$device) . $posfix;
+ }
+ }
+
+ $defdv = $this->defdv;
+ if(!$this->responcls && !empty($data)){
+ $data = (isset($param->$defdv) ? ' ' . $param->$defdv : '') . ' t3respon"' . substr($data, 0, strrpos($data, '"'));
+ }
+ }
+
+ echo $data;
+ }
+
+ /**
+ * Add current template css base on template setting.
+ * @param $name string file name, without .css
+ * @param $addresponsive bool add responsive part or not
+ *
+ * @return string Block content
+ */
+ function addCss($name, $addresponsive = true)
+ {
+ $devmode = $this->getParam('devmode', 0);
+ $themermode = $this->getParam('themermode', 1);
+ $responsive = $addresponsive && !$this->responcls ? $this->getParam('responsive', 1) : false;
+
+ if (($devmode || ($themermode && defined('T3_THEMER'))) && ($url = T3Path::getUrl('less/' . $name . '.less', '', true, false))) {
+ T3::import('core/less');
+ T3Less::addStylesheet($url);
+ } else {
+ $this->addStyleSheet(T3_TEMPLATE_URL . '/css/' . $name . '.css');
+ }
+
+ if ($responsive && !$this->responcls) {
+ $this->addCss($name . '-responsive', false);
+ }
+ }
+
+ /**
+ * Add T3 basic head
+ *
+ * @return null
+ */
+ function addHead()
+ {
+
+ $app = JFactory::getApplication();
+ $user = JFactory::getUser();
+ $input = $app->input;
+
+ $responsive = $this->getParam('responsive', 1);
+ $navtype = $this->getParam('navigation_type', 'joomla');
+ $navtrigger = $this->getParam('navigation_trigger', 'hover');
+ $offcanvas = $this->getParam('navigation_collapse_offcanvas', 0) || $this->getParam('addon_offcanvas_enable', 0);
+ $legacycss = $this->getParam('legacy_css', 0);
+ $frontedit = in_array($input->getCmd('option'), array('com_media', 'com_config')) //com_media or com_config
+ || in_array($input->getCmd('layout'), array('edit')) //edit layout
+ || (version_compare(JVERSION, '3.2', 'ge') && $user->id && $app->get('frontediting', 1) &&
+ ($user->authorise('core.edit', 'com_modules') || $user->authorise('core.edit', 'com_menus'))); //frontediting
+
+ // LEGACY COMPATIBLE
+ if($legacycss){
+ $this->addCss('legacy-grid'); //legacy grid
+ $this->addStyleSheet(T3_URL . '/fonts/font-awesome/css/font-awesome' . ($this->getParam('devmode', 0) ? '' : '.min') . '.css'); //font awesome 3
+ }
+
+ // FRONTEND EDITING
+ if($frontedit){
+ $this->addCss('frontend-edit');
+ }
+
+ // Clear current css to put bootstrap css on top
+ $_stylesheets = $this->_styleSheets;
+ $this->_styleSheets = array();
+
+ // BOOTSTRAP CSS
+ $this->addCss('bootstrap', false);
+
+ // Append current css to bootstrap
+ $this->_styleSheets = array_merge($this->_styleSheets, $_stylesheets);
+
+ // TEMPLATE CSS
+ $this->addCss('template', false);
+
+ if (!$responsive && $this->responcls) {
+ // not responsive for BS3
+ $this->addCss('non-responsive'); //no responsive
+
+ $nonrespwidth = $this->getParam('non_responsive_width', '970px');
+ if(preg_match('/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/', $nonrespwidth, $match)){
+ $nonrespwidth = $match[1] . (!empty($match[2]) ? $match[2] : 'px');
+ }
+ $this->addStyleDeclaration('.container {width: ' . $nonrespwidth . ' !important;} .t3-wrapper, .wrap {min-width: ' . $nonrespwidth . ' !important;}');
+
+ } else if($responsive && !$this->responcls){
+ // responsive for BS2
+ // BOOTSTRAP RESPONSIVE CSS
+ $this->addCss('bootstrap-responsive');
+
+ // RESPONSIVE CSS
+ $this->addCss('template-responsive');
+ }
+
+ // add core megamenu.css in plugin
+ // deprecated - will extend the core style into template megamenu.less & megamenu-responsive.less
+ // to use variable overridden in template
+ if($navtype == 'megamenu'){
+
+ // If the template does not overwrite megamenu.less & megamenu-responsive.less
+ // We check and included predefined megamenu style in base
+ if(!is_file(T3_TEMPLATE_PATH . '/less/megamenu.less')){
+ $this->addStyleSheet(T3_URL . '/css/megamenu.css');
+
+ if ($responsive && !$this->responcls){
+ $this->addStyleSheet(T3_URL . '/css/megamenu-responsive.css');
+ }
+ }
+
+ // megamenu.css override in template
+ $this->addCss('megamenu');
+ }
+
+ // Add scripts
+ if (version_compare(JVERSION, '3.0', 'ge')) {
+ JHtml::_('jquery.framework');
+ } else {
+ $scripts = @$this->_scripts;
+ $jqueryIncluded = 0;
+ if (is_array($scripts) && count($scripts)) {
+ //simple detect for jquery library. It will work for most of cases
+ $pattern = '/(^|\/)jquery([-_]*\d+(\.\d+)+)?(\.min)?\.js/i';
+ foreach ($scripts as $script => $opts) {
+ if (preg_match($pattern, $script)) {
+ $jqueryIncluded = 1;
+ break;
+ }
+ }
+ }
+
+ if (!$jqueryIncluded) {
+ $this->addScript(T3_URL . '/js/jquery-1.8.3' . ($this->getParam('devmode', 0) ? '' : '.min') . '.js');
+ $this->addScript(T3_URL . '/js/jquery.noconflict.js');
+ }
+ }
+
+ define('JQUERY_INCLUED', 1);
+
+
+ // As joomla 3.0 bootstrap is buggy, we will not use it
+ $this->addScript(T3_URL . '/bootstrap/js/bootstrap.js');
+ // a jquery tap plugin
+ $this->addScript(T3_URL . '/js/jquery.tap.min.js');
+
+ // add css/js for off-canvas
+ if ($offcanvas && ($this->responcls || $responsive)) {
+ $this->addCss('off-canvas', false);
+ $this->addScript(T3_URL . '/js/off-canvas.js');
+ }
+
+ $this->addScript(T3_URL . '/js/script.js');
+
+ //menu control script
+ if ($navtrigger == 'hover') {
+ $this->addPageClass('mm-hover');
+ }
+
+ //if($navtrigger == 'hover' || $this->responcls){
+ $this->addScript(T3_URL . '/js/menu.js');
+ //}
+
+ //reponsive script
+ if ($responsive && !$this->responcls) {
+ $this->addScript(T3_URL . '/js/responsive.js');
+ }
+
+ //some helper javascript functions for frontend edit
+ if($frontedit){
+ $this->addScript(T3_URL . '/js/frontend-edit.js');
+ }
+
+ //check and add additional assets
+ $this->addExtraAssets();
+ }
+
+ /**
+ * Update head - detect if devmode or themermode is enabled and less file existed, use less file instead of css
+ * We also detect and update jQuery, Bootstrap to use T3 assets
+ *
+ * @return null
+ */
+ function updateHead()
+ {
+ //state parameters
+ $devmode = $this->getParam('devmode', 0);
+ $themermode = $this->getParam('themermode', 1) && defined('T3_THEMER');
+ $theme = $this->getParam('theme', '');
+ $minify = $this->getParam('minify', 0);
+ $minifyjs = $this->getParam('minify_js', 0);
+ // detect RTL
+ $doc = JFactory::getDocument();
+ $dir = $doc->direction;
+ $is_rtl = ($dir == 'rtl');
+
+ // As Joomla 3.0 bootstrap is buggy, we will not use it
+ // We also prevent both Joomla bootstrap and T3 bootsrap are loaded
+ // And upgrade jquery as our Framework require jquery 1.7+ if we are loading jquery from google
+ $scripts = array();
+
+ if (version_compare(JVERSION, '3.0', 'ge')) {
+ $t3bootstrap = false;
+ $jabootstrap = false;
+
+ foreach ($doc->_scripts as $url => $script) {
+ if (strpos($url, T3_URL . '/bootstrap/js/bootstrap.js') !== false) {
+ $t3bootstrap = true;
+ if ($jabootstrap) { //we already have the Joomla bootstrap and we also replace to T3 bootstrap
+ continue;
+ }
+ }
+
+ if (preg_match('@media/jui/js/bootstrap(.min)?.js@', $url)) {
+ if ($t3bootstrap) { //we have T3 bootstrap, no need to add Joomla bootstrap
+ continue;
+ } else {
+ $scripts[T3_URL . '/bootstrap/js/bootstrap.js'] = $script;
+ }
+
+ $jabootstrap = true;
+ } else {
+ $scripts[$url] = $script;
+ }
+ }
+
+ $doc->_scripts = $scripts;
+ $scripts = array();
+ }
+
+ // VIRTUE MART / JSHOPPING compatible
+ foreach ($doc->_scripts as $url => $script) {
+ $replace = false;
+
+ if ((strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false &&
+ preg_match_all('@/jquery/(\d+(\.\d+)*)?/@msU', $url, $jqver)) ||
+ (preg_match_all('@(^|\/)jquery([-_]*(\d+(\.\d+)+))?(\.min)?\.js@i', $url, $jqver))) {
+
+ $idx = strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false ? 1 : 3;
+
+ if (is_array($jqver) && isset($jqver[$idx]) && isset($jqver[$idx][0])) {
+ $jqver = explode('.', $jqver[$idx][0]);
+
+ if (isset($jqver[0]) && (int)$jqver[0] <= 1 && isset($jqver[1]) && (int)$jqver[1] < 7) {
+ $scripts[T3_URL . '/js/jquery-1.8.3' . ($devmode ? '' : '.min') . '.js'] = $script;
+ $replace = true;
+ }
+ }
+ }
+
+ if (!$replace) {
+ $scripts[$url] = $script;
+ }
+ }
+
+ $doc->_scripts = $scripts;
+ // end update javascript
+
+ //Update css/less based on devmode and themermode
+ $root = JURI::root(true);
+ $current = JURI::current();
+ // $regex = '@' . preg_quote(T3_TEMPLATE_REL) . '/css/(rtl/)?(.*)\.css((\?|\#).*)?$@i';
+ $regex = '@' . preg_quote(T3_TEMPLATE_REL) . '/(.*)\.css((\?|\#).*)?$@i';
+ $stylesheets = array();
+ foreach ($doc->_styleSheets as $url => $css) {
+ // detect if this css in template css
+ if (preg_match($regex, $url, $match)) {
+ $fname = $match[1];
+
+ // remove rtl
+ $fname = preg_replace ('@(^|/)rtl/@mi', '\1', $fname);
+
+ // if (($devmode || $themermode) && is_file(T3_TEMPLATE_PATH . '/less/' . $fname . '.less')) {
+ if (($devmode || $themermode)) {
+ // less file
+ $lfname = preg_replace ('@(^|/)css/@mi', '\1less/', $fname);
+
+ if (is_file(T3_TEMPLATE_PATH . '/' . $lfname . '.less')) {
+ if ($themermode) {
+ $newurl = T3_TEMPLATE_URL . '/' . $lfname . '.less';
+ $css['mime'] = 'text/less';
+ } else {
+ T3::import('core/less');
+ $newurl = T3Less::buildCss(T3Path::cleanPath(T3_TEMPLATE_REL . '/' . $lfname . '.less'), true);
+ }
+ $stylesheets[$newurl] = $css;
+ continue;
+ }
+ }
+
+ $uri = null;
+ // detect css available base on direction & theme
+ if ($is_rtl && $theme) {
+ // rtl css file
+ $altfname = preg_replace ('@(^|/)css/@mi', '\1css/rtl/' . $theme . '/', $fname);
+ $uri = T3Path::getUrl ($altfname . '.css');
+ }
+
+ if (!$uri && $is_rtl) {
+ $altfname = preg_replace ('@(^|/)css/@mi', '\1css/rtl/', $fname);
+ $uri = T3Path::getUrl ($altfname . '.css');
+ }
+
+ if (!$uri && $theme) {
+ $altfname = preg_replace ('@(^|/)css/@mi', '\1css/themes/' . $theme . '/', $fname);
+ $uri = T3Path::getUrl ($altfname . '.css');
+ }
+
+ if (!$uri) {
+ $uri = T3Path::getUrl ($fname . '.css');
+ }
+
+ if ($uri) {
+ $stylesheets[$uri] = $css;
+ }
+ continue;
+ }
+
+ $stylesheets[$url] = $css;
+ }
+
+ // update back
+ $doc->_styleSheets = $stylesheets;
+
+ //only check for minify if devmode is disabled
+ if (!$devmode && ($minify || $minifyjs)) {
+ T3::import('core/minify');
+ if($minify){
+ T3Minify::optimizecss($this);
+ }
+ if($minifyjs){
+ T3Minify::optimizejs($this);
+ }
+ }
+ }
+
+ /**
+ * Add some other condition assets (css, javascript). Use to parse /etc/assets.xml
+ *
+ * @return null
+ */
+ function addExtraAssets()
+ {
+ $base = JURI::base(true);
+ $regurl = '#(http|https)://([a-zA-Z0-9.]|%[0-9A-Za-z]|/|:[0-9]?)*#iu';
+
+ $afiles = T3Path::getAllPath('etc/assets.xml');
+ foreach ($afiles as $afile) {
+ if (is_file($afile)) {
+ //load xml
+ $axml = JFactory::getXML($afile);
+
+ //process if exist
+ if ($axml) {
+ foreach ($axml as $node => $nodevalue) {
+ //ignore others node
+ if ($node == 'stylesheets' || $node == 'scripts') {
+ foreach ($nodevalue->file as $file) {
+ $compatible = (string) $file['compatible'];
+ if ($compatible) {
+ $parts = explode(' ', $compatible);
+ $operator = '='; //exact equal to
+ $operand = $parts[0];
+ if (count($parts) == 2) {
+ $operator = $parts[0];
+ $operand = $parts[1];
+ }
+
+ //compare with Joomla version
+ if (!version_compare(JVERSION, $operand, $operator)) {
+ continue;
+ }
+ }
+
+ $url = (string)$file;
+ if (substr($url, 0, 2) == '//') { //external link
+
+ } else if ($url[0] == '/') { //absolute link from based folder
+ $url = is_file(JPATH_ROOT . $url) ? $base . $url : false;
+ } else if (!preg_match($regurl, $url)) { //not match a full url -> sure internal link
+ $url = T3Path::getUrl($url); // so get it
+ }
+
+ if ($url) {
+ if ($node == 'stylesheets') {
+ $type = $file['type'] ? (string) $file['type'] : 'text/css';
+ $media = $file['media'] ? (string) $file['media'] : null;
+ $this->addStylesheet($url, $type, $media);
+ } else {
+ $type = $file['type'] ? (string) $file['type'] : 'text/javascript';
+ $defer = $file['defer'] ? (bool) $file['defer'] : false;
+ $async = $file['async'] ? (bool) $file['async'] : false;
+ $this->addScript($url, $type, $defer, $async);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // template extended styles
+ $aparams = $this->_tpl->params->toArray();
+ $extras = array();
+ $itemid = JFactory::getApplication()->input->get ('Itemid');
+ foreach ($aparams as $name => $value) {
+ if (preg_match ('/^theme_extras_(.+)$/', $name, $m)) {
+ $extras[$m[1]] = $value;
+ }
+ }
+ if (count ($extras)) {
+ foreach ($extras as $extra => $pages) {
+ if (!is_array($pages) || !count($pages) || in_array (0, $pages)) {
+ continue; // disabled
+ }
+ if (in_array (-1, $pages) || in_array($itemid, $pages)) {
+ // load this style
+ $this->addCss ('extras/'.$extra);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Turn a param to DOM style value
+ * @param string $style The style property
+ * @param string $pname The parameter name
+ * @param boolean $isurl Is url?
+ *
+ * @return string The css style string
+ * @deprecated This function is no longer used in T3
+ */
+ function paramToStyle($style, $pname = '', $isurl = false)
+ {
+ if ($pname == '') {
+ $pname = $style;
+ }
+ $param = $this->getParam($pname);
+
+ if (!$param) return '';
+
+ if ($isurl) {
+ return "$style:url($param);";
+ } else {
+ return "$style:$param" . (is_numeric($param) ? 'px;' : ';');
+ }
+ }
+
+ /**
+ * Internal function, auto generate optimize width in a row fit to 12 grid
+ * @param number $numpos number columns in row
+ *
+ * @return array The span width layout columns for a row
+ */
+ function fitWidth($numpos)
+ {
+ $result = array();
+ $avg = floor($this->maxgrid / $numpos);
+ $sum = 0;
+
+ for ($i = 0; $i < $numpos - 1; $i++) {
+ $result[] = $avg;
+ $sum += $avg;
+ }
+
+ $result[] = $this->maxgrid - $sum;
+
+ return $result;
+ }
+
+ /**
+ * Internal function, generate auto calculate width
+ * @param string $layout The target layout
+ * @param number $numpos Number of columns (block)
+ *
+ * @return array The span width layout columns
+ */
+ function genWidth($layout, $numpos)
+ {
+ $cminspan = $this->minspan[$layout];
+ $total = $cminspan * $numpos;
+
+ if ($total < $this->maxgrid) {
+ return $this->fitWidth($numpos);
+ } else {
+ $result = array();
+ $rows = ceil($total / $this->maxgrid);
+ $cols = ceil($numpos / $rows);
+
+ for ($i = 0; $i < $rows - 1; $i++) {
+ $result = array_merge($result, $this->fitWidth($cols));
+ $numpos -= $cols;
+ }
+
+ $result = array_merge($result, $this->fitWidth($numpos));
+ }
+
+ return $result;
+ }
+}
diff --git a/plugins/system/t3/includes/core/templatelayout.php b/plugins/system/t3/includes/core/templatelayout.php
new file mode 100644
index 0000000..effed7a
--- /dev/null
+++ b/plugins/system/t3/includes/core/templatelayout.php
@@ -0,0 +1,646 @@
+responcls){
+ $this->setParam('responsive', 0);
+ }
+ $this->setParam('devmode', 0);
+ }
+
+ /**
+ * Get current layout tpls
+ *
+ * @return string Layout name
+ */
+ public function getLayout()
+ {
+ return JFactory::getApplication()->input->getCmd('t3layout', $this->_tpl->params->get('mainlayout'));
+ }
+
+ /**
+ * Check a module condition is true or not
+ * @param string $positions
+ * @return true always return true
+ */
+ function countModules($positions)
+ {
+ return 1;
+ }
+
+ /**
+ * Check for a spotlight if it can be render or not
+ * @param string $name spotlight name
+ * @param string $positions default position values
+ *
+ * @return true always return true
+ */
+ function checkSpotlight($name, $positions)
+ {
+ return 1;
+ }
+
+
+ /**
+ * Check for the message queue
+ *
+ * @return true always return true
+ */
+ function hasMessage(){
+ return 1;
+ }
+
+ /**
+ * Load block content
+ *
+ * @param $block string block name - the real block is tpls/blocks/[blockname].php
+ * @param $vars array information of block (used in template layout)
+ *
+ * @return string Block content
+ */
+ function loadBlock($block, $vars = array())
+ {
+ if (!$this->_block) {
+ $this->_block = $block;
+ }
+
+ $path = T3Path::getPath('tpls/system/' . $block . '.php');
+ if (!$path) {
+ $path = T3Path::getPath('tpls/blocks/' . $block . '.php');
+ }
+
+ ob_start();
+ if ($path) {
+ include $path;
+ } else {
+ echo "Block [$block] not found!
";
+ }
+ $content = ob_get_contents();
+ ob_end_clean();
+
+ if (isset($vars['spl'])) {
+ $content = preg_replace('#(<[A-Za-z]+[^>^\/]*)>#', '\1 data-original="' . $block . '"' . (isset($vars['spl']) ? ' data-spotlight="' . $vars['name'] . '"' : '') . '>', $content, 1);
+ $this->_block = null;
+ }
+
+ echo isset($vars['spl']) ? $content : ('' . $content . '
');
+ }
+
+ /**
+ * Load layout content
+ * @param $layout string Block name - the real block is tpls/blocks/[blockname].php
+ *
+ * @return none
+ */
+ function loadLayout($layout)
+ {
+ $path = T3Path::getPath('tpls/' . $layout . '.php', 'tpls/default.php');
+
+ if ($path) {
+ // include $path;
+ $html = $this->loadFile($path);
+
+ // parse and replace jdoc
+ $html = $this->_parse($html);
+ echo $html;
+ } else {
+ echo "Layout [$layout] or [Default] not found!
";
+ }
+ }
+
+ /**
+ * Generate a spotlight block
+ *
+ * @param $name string Name of spotlight - identity, ex: 'spotlight-1'
+ * @param $positions string default positions, ex: 'positon-1, position-2'
+ * @param $info array
+ * options for spotlight and for every position
+ * ex: array(
+ * 'row-fluid' => 1,
+ * 'position-1' => array(
+ * '[dv1]' => 'span3 special',
+ * '[dv2]' => 'span3 hidden'
+ * ),
+ * 'position-2' => array(...)
+ * )
+ * @return none render spotlight block
+ */
+ function spotlight($name, $positions, array $info = array())
+ {
+ $vars = is_array($info) ? $info : array();
+ $defpos = $poss = preg_split('/\s*,\s*/', $positions);
+ $defnumpos = count($defpos);
+
+ $splparams = array();
+ for ($i = 1; $i <= $this->maxgrid; $i++) {
+ $param = $this->getLayoutSetting('block' . $i . '@' . $name);
+ if (empty($param)) {
+ break;
+ } else {
+ $splparams[] = $param;
+ }
+ }
+
+ //we have data - configuration saved
+ if (!empty($splparams)) {
+ $poss = array();
+ foreach ($splparams as $i => $splparam) {
+ $param = (object)$splparam;
+ $poss[] = isset($param->position) ? $param->position : $defpos[$i];
+ }
+
+ } else {
+ foreach ($poss as $i => $pos) {
+ $splparams[$i] = '';
+ }
+ }
+
+ $original = implode(',', $defpos);
+
+ $inits = array();
+ foreach ($defpos as $i => $dpos) {
+ $inits[$i] = $this->parseInfo(isset($vars[$dpos]) ? $vars[$dpos] : '');
+ }
+
+ $infos = array();
+ foreach ($splparams as $i => $splparam) {
+ $infos[$i] = !empty($splparam) ? $this->parseInfo($splparam) : $inits[$i];
+ }
+
+ $defwidths = $this->extractKey($inits, 'width');
+ $deffirsts = $this->extractKey($inits, 'first');
+
+ $widths = $this->extractKey($infos, 'width');
+ $firsts = $this->extractKey($infos, 'first');
+ $others = $this->extractKey($infos, 'others');
+
+ //optimize default width if needed
+ $this->optimizeWidth($defwidths, $defnumpos);
+ $this->optimizeWidth($widths, $defnumpos);
+
+ $visibility = array(
+ 'name' => $name,
+ 'vals' => $this->extractKey($infos, 'hidden'),
+ 'deft' => $this->extractKey($inits, 'hidden'),
+ );
+
+ $spldata = array(
+ ' data-original="', $original, '"',
+ ' data-vis="', $this->htmlattr($visibility), '"',
+ ' data-owidths="', $this->htmlattr($defwidths), '"',
+ ' data-widths="', $this->htmlattr($widths), '"',
+ ' data-ofirsts="', $this->htmlattr($deffirsts), '"',
+ ' data-firsts="', $this->htmlattr($firsts), '"',
+ ' data-others="', $this->htmlattr($others), '"'
+ );
+
+ $default = $widths[$this->defdv];
+ //
+ $vars['name'] = $name;
+ $vars['poss'] = $poss;
+ $vars['spldata'] = implode('', $spldata);
+ $vars['default'] = $default;
+ $vars['spl'] = 1;
+
+ //normal
+ $this->loadBlock('spotlight', $vars);
+ }
+
+ /**
+ * Render mainnav block (joomla default navigation)
+ */
+ function mainnav()
+ {
+ echo ' ';
+ }
+
+ /**
+ * Render position name
+ * @param string $condition
+ * @return string the position value
+ */
+ function getPosname($condition)
+ {
+ return parent::getPosname($condition) . '" data-original="' . $condition;
+ }
+
+
+ /**
+ * Add additional class and parse for visibility of block
+ * @param string $name
+ * @param array $cls
+ * @return null|void
+ */
+ function _c($name, $cls = array())
+ {
+ $params = $this->getLayoutSetting($name, '');
+
+ $cinfo = $oinfo = $this->parseVisibility(is_string($cls) ? array($this->defdv => $cls) : (is_array($cls) ? $cls : array()));
+ if (!empty($params)) {
+ $cinfo = $this->parseVisibility($params);
+ }
+
+ $data = '';
+ $visible = array(
+ 'name' => $name,
+ 'vals' => $this->extractKey(array($cinfo), 'hidden'),
+ 'deft' => $this->extractKey(array($oinfo), 'hidden')
+ );
+
+ if (empty($params)) {
+ if (is_string($cls)) {
+ $data = ' ' . $cls;
+ } else if (is_array($cls)) {
+ $params = (object)$cls;
+ }
+ }
+
+ if(!empty($params)){
+ foreach ($this->maxcol as $device => $span) {
+ if(!empty($params->$device)){
+ $prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
+ $posfix = $this->responcls ? '' : '"';
+ $data .= $prefix . trim($params->$device) . $posfix;
+ }
+ }
+
+ $defdv = $this->defdv;
+ if(!$this->responcls && !empty($data)){
+ $data = (isset($params->$defdv) ? ' ' . $params->$defdv : '') . ' t3respon"' . substr($data, 0, strrpos($data, '"'));
+ }
+ }
+
+ //remove hidden class
+ $data = preg_replace('@("|\s)?'. preg_quote(T3_BASE_HIDDEN_PATTERN) .'(\s|")?@iU', '$1$2', $data);
+
+ echo $data . '" data-vis="' . $this->htmlattr($visible) . '" data-others="' . $this->htmlattr($this->extractKey(array($oinfo), 'others'));
+ }
+
+ /**
+ * Internal function, use to parse layout blocks
+ * @param string $html html markup string
+ * @return string mixed layout markup
+ */
+ protected function _parse($html)
+ {
+ $html = preg_replace_callback('# #iU', array($this, '_parseJDoc'), $html);
+ return $html;
+ }
+
+ /**
+ * Parse each and return the corresponding content
+ * @param $matches infomation
+ * @return string block markup
+ */
+ protected function _parseJDoc($matches)
+ {
+ $type = $matches[1];
+ if ($type == 'head') {
+ return $matches[0];
+ }
+ $attribs = empty($matches[2]) ? array() : JUtility::parseAttributes($matches[2]);
+ $attribs['type'] = $type;
+ if (!isset($attribs['name'])) {
+ $attribs['name'] = $attribs['type'];
+ }
+
+ $tp = 'tpls/system/tp.php';
+ $path = '';
+ if (is_file(T3_TEMPLATE_PATH . '/' . $tp)) {
+ $path = T3_TEMPLATE_PATH . '/' . $tp;
+ } else if (is_file(T3_PATH . '/' . $tp)) {
+ $path = T3_PATH . '/' . $tp;
+ }
+
+ return $this->loadFile($path, $attribs);
+ }
+
+ /**
+ * Render a file in memory
+ * @param string $path file path to render
+ * @param array $vars additional information
+ * @return string the renderred content
+ */
+ function loadFile($path, $vars = array())
+ {
+ ob_start();
+ include $path;
+ $content = ob_get_contents();
+ ob_end_clean();
+ return $content;
+ }
+
+ /**
+ * Add T3 basic head
+ */
+ function addHead()
+ {
+ //TODO: should we return null here
+ //we do not really need a header here
+
+ // BOOTSTRAP CSS
+ //$this->addCss ('bootstrap', false);
+ //$this->addCss ('t3-admin-layout-preview', false);
+
+ // Add scripts
+ //$this->addScript (T3_URL.'/bootstrap/js/jquery.js');
+ //$this->addScript (T3_URL.'/bootstrap/js/bootstrap.js');
+ }
+
+ /**
+ * Render dummy megamenu block in layout
+ * @param string $menutype
+ */
+ function megamenu($menutype)
+ {
+ echo "
Megamenu [$menutype] ";
+ }
+
+ /**
+ * Parse information
+ * @param $posinfo array should be an object in setting file
+ * $posinfo = array(
+ * '[dv1]' => 'col-lg-3',
+ * '[dv2]' => 'col-md-4',
+ * '[dv3]' => 'col-xs-6 hidden'
+ * )
+ * @return array positions information
+ */
+ function parseInfo($posinfo = array())
+ {
+ //convert to array
+ if (empty($posinfo)) {
+ $posinfo = array();
+ } else {
+ $posinfo = is_array($posinfo) ? $posinfo : get_object_vars($posinfo);
+ }
+
+ // init empty result
+ $result = array();
+ foreach ($this->devices as $device) {
+ $result[$device] = array();
+ }
+
+ $defcls = !$this->responcls && isset($posinfo[$this->defdv]) ? $posinfo[$this->defdv] : '';
+
+ foreach ($result as $device => &$info) {
+ //class presentation string
+ $cls = isset($posinfo[$device]) ? $posinfo[$device] : '';
+
+ //extend other device
+ if (!empty($defcls) && $device != $this->defdv) {
+ $cls = $this->addclass($cls, $defcls);
+ }
+ //if isset
+ if (!empty($cls)) {
+ //check if this position is hidden
+ $hidden = T3_BASE_HIDDEN_PATTERN && $this->hasclass($cls, T3_BASE_HIDDEN_PATTERN);
+ if ($hidden) {
+ $cls = $this->removeclass($cls, T3_BASE_HIDDEN_PATTERN);
+ }
+
+ //check if this position is first position
+ $first = T3_BASE_FIRST_PATTERN && $this->hasclass($cls, T3_BASE_FIRST_PATTERN);
+ if ($first) {
+ $cls = $this->removeclass($cls, T3_BASE_FIRST_PATTERN);
+ }
+
+ //check for width of this position
+ $width = $this->maxgrid;
+ if(preg_match($this->spancls, $cls, $match)){
+ $match = array_filter($match, 'is_numeric');
+ $width = array_pop($match);
+ $width = is_numeric($width) ? $width : $this->maxgrid;
+ }
+
+ if (!$this->responcls && intval($width) > 0) {
+ $width = $this->convertWidth($width, $device);
+ }
+
+ //other class
+ $others = trim(preg_replace($this->spancls, ' ', $cls));
+ } else {
+ $hidden = 0;
+ $first = 0;
+ $width = 0;
+ $others = '';
+ }
+
+ $info['hidden'] = $hidden;
+ $info['first'] = $first;
+ $info['width'] = $width;
+ $info['others'] = $others;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Parse visibility information
+ * @param $posinfo array should be an object in setting file
+ * $posinfo = array(
+ * '[dv1]' => 'col-lg-3',
+ * '[dv2]' => 'col-md-4',
+ * '[dv3]' => 'col-xs-6 hidden'
+ * )
+ *
+ * We focus on visibility value only, other information will be placed in others
+ * @return array visibility information
+ **/
+ function parseVisibility($posinfo = array())
+ {
+
+ //convert to array
+ if (empty($posinfo)) {
+ $posinfo = array();
+ } else {
+ $posinfo = is_array($posinfo) ? $posinfo : get_object_vars($posinfo);
+ }
+
+ // init empty result
+ $result = array();
+ foreach ($this->devices as $device) {
+ $result[$device] = array();
+ }
+
+ foreach ($result as $device => &$info) {
+ //class presentation string
+ $cls = isset($posinfo[$device]) ? $posinfo[$device] : '';
+
+ //if isset
+ if (!empty($cls)) {
+ //check if this position is hidden
+ $hidden = T3_BASE_HIDDEN_PATTERN && $this->hasclass($cls, T3_BASE_HIDDEN_PATTERN);
+ if ($hidden) {
+ $cls = $this->removeclass($cls, T3_BASE_HIDDEN_PATTERN);
+ }
+
+ //other class
+ $others = trim($cls);
+ } else {
+ $hidden = 0;
+ $others = '';
+ }
+
+ $info['hidden'] = $hidden;
+ $info['others'] = $others;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Extract a value key from object
+ **/
+ function extractKey($infos, $key)
+ {
+ //$info = array(
+ // [0] => array(
+ // '[dv1]' => array(
+ // 'hidden' => 0
+ // 'first' => 0
+ // 'width' => 2
+ // 'others' => ''
+ // ),
+ // '[dv2]' => array(
+ // 'hidden' => 0
+ // 'width' => 2
+ // 'others' => ''
+ // ),
+ // ...
+ // ),
+ //
+ // [1] => array(
+ // '[dv1]' => array(
+ // 'hidden' => 0
+ // 'width' => 2
+ // 'others' => ''
+ // )
+ // )
+ // ),
+ // ...
+
+ // init empty result
+ $result = array();
+ foreach ($this->devices as $device) {
+ $result[$device] = array();
+ }
+
+ foreach ($infos as $i => $devices) {
+ foreach ($devices as $device => $info) {
+ $result[$device][$i] = $info[$key];
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * Optimize width of a spotlight
+ * - we try to fit all position of a spotlight to one row
+ * $widths = array(
+ * '[dv1]' => array(3,3,3,3),
+ * '[dv2]' => array(1,2,3,4)
+ * )
+ **/
+ function optimizeWidth(&$widths, $newcols = false)
+ {
+ foreach ($widths as $device => &$width) {
+ if (array_sum($width) < $this->maxgrid || $width[0] == 0) { //test if default empty width
+ $widths[$device] = $this->genWidth($device, $newcols ? $newcols : count($width));
+ }
+ }
+ }
+
+ /**
+ * Convert width of mobile - mobile have special width number
+ **/
+ function convertWidth($width, $device)
+ {
+ //convert back - width of mobile should be [33%,] 50% and 100%
+ //there might be some case when we enter the width of other device ( < 12) => return 100% (12)
+ return $device == 'mobile' ? ($width <= 12 ? 12 : floor($width / 100 * 12)) : $width;
+ }
+
+ /**
+ * Utility function - check if a HTML class is exist in a HTML class list
+ **/
+ function hasclass($clsname, $cls)
+ {
+ return intval(strpos(' ' . $clsname . ' ', ' ' . $cls . ' ') !== false);
+ }
+
+ /**
+ * Utility function - remove a HTML class in a HTML class list
+ **/
+ function removeclass($clsname, $cls)
+ {
+ return preg_replace('/(^|\s)' . $cls . '(?:\s|$)/', '$1', $clsname);
+ }
+
+ /**
+ * Utility function - remove a HTML class in a HTML class list
+ * The result will contains only 1 width class (col-xx-yy)
+ **/
+ function addclass($clsname, $cls)
+ {
+ $haswidth = preg_match($this->spancls, $clsname);
+ if ($haswidth) {
+ $cls = trim(preg_replace($this->spancls, ' ', $cls));
+ }
+
+ $cls = explode(' ', $cls);
+
+ foreach ($cls as $cl) {
+ if (!$this->hasclass($clsname, $cl)) {
+ $clsname .= ' ' . $cl;
+ }
+ }
+
+ return implode(' ', array_unique(explode(' ', $clsname)));
+ }
+
+ /**
+ * Utility function - embed json to HTML attribute
+ * @param mixed $obj Object to encode
+ * @return string The escape html string
+ **/
+ function htmlattr($obj)
+ {
+ return htmlentities(json_encode($obj), ENT_QUOTES);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/css/depend.css b/plugins/system/t3/includes/depend/css/depend.css
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/system/t3/includes/depend/css/index.html b/plugins/system/t3/includes/depend/css/index.html
new file mode 100644
index 0000000..fa6d84e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/css/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/helper.php b/plugins/system/t3/includes/depend/helper.php
new file mode 100644
index 0000000..36c6ac6
--- /dev/null
+++ b/plugins/system/t3/includes/depend/helper.php
@@ -0,0 +1,67 @@
+mark('afterLoad') : null;
+
+ /**
+ * CREATE THE APPLICATION
+ *
+ * NOTE :
+ */
+ $japp = JFactory::getApplication('administrator');
+
+ /**
+ * INITIALISE THE APPLICATION
+ *
+ * NOTE :
+ */
+ $japp->initialise(array('language' => $japp->getUserState('application.lang', 'lang')));
+}
+
+$user = JFactory::getUser();
+
+jimport('joomla.filesystem.folder');
+jimport('joomla.filesystem.file');
+
+
+if(!$user->authorise('core.manage', 'com_templates')){
+ die(json_encode(array(JText::_('NO_PERMISSION'))));
+}
+
+
+$helpcls = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fileconfig.php';
+if(file_exists($helpcls))
+include_once $helpcls;
+
+$task = isset($_REQUEST['dptask']) ? $_REQUEST['dptask'] : '';
+if ($task != '' && method_exists('JAFileConfig', $task)) {
+ JAFileConfig::$task();
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/images/admin-bg.gif b/plugins/system/t3/includes/depend/images/admin-bg.gif
new file mode 100644
index 0000000..f0eeace
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/admin-bg.gif differ
diff --git a/plugins/system/t3/includes/depend/images/apply.gif b/plugins/system/t3/includes/depend/images/apply.gif
new file mode 100644
index 0000000..7ae2c8e
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/apply.gif differ
diff --git a/plugins/system/t3/includes/depend/images/arrow-blue.png b/plugins/system/t3/includes/depend/images/arrow-blue.png
new file mode 100644
index 0000000..23e26d8
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/arrow-blue.png differ
diff --git a/plugins/system/t3/includes/depend/images/arrow-level1.png b/plugins/system/t3/includes/depend/images/arrow-level1.png
new file mode 100644
index 0000000..f2de239
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/arrow-level1.png differ
diff --git a/plugins/system/t3/includes/depend/images/arrow-list.gif b/plugins/system/t3/includes/depend/images/arrow-list.gif
new file mode 100644
index 0000000..7bff889
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/arrow-list.gif differ
diff --git a/plugins/system/t3/includes/depend/images/block-head.gif b/plugins/system/t3/includes/depend/images/block-head.gif
new file mode 100644
index 0000000..a2c3afe
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/block-head.gif differ
diff --git a/plugins/system/t3/includes/depend/images/block-setting.gif b/plugins/system/t3/includes/depend/images/block-setting.gif
new file mode 100644
index 0000000..b0d924b
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/block-setting.gif differ
diff --git a/plugins/system/t3/includes/depend/images/bt-close.gif b/plugins/system/t3/includes/depend/images/bt-close.gif
new file mode 100644
index 0000000..8a889f0
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/bt-close.gif differ
diff --git a/plugins/system/t3/includes/depend/images/cancel.gif b/plugins/system/t3/includes/depend/images/cancel.gif
new file mode 100644
index 0000000..fd287fd
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/cancel.gif differ
diff --git a/plugins/system/t3/includes/depend/images/close-all.png b/plugins/system/t3/includes/depend/images/close-all.png
new file mode 100644
index 0000000..ac3e7b3
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/close-all.png differ
diff --git a/plugins/system/t3/includes/depend/images/copy.png b/plugins/system/t3/includes/depend/images/copy.png
new file mode 100644
index 0000000..8969c40
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/copy.png differ
diff --git a/plugins/system/t3/includes/depend/images/del.gif b/plugins/system/t3/includes/depend/images/del.gif
new file mode 100644
index 0000000..28696a3
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/del.gif differ
diff --git a/plugins/system/t3/includes/depend/images/del2.gif b/plugins/system/t3/includes/depend/images/del2.gif
new file mode 100644
index 0000000..247d61c
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/del2.gif differ
diff --git a/plugins/system/t3/includes/depend/images/grad.png b/plugins/system/t3/includes/depend/images/grad.png
new file mode 100644
index 0000000..ac8f875
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/grad.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-default.png b/plugins/system/t3/includes/depend/images/icon-default.png
new file mode 100644
index 0000000..c71b924
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-default.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-message.png b/plugins/system/t3/includes/depend/images/icon-message.png
new file mode 100644
index 0000000..1d9f380
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-message.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-move.png b/plugins/system/t3/includes/depend/images/icon-move.png
new file mode 100644
index 0000000..6074c87
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-move.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-moved.png b/plugins/system/t3/includes/depend/images/icon-moved.png
new file mode 100644
index 0000000..7f27b28
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-moved.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-save.png b/plugins/system/t3/includes/depend/images/icon-save.png
new file mode 100644
index 0000000..974ab69
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-save.png differ
diff --git a/plugins/system/t3/includes/depend/images/icon-success.png b/plugins/system/t3/includes/depend/images/icon-success.png
new file mode 100644
index 0000000..85607a0
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/icon-success.png differ
diff --git a/plugins/system/t3/includes/depend/images/index.html b/plugins/system/t3/includes/depend/images/index.html
new file mode 100644
index 0000000..fa6d84e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/images/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/images/level1-block.gif b/plugins/system/t3/includes/depend/images/level1-block.gif
new file mode 100644
index 0000000..4e08a83
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/level1-block.gif differ
diff --git a/plugins/system/t3/includes/depend/images/level2-block.gif b/plugins/system/t3/includes/depend/images/level2-block.gif
new file mode 100644
index 0000000..9251f94
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/level2-block.gif differ
diff --git a/plugins/system/t3/includes/depend/images/level2-close.gif b/plugins/system/t3/includes/depend/images/level2-close.gif
new file mode 100644
index 0000000..1f122e4
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/level2-close.gif differ
diff --git a/plugins/system/t3/includes/depend/images/lightbulb.png b/plugins/system/t3/includes/depend/images/lightbulb.png
new file mode 100644
index 0000000..17181a9
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/lightbulb.png differ
diff --git a/plugins/system/t3/includes/depend/images/message-bg.gif b/plugins/system/t3/includes/depend/images/message-bg.gif
new file mode 100644
index 0000000..be957b2
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/message-bg.gif differ
diff --git a/plugins/system/t3/includes/depend/images/normal-check.jpg b/plugins/system/t3/includes/depend/images/normal-check.jpg
new file mode 100644
index 0000000..75e20cb
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/normal-check.jpg differ
diff --git a/plugins/system/t3/includes/depend/images/open-all.png b/plugins/system/t3/includes/depend/images/open-all.png
new file mode 100644
index 0000000..57194e2
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/open-all.png differ
diff --git a/plugins/system/t3/includes/depend/images/popup-list.gif b/plugins/system/t3/includes/depend/images/popup-list.gif
new file mode 100644
index 0000000..7f579ef
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/popup-list.gif differ
diff --git a/plugins/system/t3/includes/depend/images/success-bg.gif b/plugins/system/t3/includes/depend/images/success-bg.gif
new file mode 100644
index 0000000..1eff709
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/success-bg.gif differ
diff --git a/plugins/system/t3/includes/depend/images/table-bg.gif b/plugins/system/t3/includes/depend/images/table-bg.gif
new file mode 100644
index 0000000..6d502eb
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/table-bg.gif differ
diff --git a/plugins/system/t3/includes/depend/images/tabs-setting.gif b/plugins/system/t3/includes/depend/images/tabs-setting.gif
new file mode 100644
index 0000000..4e08a83
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/tabs-setting.gif differ
diff --git a/plugins/system/t3/includes/depend/images/themes-default.gif b/plugins/system/t3/includes/depend/images/themes-default.gif
new file mode 100644
index 0000000..1eab171
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/themes-default.gif differ
diff --git a/plugins/system/t3/includes/depend/images/toggle-btn.png b/plugins/system/t3/includes/depend/images/toggle-btn.png
new file mode 100644
index 0000000..4c8fcf1
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/toggle-btn.png differ
diff --git a/plugins/system/t3/includes/depend/images/tooltip-bg.gif b/plugins/system/t3/includes/depend/images/tooltip-bg.gif
new file mode 100644
index 0000000..3387113
Binary files /dev/null and b/plugins/system/t3/includes/depend/images/tooltip-bg.gif differ
diff --git a/plugins/system/t3/includes/depend/index.html b/plugins/system/t3/includes/depend/index.html
new file mode 100644
index 0000000..fa6d84e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/js/depend.js b/plugins/system/t3/includes/depend/js/depend.js
new file mode 100644
index 0000000..23a97f9
--- /dev/null
+++ b/plugins/system/t3/includes/depend/js/depend.js
@@ -0,0 +1,579 @@
+/**
+ *------------------------------------------------------------------------------
+ * @package T3 Framework for Joomla!
+ *------------------------------------------------------------------------------
+ * @copyright Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ * @authors JoomlArt, JoomlaBamboo, (contribute to this project at github
+ * & Google group to become co-author)
+ * @Google group: https://groups.google.com/forum/#!forum/t3fw
+ * @Link: http://t3-framework.org
+ *------------------------------------------------------------------------------
+ */
+
+!function($){
+
+ var T3Depend = window.T3Depend = window.T3Depend || {
+
+ depends: {},
+ controls: {},
+ infos: {},
+ ajaxs: {},
+
+ register: function(to, depend){
+ var controls = this.controls;
+
+ if(!controls[to]){
+ controls[to] = [];
+
+ var inst = this;
+ this.elmsFrom(to).on('change.less', function(e){
+ inst.change(this);
+ });
+ }
+
+ if($.inArray(depend, controls[to]) == -1){
+ controls[to].push(depend);
+ }
+ },
+
+ change: function(ctrlelm){
+ var controls = this.controls,
+ depends = this.depends,
+ ctrls = controls[ctrlelm.name],
+ form = this;
+
+
+ if(!ctrls){
+ ctrls = controls[ctrlelm.name.substr(0, ctrlelm.name.length - 2)];
+ }
+
+ if(!ctrls){
+ return false;
+ }
+
+ $.each(ctrls, function(idx, ectrl){
+ var showup = true;
+
+ $.each(depends[ectrl], function(ctrl, cvals){
+ if(showup){
+ var celms = form.elmsFrom(ctrl);
+ showup = showup && !!($.grep(celms, function(celm){ return celm._disabled; }).length == 0);
+ if(showup){
+ showup = showup && !!($.grep(form.valuesFrom(celms), function(val){ return ($.inArray(val, cvals) != -1); }).length);
+ }
+ }
+ });
+
+ form.elmsFrom(ectrl).each(function(){
+ if(showup){
+ form.enable(this);
+ } else {
+ form.disable(this);
+ }
+ });
+
+ if(controls[ectrl] && controls[ectrl] != ectrl){
+ form.elmsFrom(this).eq(0).trigger('change');
+ }
+
+ });
+ },
+
+ add: function(control, info){
+
+ var depends = this.depends,
+ infos = this.infos,
+ form = this,
+ name = info.group + '[' + control + ']';
+
+ info = $.extend({
+ group: 'params',
+ hide: true
+ }, info);
+
+ $.each(info.elms.split(','), function(el){
+ var elm = info.group +'[' + $.trim(this) + ']';
+
+ if (!depends[elm]) {
+ depends[elm] = {};
+ }
+
+ //save info
+ if (!infos[elm]){
+ infos[elm] = info;
+ } else {
+ $.extend(infos[elm], info);
+ }
+
+ if (!depends[elm][name]) {
+ depends[elm][name] = [];
+ }
+
+ depends[elm][name] = depends[elm][name].concat(info.vals.split(','));
+
+ form.register(name, elm);
+
+ });
+ },
+
+ start: function(){
+ $(document.adminForm).find('h4.block-head').parent().addClass('segment');
+
+ this.update();
+ },
+
+ update: function () {
+ var form = this;
+ $.each(this.controls, function(ctrl, ctrls){
+ form.elmsFrom(ctrl).trigger('change');
+ });
+ },
+
+ enable: function (el) {
+ el._disabled = false; //selector 'li' is J2.5 compactible
+ if(this.infos[el.name] && this.infos[el.name].hide){
+ $(el).closest('.adminformlist > li, div.control-group').css('display', 'block');
+ } else {
+ $(el).closest('.controls, .t3-controls').children().removeClass('disabled');
+ }
+ },
+
+ disable: function (el) {
+ el._disabled = true; //selector 'li' is J2.5 compactible
+ if(this.infos[el.name] && this.infos[el.name].hide){
+ $(el).closest('.adminformlist > li, div.control-group').css('display', 'none');
+ } else {
+ $(el).closest('.controls, .t3-controls').children().addClass('disabled');
+ }
+ },
+
+ elmsFrom: function(name){
+ var el = document.adminForm[name];
+ if(!el){
+ el = document.adminForm[name + '[]'];
+ }
+
+ return $(el);
+ },
+
+ valuesFrom: function(els){
+ var vals = [];
+
+ $(els).each(function(){
+ var type = this.type,
+ val = $.makeArray(((type == 'radio' || type == 'checkbox') && !this.checked) ? null : $(this).val());
+
+ for (var i = 0, l = val.length; i < l; i++){
+ if($.inArray(val[i], vals) == -1){
+ vals.push(val[i]);
+ }
+ }
+ });
+
+ return vals;
+ },
+
+ addajax: function(name, info){
+ var ajaxs = this.ajaxs;
+
+ info = $.extend({
+ url: info.site == 'admin' ? T3Depend.adminurl : T3Depend.rooturl,
+ func: ''
+ }, info);
+
+ if(info.query){
+ var urlparts = info.url.split('#');
+ if(urlparts[0].indexOf('?') == -1){
+ urlparts[0] += '?' + info.query;
+ } else {
+ urlparts[0] += '&' + info.query;
+ }
+
+ info.url = urlparts.join('#');
+ }
+
+ if(!ajaxs[name]){
+ ajaxs[name] = {};
+
+ var inst = this;
+ this.elmsFrom(name).on('change.less', function(e){
+ inst.loadajax(this);
+ });
+ }
+
+ ajaxs[name].info = info;
+ },
+
+ loadajax: function(ctrlelm){
+ var ajaxs = this.ajaxs,
+ name = ctrlelm.name,
+ ctrl = ajaxs[name],
+ form = this;
+
+ if(!ctrl){
+ ctrl = ajaxs[name.substr(0, name.length - 2)];
+ }
+
+ if(!ctrl){
+ return false;
+ }
+
+ var info = ctrl.info;
+ if(!info){
+ return false;
+ }
+
+ if(ctrl.elms && ctrl.elms.length){
+ $(ctrl.elms).remove();
+ ctrl.elms.length = 0;
+ } else {
+ ctrl.elms = [];
+ }
+
+ if(!this.progElm){
+
+ }
+
+ if(!this.progElm){
+ this.progElm = $('.t3-progress');
+
+ if(!this.progElm.length){
+ this.progElm = $('
')
+ }
+
+ this.progElm.appendTo(document.body);
+
+ var placed = $('#toolbar-box');
+ if(!placed.length){
+ placed = $('#t3-admin-toolbar');
+ }
+
+ if(placed.length){
+ this.progElm.appendTo(placed);
+ }
+ }
+
+ //progress bar
+ //show it first
+ if($.support.transition){
+ form.progElm
+ .removeClass('t3-anim-slow t3-anim-finish')
+ .css('width', '');
+
+ setTimeout(function(){
+ if(!form.progElm.hasClass('t3-anim-finish')){
+ form.progElm
+ .addClass('t3-anim-slow')
+ .css('width', 50 + Math.floor(Math.random() * 20) + '%');
+ }
+ });
+ } else {
+ form.progElm.stop(true).css({
+ width: '0%',
+ display: 'block'
+ }).animate({
+ width: 50 + Math.floor(Math.random() * 20) + '%'
+ });
+ }
+
+ $.get(info.url, {
+ jvalue: form.valuesFrom(form.elmsFrom(name))[0],
+ _: $.now()
+ }).always(function(){
+ //progress bar
+ if($.support.transition){
+
+ form.progElm
+ .removeClass('t3-anim-slow')
+ .addClass('t3-anim-finish')
+ .one($.support.transition.end, function () {
+ setTimeout(function(){
+ if(form.progElm.hasClass('t3-anim-finish')){
+ $(form.progElm).removeClass('t3-anim-finish');
+ }
+ }, 1000);
+ });
+
+ } else {
+ $(form.progElm).stop(true).animate({
+ width: '100%'
+ }, function(){
+ $(form.progElm).hide();
+ });
+ }
+
+ }).done(function(rsp){
+
+ var parts = ctrl.info.func.split('.'),
+ fobj = window;
+
+ for(var i = 0; i < parts.length; i++){
+ if(!(fobj = fobj[parts[i]])) {
+ break;
+ }
+ }
+
+ if(fobj && i == parts.length && $.isFunction(fobj)){
+ fobj(form, ctrlelm, ctrl, rsp);
+ }
+ });
+ },
+
+ segment: function(seg){
+ if($(seg).hasClass('close')){
+ this.showseg(seg);
+ } else {
+ this.hideseg(seg);
+ }
+ },
+
+ showseg: function(seg){
+
+ var segelm = $(seg),
+ snext = segelm.parent().next();
+
+ while(snext.length && !snext.hasClass('segment')){
+ snext.css('display', snext.data('jdisplay') || '');
+ snext = snext.next();
+ }
+
+ segelm.removeClass('close').addClass('open');
+ },
+
+ hideseg: function(seg){
+ var segelm = $(seg),
+ snext = segelm.parent().next();
+
+ while(snext.length && !snext.hasClass('segment')){
+ snext.data('jdisplay', snext.css('display')).css('display', 'none');
+ snext = snext.next();
+ }
+
+ segelm.removeClass('open').addClass('close');
+ }
+ };
+
+ var JAFileConfig = window.JAFileConfig = window.JAFileConfig || {
+
+ vars: {
+ },
+
+ initialize: function(optionid){
+ var vars = this.vars;
+ vars.group = 't3form';
+ vars.el = document.getElementById(optionid);
+
+ var adminlist = $('#module-sliders').find('ul.adminformlist:first');
+ if(adminlist.length){
+ $(' ').appendTo(adminlist);
+ }
+ },
+
+ changeProfile: function(profile){
+ if(profile == ''){
+ return;
+ }
+
+ this.vars.active = profile;
+ this.fillData();
+
+ if(T3Depend && T3Depend.update){
+ T3Depend.update();
+ }
+ },
+
+ serializeArray: function(){
+ var vars = this.vars,
+ els = [],
+ allelms = document.adminForm.elements,
+ pname1 = vars.group + '\\[params\\]\\[.*\\]',
+ pname2 = vars.group + '\\[params\\]\\[.*\\]\\[\\]';
+
+ for (var i = 0, il = allelms.length; i < il; i++){
+ var el = $(allelms[i]);
+
+ if (el.name && ( el.name.test(pname1) || el.name.test(pname2))){
+ els.push(el);
+ }
+ }
+
+ return els;
+ },
+
+ fillData: function (){
+ var vars = this.vars,
+ els = this.serializeArray(),
+ profile = T3Depend.profiles[vars.active],
+ form = this;
+
+ if(els.length == 0 || !profile){
+ return;
+ }
+
+ $.each(els, function(){
+ var name = this.getName(this),
+ values = (profile[name] != undefined) ? profile[name] : '';
+
+ form.setValues(this, $.makeArray(values));
+ });
+ },
+
+ valuesFrom: function(els){
+ var vals = [];
+
+ $(els).each(function(){
+ var type = this.type,
+ val = $.makeArray(((type == 'radio' || type == 'checkbox') && !this.checked) ? null : $(this).val());
+
+ for (var i = 0, l = val.length; i < l; i++){
+ if($.inArray(val[i], vals) == -1){
+ vals.push(val[i]);
+ }
+ }
+ });
+
+ return vals;
+ },
+
+ setValues: function(el, vals){
+ var jel = $(el);
+
+ if(jel.prop('tagName').toUpperCase() == 'SELECT'){
+ jel.val(vals);
+
+ if($.makeArray(jel.val())[0] != vals[0]){
+ jel.val('-1');
+ }
+ }else {
+ if(jel.prop('type') == 'checkbox' || jel.prop('type') == 'radio'){
+ jel.prop('checked', $.inArray(el.value, vals) != -1);
+ } else {
+ jel.attr('placeholder', vals[0]);
+ jel.val(vals[0]);
+ }
+ }
+ },
+
+ getName: function(el){
+ var matches = el.name.match(this.vars.group + '\\[params\\]\\[([^\\]]*)\\]');
+ if (matches){
+ return matches[1];
+ }
+
+ return '';
+ },
+
+
+ deleteProfile: function(){
+ if(confirm(JAFileConfig.langs.confirmDelete)){
+ this.submitForm(JAFileConfig.mod_url + '?dptask=delete&profile=' + this.vars.active + '&template='+ JAFileConfig.template, {}, 'profile');
+ }
+ },
+
+ duplicateProfile: function (){
+ var nname = prompt(JAFileConfig.langs.enterName);
+
+ if(nname){
+ nname = nname.replace(/[^0-9a-zA-Z_-]/g, '').replace(/ /, '').toLowerCase();
+ if(nname == ''){
+ alert(JAFileConfig.langs.correctName);
+ return this.cloneProfile();
+ }
+
+ JAFileConfig.profiles[nname] = JAFileConfig.profiles[this.vars.active];
+
+ this.submitForm(JAFileConfig.mod_url + '?dptask=duplicate&profile=' + nname + '&from=' + this.vars.active + '&template=' + JAFileConfig.template, {}, 'profile');
+ }
+ },
+
+ saveProfile: function (task){
+
+ if(task){
+ JAFileConfig.profiles[this.vars.active] = this.rebuildData();
+ this.submitForm(JAFileConfig.mod_url + '?dptask=save&profile=' + this.vars.active, JAFileConfig.profiles[this.vars.active], 'profile', task);
+ }
+ },
+
+ submitForm: function(url, request, type, task){
+ if(JAFileConfig.run){
+ JAFileConfig.ajax.cancel();
+ }
+
+ JAFileConfig.run = true;
+
+ JAFileConfig.ajax = $.ajax({
+ type: 'post',
+ url: url,
+ data: request,
+ complete: function(result){
+
+ JAFileConfig.run = false;
+
+ if(result == ''){
+ return;
+ }
+
+ var vars = JAFileConfig;
+
+ alert(json.error || json.successfull);
+
+ if(result.profile){
+ switch (result.type){
+ case 'new':
+ Joomla.submitbutton(document.adminForm.task.value);
+ break;
+
+ case 'delete':
+ if(result.template == 0){
+ var opts = vars.el.options;
+
+ for(var j = 0, jl = opts.length; j < jl; j++){
+ if(opts[j].value == result.profile){
+ vars.el.remove(j);
+ break;
+ }
+ }
+ } else {
+ JAFileConfig.profiles[result.profile] = JAFileConfig.tempprofiles[result.profile];
+ }
+
+ vars.el.options[0].selected = true;
+ JAFileConfig.changeProfile(vars.el.options[0].value);
+ break;
+
+ case 'duplicate':
+ vars.el.options[vars.el.options.length] = new Option(result.profile, result.profile);
+ vars.el.options[vars.el.options.length - 1].selected = true;
+ JAFileConfig.changeProfile(result.profile);
+ break;
+
+ default:
+ }
+ }
+ }
+ });
+ },
+
+ rebuildData: function (){
+ var els = this.serializeArray(this.group),
+ form = this,
+ json = {};
+
+ $.each(els, function(){
+ var values = form.valuesFrom(this);
+ if(values.length){
+ json[this.getName(this)] = this.name.substr(-2) == '[]' ? values : values[0];
+ }
+ });
+
+ return json;
+ }
+ };
+
+ $(window).on('load', function() {
+ setTimeout($.proxy(T3Depend.start, T3Depend), 100);
+ });
+
+}(jQuery);
+
diff --git a/plugins/system/t3/includes/depend/js/index.html b/plugins/system/t3/includes/depend/js/index.html
new file mode 100644
index 0000000..fa6d84e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/js/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3depend.php b/plugins/system/t3/includes/depend/t3depend.php
new file mode 100644
index 0000000..048a33e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3depend.php
@@ -0,0 +1,368 @@
+load(T3_PLUGIN, JPATH_ADMINISTRATOR);
+
+ if(version_compare(JVERSION, '3.0', 'ge')){
+ JHtml::_('jquery.framework');
+ } else {
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.8.3.min.js');
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
+ }
+ }
+
+ if(JFactory::getApplication()->isSite() || !defined('T3_TEMPLATE')){
+ $jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
+ $jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
+ }
+
+ JFactory::getDocument()->addScriptDeclaration ( '
+ jQuery.extend(T3Depend, {
+ adminurl: \'' . JFactory::getURI()->toString() . '\',
+ rooturl: \'' . JURI::root() . '\'
+ });
+ ');
+ }
+ }
+
+ /**
+ * Element name
+ *
+ * @access protected
+ * @var string
+ */
+ protected function getInput(){
+ $this->loadAsset();
+
+ $func = (string)$this->element['function'] ? (string)$this->element['function'] : '';
+ $value = $this->value ? $this->value : (string) $this->element['default'];
+
+ if (substr($func, 0, 1) == '@'){
+ $func = substr($func, 1);
+ if (method_exists($this, $func)) {
+ return $this->$func();
+ }
+ } else {
+ $subtype = ( isset( $this->element['subtype'] ) ) ? trim($this->element['subtype']) : '';
+ if (method_exists ($this, $subtype)) {
+ return $this->$subtype ();
+ }
+ }
+ return;
+ }
+
+ /**
+ *
+ * Get profile config
+ * @return Ambigous |string
+ */
+ protected function profile()
+ {
+ $this->loadAsset();
+
+ $module = $this->element['module'];
+
+ if(!$module){
+ return JText::_('UNKNOWN_MODULE_PATH');
+ }
+
+ /* Get all profiles name folder from folder profiles */
+ $profiles = array();
+ $jsonData = array();
+ // get in module
+ $path = JPATH_SITE . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'profiles';
+ if (!JFolder::exists($path)){
+ return JText::_('PROFILE_FOLDER_NOT_EXIST');
+ }
+ $files = JFolder::files($path, '.ini');
+ if ($files) {
+ foreach ($files as $fname) {
+ $fname = substr($fname, 0, -4);
+
+ $f = new stdClass();
+ $f->id = $fname;
+ $f->title = $fname;
+
+ $profiles[$fname] = $f;
+
+ $params = new JRegistry(JFile::read($path . DIRECTORY_SEPARATOR . $fname . '.ini'));
+ $jsonData[$fname] = $params->toArray();
+ }
+ }
+
+ $xmlparams = JPATH_SITE . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'config.xml';
+ if (file_exists($xmlparams)) {
+ /* For General Form */
+ $t3form = JForm::getInstance('jform', $xmlparams, array('control' => 't3form'));
+
+ $profileHTML = JHTML::_('select.genericlist', $profiles, '' . $this->name, 'onchange="JAFileConfig.changeProfile(this.value)"', 'id', 'title', $this->value);
+
+ ob_start();
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tpls' . DIRECTORY_SEPARATOR . 'profile.php';
+ $content = ob_get_clean();
+ ob_end_flush();
+
+ return $content;
+ }
+ }
+
+ /**
+ *
+ * Get Label of element param
+ * @return string label
+ */
+ function getLabel()
+ {
+ $func = (string)$this->element['function']?(string)$this->element['function']:'';
+ if (substr($func, 0, 1) == '@' || !isset( $this->label ) || !$this->label){
+ return;
+ } else {
+ return parent::getLabel ();
+ }
+ }
+
+ /**
+ * render title: name="@title"
+ * @param string $name The name of element param
+ * @param string $value The value of element
+ * @param object $node The node of element
+ * @param string $control_name
+ * @return string title
+ */
+ function title()
+ {
+ $_title = (string) $this->element['label'];
+ $_description = $this->description;
+ $_url = (isset($this->element['url'])) ? (string) $this->element['url'] : '';
+ $class = (isset($this->element['class'])) ? (string) $this->element['class'] : '';
+ $level = (isset($this->element['level'])) ? (string) $this->element['level'] : '';
+ $group = (isset($this->element['group'])) ? (string) $this->element['group'] : '';
+ $group = $group ? "id='params$group-group'" : "";
+ if ($_title) {
+ $_title = html_entity_decode(JText::_($_title));
+ }
+
+ if ($_description) {
+ $_description = html_entity_decode(JText::_($_description));
+ }
+ if ($_url) {
+ $_url = " [" . html_entity_decode(JText::_("Demo")) . "] ";
+ }
+
+ $regionID = time()+rand();
+
+ $class_name = trim(str_replace(" ", "", strtolower($_title) ));
+
+ if($level==1){
+ $html = '
+ ';
+ } else {
+ $html = '
+
+ '.$_title.$_url.'
+
+ open
+ ';
+ }
+ //'.$_description.'
';
+
+ return $html;
+ }
+
+ /**
+ * Subtype - Checkbox: subtype="checkbox"
+ */
+ function checkbox(){
+ $k = 0;
+ $html = "";
+
+ $cols = intval($this->element['cols']);
+ if($cols == 0){
+ $cols = 1;
+ }
+ $width = floor(100/$cols);
+ $style = ' style="width:'.$width.'%;"';
+ if($this->element->children()){
+ foreach ($this->element->children() as $option)
+ {
+ $group = isset($option['group'])?intval($option['group']):0;
+ $odesc = isset($option['description'])?JText::_($option['description']):'';
+ $otext = JText::_(trim((string) $option));
+
+ $tooltip = addslashes(htmlspecialchars($odesc, ENT_QUOTES, 'UTF-8'));
+ $titletip = addslashes(htmlspecialchars($otext, ENT_QUOTES, 'UTF-8'));
+
+ if($titletip) {
+ $titletip = $titletip.'::';
+ }
+
+ if($group) {
+ $html .= "\n\t$otext
";
+ } else {
+
+
+ $oval = $option['value'];
+ $children = $option['children'];
+ $alt = ($children) ? ' alt="'.$children.'"' : '';
+ $extra = '';
+
+ if (is_array( $this->value ))
+ {
+ foreach ($this->value as $val)
+ {
+ $val2 = is_object( $val ) ? $val->$key : $val;
+ if ($oval == $val2)
+ {
+ $extra .= ' checked="checked"';
+ break;
+ }
+ }
+ } else {
+ $extra .= ( (string)$oval == (string)$this->value ? ' checked="checked"' : '' );
+ }
+
+ $html .= "\n\t";
+ $html .= "\n\t name}[]\" id=\"{$this->id}{$k}\" value=\"$oval\"$extra $alt />";
+ $html .= "\n\tid}{$k}-label\" class=\"hasTip\" title=\"{$titletip}{$tooltip}\" for=\"{$this->id}{$k}\">$otext ";
+ $html .= "\n\t
";
+
+ $k++;
+ }
+ }
+ }
+
+ return $html;
+ }
+
+ /**
+ * render js to control setting form.
+ * @param string $name The name of element param
+ * @param string $value The value of element
+ * @param object $node The node of element
+ * @param string $control_name
+ * @return string group param
+ */
+ function group(){
+ $this->loadAsset();
+
+ if(preg_match_all('@\[([^\]]*)\]@', $this->name, $matches)):
+
+ $group_name = str_replace(end($matches[0]), '', $this->name);
+ ?>
+
+ element->children() as $option):
+ $fparams = array();
+ if (!empty($option['url'])){
+ $fparams['url'] = (string)$option['url'];
+ }
+
+ if (!empty($option['site'])){
+ $fparams['site'] = (string)$option['site'];
+ }
+
+ if (!empty($option['query'])){
+ $fparams['query'] = (string)$option['query'];
+ } else {
+ $fparams['query'] = '';
+ }
+ // append styleid into query
+ $input = JFactory::getApplication()->input;
+ if($input->getCmd('option') == 'com_templates' &&
+ (preg_match('/style\./', $input->getCmd('task')) || $input->getCmd('view') == 'style' || $input->getCmd('view') == 'template')
+ ){
+ $fparams['query'] .= '&styleid='.$input->getInt('id');
+ }
+
+ if (!empty($option['func'])){
+ $fparams['func'] = (string)$option['func'];
+ }
+
+ $fcalls[] = 'T3Depend.addajax(\'' . $this->getName($option['for']) . '\', ' . json_encode($fparams) . ');';
+ endforeach;
+ ?>
+
+ ' . JText::_($this->element['label']) . '' . JText::_($this->element['description']) . ' ';
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3filelist.php b/plugins/system/t3/includes/depend/t3filelist.php
new file mode 100644
index 0000000..6245e7e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3filelist.php
@@ -0,0 +1,78 @@
+element['directory'];
+ $options = array();
+ if (!is_dir($path)) {
+ // get files in template path
+ $this->directory = $this->element['directory'] = T3_TEMPLATE_PATH . DIRECTORY_SEPARATOR . $path;
+ $options = parent::getOptions();
+ // get files in template local path
+
+ if (!defined('T3_LOCAL_DISABLED') && is_dir (T3_LOCAL_PATH . DIRECTORY_SEPARATOR . $path)) {
+ $this->directory = $this->element['directory'] = T3_LOCAL_PATH . DIRECTORY_SEPARATOR . $path;
+ $options2 = parent::getOptions();
+ foreach ($options2 as $option) {
+ $option->text .= ' (local)';
+ $options[] = $option;
+ }
+ }
+ }
+ return $options;
+ }
+}
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3folderlist.php b/plugins/system/t3/includes/depend/t3folderlist.php
new file mode 100644
index 0000000..73cea6e
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3folderlist.php
@@ -0,0 +1,74 @@
+load((int) JFactory::getApplication()->input->getInt('id'));
+ // update path to this template
+ $path = (string) $this->element['directory'];
+ if (!is_dir($path))
+ {
+ // process path in template
+ $options = array();
+ $vals = array();
+ // get all path in template
+ $paths = T3Path::getAllPath ($path);
+ foreach ($paths as $path) {
+ $this->directory = $this->element['directory'] = $path;
+ $tmps = parent::getOptions();
+ foreach ($tmps as $tmp) {
+ if (in_array($tmp->value, $vals)) continue;
+ $vals[] = $tmp->value;
+ $options[] = $tmp;
+ }
+ }
+ return $options;
+ }
+
+ return parent::getOptions();
+ }
+}
diff --git a/plugins/system/t3/includes/depend/t3form.php b/plugins/system/t3/includes/depend/t3form.php
new file mode 100644
index 0000000..401e76b
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3form.php
@@ -0,0 +1,162 @@
+ $value) {
+ $this->$property = $value;
+ }
+
+ } else {
+ parent::__construct($name, $options);
+ }
+ }
+
+
+ /**
+ * Method to load the form description from an XML string or object.
+ *
+ * The replace option works per field. If a field being loaded already exists in the current
+ * form definition then the behavior or load will vary depending upon the replace flag. If it
+ * is set to true, then the existing field will be replaced in its exact location by the new
+ * field being loaded. If it is false, then the new field being loaded will be ignored and the
+ * method will move on to the next field to load.
+ *
+ * @param string $data The name of an XML string or object.
+ * @param string $replace Flag to toggle whether form fields should be replaced if a field
+ * already exists with the same group/name.
+ * @param string $xpath An optional xpath to search for the fields.
+ *
+ * @return boolean True on success, false otherwise.
+ *
+ * @since 11.1
+ */
+ public function load($data, $replace = true, $xpath = false)
+ {
+ // If the data to load isn't already an XML element or string return false.
+ if ((!($data instanceof SimpleXMLElement)) && (!is_string($data)))
+ {
+ return false;
+ }
+
+ // Attempt to load the XML if a string.
+ if (is_string($data))
+ {
+ try
+ {
+ $data = new SimpleXMLElement($data);
+ }
+ catch (Exception $e)
+ {
+ return false;
+ }
+
+ // Make sure the XML loaded correctly.
+ if (!$data)
+ {
+ return false;
+ }
+ }
+
+ // If we have no XML definition at this point let's make sure we get one.
+ if (empty($this->xml))
+ {
+ // If no XPath query is set to search for fields, and we have a , set it and return.
+ if (!$xpath && ($data->getName() == 'form'))
+ {
+ $this->xml = $data;
+
+ // Synchronize any paths found in the load.
+ $this->syncPaths();
+
+ return true;
+ }
+ // Create a root element for the form.
+ else
+ {
+ $this->xml = new SimpleXMLElement('');
+ }
+ }
+
+ // Get the XML elements to load.
+ $elements = array();
+ if ($xpath)
+ {
+ $elements = $data->xpath($xpath);
+ }
+ elseif ($data->getName() == 'form')
+ {
+ $elements = $data->children();
+ }
+
+ // If there is nothing to load return true.
+ if (empty($elements))
+ {
+ return true;
+ }
+
+ // Load the found form elements.
+ foreach ($elements as $element)
+ {
+ // Get an array of fields with the correct name.
+ $fields = $element->xpath('descendant-or-self::field');
+ foreach ($fields as $field)
+ {
+ // Get the group names as strings for ancestor fields elements.
+ $attrs = $field->xpath('ancestor::fields[@name]/@name');
+ $groups = array_map('strval', $attrs ? $attrs : array());
+
+ // Check to see if the field exists in the current form.
+ if ($current = $this->findField((string) $field['name'], implode('.', $groups)))
+ {
+
+ // If set to replace found fields, replace the data and remove the field so we don't add it twice.
+ if ($replace)
+ {
+ $olddom = dom_import_simplexml($current);
+ $loadeddom = dom_import_simplexml($field);
+ $addeddom = $olddom->ownerDocument->importNode($loadeddom, true); // Import child nodes too
+ $olddom->parentNode->replaceChild($addeddom, $olddom);
+ $loadeddom->parentNode->removeChild($loadeddom);
+ }
+ else
+ {
+ unset($field);
+ }
+ }
+ }
+
+ // Merge the new field data into the existing XML document.
+ self::addNode($this->xml, $element);
+ }
+
+ // Synchronize any paths found in the load.
+ $this->syncPaths();
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3layoutlist.php b/plugins/system/t3/includes/depend/t3layoutlist.php
new file mode 100644
index 0000000..c451ae8
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3layoutlist.php
@@ -0,0 +1,81 @@
+element['directory'];
+ if (!is_dir($path)) {
+ $this->directory = $this->element['directory'] = T3_TEMPLATE_PATH . DIRECTORY_SEPARATOR . $path;
+ }
+
+ $options = parent::getOptions();
+
+ // get addon layouts
+ $folders = JFolder::folders(T3_TEMPLATE_PATH . '/addons');
+
+ // Build the options list from the list of folders.
+ if (is_array($folders))
+ {
+ foreach ($folders as $folder)
+ {
+ $options[] = JHtml::_('select.option', 'addon.'.$folder, 'addon - '.$folder);
+ }
+ }
+
+ return $options;
+
+ }
+}
+?>
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3media.php b/plugins/system/t3/includes/depend/t3media.php
new file mode 100644
index 0000000..4274568
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3media.php
@@ -0,0 +1,257 @@
+element['asset_field'] ? (string) $this->element['asset_field'] : 'asset_id';
+ $authorField = $this->element['created_by_field'] ? (string) $this->element['created_by_field'] : 'created_by';
+ $asset = $this->form->getValue($assetField) ? $this->form->getValue($assetField) : (string) $this->element['asset_id'];
+ if ($asset == '')
+ {
+ $asset = JFactory::getApplication()->input->get('option');
+ }
+
+ $link = (string) $this->element['link'];
+ if (!self::$initialised)
+ {
+ // Load the modal behavior script.
+ JHtml::_('behavior.modal');
+
+ // Build the script.
+ $script = array();
+ $script[] = ' function jInsertFieldValue(value, id) {';
+ $script[] = ' var old_value = document.id(id).value;';
+ $script[] = ' if (old_value != value) {';
+ $script[] = ' var elem = document.id(id);';
+ $script[] = ' elem.value = value;';
+ $script[] = ' elem.fireEvent("change");';
+ $script[] = ' if (typeof(elem.onchange) === "function") {';
+ $script[] = ' elem.onchange();';
+ $script[] = ' }';
+ $script[] = ' jMediaRefreshPreview(id);';
+ $script[] = ' }';
+ $script[] = ' }';
+
+ $script[] = ' function jMediaRefreshPreview(id) {';
+ $script[] = ' var value = document.id(id).value;';
+ $script[] = ' var img = document.id(id + "_preview");';
+ $script[] = ' if (img) {';
+ $script[] = ' if (value) {';
+ $script[] = ' img.src = "' . JURI::root() . '" + value;';
+ $script[] = ' document.id(id + "_preview_empty").setStyle("display", "none");';
+ $script[] = ' document.id(id + "_preview_img").setStyle("display", "");';
+ $script[] = ' } else { ';
+ $script[] = ' img.src = ""';
+ $script[] = ' document.id(id + "_preview_empty").setStyle("display", "");';
+ $script[] = ' document.id(id + "_preview_img").setStyle("display", "none");';
+ $script[] = ' } ';
+ $script[] = ' } ';
+ $script[] = ' }';
+
+ $script[] = ' function jMediaRefreshPreviewTip(tip)';
+ $script[] = ' {';
+ $script[] = ' var img = tip.getElement("img.media-preview");';
+ $script[] = ' tip.getElement("div.tip").setStyle("max-width", "none");';
+ $script[] = ' var id = img.getProperty("id");';
+ $script[] = ' id = id.substring(0, id.length - "_preview".length);';
+ $script[] = ' jMediaRefreshPreview(id);';
+ $script[] = ' tip.setStyle("display", "block");';
+ $script[] = ' }';
+
+ // Add the script to the document head.
+ JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
+
+ self::$initialised = true;
+ }
+
+ $html = array();
+ $attr = '';
+
+ // Initialize some field attributes.
+ $attr .= $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : '';
+ $attr .= $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : '';
+
+ // Initialize JavaScript field attributes.
+ $attr .= $this->element['onchange'] ? ' onchange="' . (string) $this->element['onchange'] . '"' : '';
+
+ // The text field.
+ $html[] = '';
+
+ return implode("\n", $html);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3megamenu.php b/plugins/system/t3/includes/depend/t3megamenu.php
new file mode 100644
index 0000000..19baaeb
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3megamenu.php
@@ -0,0 +1,151 @@
+getMegaMenuMarkup();
+ }
+
+ /**
+ * Method to get the field input markup for a generic list.
+ * Use the multiple attribute to enable multiselect.
+ *
+ * @return string The field input markup.
+ *
+ * @since 11.1
+ */
+ protected function getMegaMenuMarkup()
+ {
+ if(!defined('T3')){
+ return false;
+ }
+
+ if(!defined('T3_TEMPLATE')){
+ $this->loadT3Depend();
+ }
+
+ $t3path = T3_ADMIN_PATH;
+
+ if(!defined('__T3_MEGAMENU_ASSET__')){
+ define('__T3_MEGAMENU_ASSET__', 1);
+
+ $jdoc = JFactory::getDocument();
+
+ if(is_file(T3_PATH . '/css/megamenu.css')){
+ $jdoc->addStylesheet(T3_URL . '/css/megamenu.css');
+ }
+
+ if(is_file(T3_ADMIN_PATH . '/admin/megamenu/css/megamenu.css')){
+ $jdoc->addStylesheet(T3_ADMIN_URL . '/admin/megamenu/css/megamenu.css');
+ }
+
+ if(version_compare(JVERSION, '3.0', 'ge')){
+ JHtml::_('jquery.framework');
+ } else {
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.8.3.min.js');
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
+ }
+
+ if(is_file(T3_ADMIN_PATH . '/admin/megamenu/js/megamenu.js')){
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/megamenu/js/megamenu.js');
+ }
+ }
+
+ if(is_file(T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php')){
+ include T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php';
+ }
+
+ if($this->element['hide']):
+ ?>
+
+ load(T3_PLUGIN, JPATH_ADMINISTRATOR);
+
+ $jdoc = JFactory::getDocument();
+ $jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
+ $jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
+
+ JFactory::getDocument()->addScriptDeclaration ( '
+ jQuery.extend(T3Depend, {
+ adminurl: \'' . JFactory::getURI()->toString() . '\',
+ rooturl: \'' . JURI::root() . '\'
+ });
+ ');
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3modules.php b/plugins/system/t3/includes/depend/t3modules.php
new file mode 100644
index 0000000..2082aba
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3modules.php
@@ -0,0 +1,126 @@
+load(T3_PLUGIN, JPATH_ADMINISTRATOR);
+
+ if(version_compare(JVERSION, '3.0', 'ge')){
+ JHtml::_('jquery.framework');
+ } else {
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.8.3.min.js');
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
+ }
+
+ $jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
+ $jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
+ }
+
+ JFactory::getDocument()->addScriptDeclaration ( '
+ jQuery.extend(T3Depend, {
+ adminurl: \'' . JFactory::getURI()->toString() . '\',
+ rooturl: \'' . JURI::root() . '\'
+ });
+ ');
+ }
+ }
+
+ /**
+ * Method to get the field input markup.
+ *
+ * @return string The field input markup.
+ */
+ function getInput()
+ {
+ $this->loadAsset();
+
+ $show_default = $this->toBoolean((string) $this->element['show_default']);
+ $show_none = $this->toBoolean((string) $this->element['show_none']);
+ $multiple = $this->toBoolean((string) $this->element['multiple']);
+ $disabled = $this->toBoolean((string) $this->element['disabled']);
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('id, title, module, position')
+ ->from('#__modules')
+ ->where('published = 1')
+ ->where('client_id = 0')
+ ->order('title');
+ $db->setQuery($query);
+
+ $modules = $db->loadObjectList();
+ $moduleopts = array();
+
+ if($show_default){
+ $moduleopts[] = JHTML::_('select.option', 'default', JText::_('JDEFAULT'));
+ }
+
+ if($show_none){
+ $moduleopts[] = JHTML::_('select.option', 'none', JText::_('JNONE'));
+ }
+
+ if (is_array($modules)) {
+ foreach ($modules as $module) {
+ $moduleopts[] = JHTML::_('select.option', $module->id, $module->title);
+ }
+ }
+
+ return JHTML::_('select.genericlist', $moduleopts, $this->name . ($multiple ? '[]' : ''), ($multiple ? 'multiple="multiple" size="10" ' : '') . ($disabled ? 'disabled="disabled"' : ''), 'value', 'text', $this->value);
+ }
+
+
+ /**
+ * Helper function, check the field attribute and return boolean value
+ *
+ * @return boolean the check result
+ */
+ function toBoolean($str){
+ return !in_array($str, array('false', '', '0', 'no', 'off'));
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/t3positions.php b/plugins/system/t3/includes/depend/t3positions.php
new file mode 100644
index 0000000..dac5cc4
--- /dev/null
+++ b/plugins/system/t3/includes/depend/t3positions.php
@@ -0,0 +1,127 @@
+load(T3_PLUGIN, JPATH_ADMINISTRATOR);
+
+ if(version_compare(JVERSION, '3.0', 'ge')){
+ JHtml::_('jquery.framework');
+ } else {
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.8.3.min.js');
+ $jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
+ }
+
+ $jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
+ $jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
+ }
+
+ JFactory::getDocument()->addScriptDeclaration ( '
+ jQuery.extend(T3Depend, {
+ adminurl: \'' . JFactory::getURI()->toString() . '\',
+ rooturl: \'' . JURI::root() . '\'
+ });
+ ');
+ }
+ }
+
+ /**
+ * Method to get the field input markup.
+ *
+ * @return string The field input markup.
+ */
+ function getInput()
+ {
+ $this->loadAsset();
+
+ T3::import('admin/layout');
+
+ return $this->getPositions();
+ }
+
+ function getPositions()
+ {
+ $path = JPATH_SITE;
+ $lang = JFactory::getLanguage();
+ $clientId = 0;
+ $state = 1;
+
+ $templates = array_keys(T3AdminLayout::getTemplates($clientId, $state));
+ $templateGroups = array();
+
+ // Add positions from templates
+ foreach ($templates as $template) {
+ $options = array();
+
+ $positions = T3AdminLayout::getTplPositions($clientId, $template);
+ if (is_array($positions))
+ foreach ($positions as $position) {
+ $text = T3AdminLayout::getTranslatedModulePosition($clientId, $template, $position) . ' [' . $position . ']';
+ $options[] = T3AdminLayout::createOption($position, $text);
+ }
+
+ $templateGroups[$template] = T3AdminLayout::createOptionGroup(ucfirst($template), $options);
+ }
+
+ // Add custom position to options
+ $customGroupText = JText::_('T3_LAYOUT_CUSTOM_POSITION');
+ $customPositions = T3AdminLayout::getDbPositions($clientId);
+ $templateGroups[$customGroupText] = T3AdminLayout::createOptionGroup($customGroupText, $customPositions);
+
+
+ $multiple = $this->toBoolean((string) $this->element['multiple']);
+ $disabled = $this->toBoolean((string) $this->element['disabled']);
+
+
+ return JHtml::_('select.groupedlist', $templateGroups, $this->name, array(
+ 'list.attr' => ($multiple ? ' multiple="multiple" size="10"' : '') . ($disabled ? 'disabled="disabled"' : '')
+ ));
+ }
+
+
+ /**
+ * Helper function, check the field attribute and return boolean value
+ *
+ * @return boolean the check result
+ */
+ function toBoolean($attr){
+ return !in_array($attr, array('false', '', '0', 'no', 'off'));
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/depend/tpls/profile.php b/plugins/system/t3/includes/depend/tpls/profile.php
new file mode 100644
index 0000000..b7db3b5
--- /dev/null
+++ b/plugins/system/t3/includes/depend/tpls/profile.php
@@ -0,0 +1,129 @@
+
+
+
+
+
element["label"])?>
+
+
+
+
+isCompatible('3.0')) : ?>
+
+
+
+
+
+
+getFieldsets('params');
+
+foreach ($fieldSets as $name => $fieldSet) :
+ if (isset($fieldSet->description) && trim($fieldSet->description)){
+ echo ''.JText::_($fieldSet->description).'
';
+ }
+
+ $hidden_fields = '';
+ foreach ($t3form->getFieldset($name) as $field) :
+ if (!$field->hidden) :
+ if($javersion->isCompatible('3.0')) : ?>
+
+
+
+
+ getLabel($field->fieldname,$field->group);
+
+ if($javersion->isCompatible('3.0')) : ?>
+
+
+ getInput($field->fieldname,$field->group);
+ if($javersion->isCompatible('3.0')) : ?>
+
+
+
+
+ getInput($field->fieldname,$field->group);
+ endif;
+ endforeach;
+ echo $hidden_fields;
+endforeach;
+?>
+
+isCompatible('3.0')) : ?>
+
+
+
+
+
+
+
diff --git a/plugins/system/t3/includes/extendable/extendable.php b/plugins/system/t3/includes/extendable/extendable.php
new file mode 100644
index 0000000..3809388
--- /dev/null
+++ b/plugins/system/t3/includes/extendable/extendable.php
@@ -0,0 +1,73 @@
+= 5) {
+ include_once dirname(__FILE__) . '/object.5.php';
+} else {
+ include_once dirname(__FILE__) . '/object.4.php';
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/extendable/object.4.php b/plugins/system/t3/includes/extendable/object.4.php
new file mode 100644
index 0000000..d347c36
--- /dev/null
+++ b/plugins/system/t3/includes/extendable/object.4.php
@@ -0,0 +1,67 @@
+_extendableObjects = $oObject;
+ }
+
+ function __get($sName, &$sValue)
+ {
+ for ($i = 0; $i < count($this->_extendableObjects); $i++) {
+ if (property_exists($this->_extendableObjects[$i], $sName)) {
+ $sValue = $this->_extendableObjects[$i]->$sName;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function __set($sName, &$sValue)
+ {
+ for ($i = 0; $i < count($this->_extendableObjects); $i++) {
+ if (property_exists($this->_extendableObjects[$i], $sName)) {
+ $this->_extendableObjects[$i]->$sName = $sValue;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function __call($sName, $aArgs = array(), &$return)
+ {
+ // try call itself method
+ if (method_exists($this, $sName)) {
+ $return = call_user_func_array(array($this, $sName), $aArgs);
+ return true;
+ }
+
+ // try to call method extended from objects
+ for ($i = 0; $i < count($this->_extendableObjects); $i++) {
+ //if (method_callable($this->_extendableObjects[$i], $sName)) {
+ if (method_exists($this->_extendableObjects[$i], $sName)) {
+ $return = call_user_func_array(array(&$this->_extendableObjects[$i], $sName), $aArgs);
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/extendable/object.5.php b/plugins/system/t3/includes/extendable/object.5.php
new file mode 100644
index 0000000..9fc55f9
--- /dev/null
+++ b/plugins/system/t3/includes/extendable/object.5.php
@@ -0,0 +1,69 @@
+_extendableObjects[] = $oObject;
+ } else if (is_array($oObject)) {
+ $this->_extendableObjects = array_merge($this->_extendableObjects, $oObject);
+ }
+ }
+
+ function __get($sName)
+ {
+ foreach ($this->_extendableObjects as $oObject) {
+ if (property_exists($oObject, $sName)) {
+ $sValue = $oObject->$sName;
+ return $sValue;
+ }
+ }
+
+ return null;
+ }
+
+ function __set($sName, $sValue)
+ {
+ foreach ($this->_extendableObjects as $oObject) {
+ if (property_exists($oObject, $sName)) {
+ return $oObject->$sName = $sValue;
+ }
+ }
+ }
+
+ function __call($sName, $aArgs = array())
+ {
+ // try call itself method
+ if (method_exists($this, $sName)) {
+ $return = call_user_func_array(array($this, $sName), $aArgs);
+ return $return;
+ }
+
+ // try to call method extended from objects
+ foreach ($this->_extendableObjects as $oObject) {
+ //if (method_callable($oObject, $sName)) {
+ if (method_exists($oObject, $sName)) {
+ $return = call_user_func_array(array($oObject, $sName), $aArgs);
+ return $return;
+ }
+ }
+
+ return NULL;
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/format/less.php b/plugins/system/t3/includes/format/less.php
new file mode 100644
index 0000000..4958a8a
--- /dev/null
+++ b/plugins/system/t3/includes/format/less.php
@@ -0,0 +1,178 @@
+ $value)
+ {
+ // If the value is an object then we need to put it in a local section.
+ if ($key == 'import-external-urls') {
+ $import_urls = explode ("\n", $value);
+ } else {
+ $result[] = $this->getKey($key) . ': ' . $this->getValue($value);
+ }
+ }
+
+ $output = '';
+ if (is_array ($import_urls)) {
+ foreach ($import_urls as $url) {
+ $output .= "@import url({$url});\n";
+ }
+ }
+
+ $output .= "\n" . implode("\n", $result);
+
+ return $output;
+ }
+
+ /**
+ * Parse an INI formatted string and convert it into an object.
+ *
+ * @param string $data INI formatted string to convert.
+ * @param mixed $options An array of options used by the formatter, or a boolean setting to process sections.
+ *
+ * @return object Data object.
+ *
+ * @since 11.1
+ */
+ public function stringToObject($data, $options = array())
+ {
+ // If no lines present just return the object.
+ if (empty($data))
+ {
+ return new stdClass;
+ }
+
+ // Initialize variables.
+ $obj = new stdClass;
+ $lines = explode("\n", $data);
+ $import_urls = array();
+
+ // Process the lines.
+ foreach ($lines as $line)
+ {
+ // Trim any unnecessary whitespace.
+ $line = trim($line);
+
+ // Ignore empty lines and comments.
+ if (empty($line) || (substr($line, 0, 1) == '/') || (substr($line, 0, 1) == '*'))
+ {
+ continue;
+ }
+
+ // if url import
+ if (preg_match ('/@import\s+url\((.+)\);/', $line, $match)) {
+ $import_urls[] = $match[1];
+ continue;
+ }
+
+ // Check that an equal sign exists and is not the first character of the line.
+ if (!strpos($line, ':'))
+ {
+ // Maybe throw exception?
+ continue;
+ }
+
+ // Get the key and value for the line.
+ list ($key, $value) = explode(':', $line, 2);
+
+ // Validate the key.
+ if (preg_match('/@[^A-Z0-9_]/i', $key))
+ {
+ // Maybe throw exception?
+ continue;
+ }
+
+ // Validate the value.
+ //if (preg_match('/[^\(\)A-Z0-9_-];$/i', $value))
+ //{
+ // Maybe throw exception?
+ // continue;
+ //}
+
+ // If the value is quoted then we assume it is a string.
+
+ $key = str_replace('@', '', $key);
+ $value = str_replace(';', '', $value);
+ $value = preg_replace('/\/\/(.*)/', '', $value);
+ $value = trim($value);
+ $obj->$key = $value;
+ }
+
+ // update font import
+ $key = 'import-external-urls';
+ $obj->$key = implode ("\n", $import_urls);
+
+ // Cache the string to save cpu cycles -- thus the world :)
+
+ return $obj;
+ }
+
+ /**
+ * Method to get a value in an INI format.
+ *
+ * @param mixed $value The value to convert to INI format.
+ *
+ * @return string The value in INI format.
+ *
+ * @since 11.1
+ */
+ protected function getValue($value)
+ {
+ return $value . ';';
+ }
+
+ /**
+ * Method to get a value in an INI format.
+ *
+ * @param mixed $key
+ *
+ * @return string The value in INI format.
+ *
+ * @since 11.1
+ */
+ protected function getKey($key)
+ {
+ return '@' . $key;
+ }
+}
diff --git a/plugins/system/t3/includes/format/less3.3.php b/plugins/system/t3/includes/format/less3.3.php
new file mode 100644
index 0000000..8b923ca
--- /dev/null
+++ b/plugins/system/t3/includes/format/less3.3.php
@@ -0,0 +1,162 @@
+ $value)
+ {
+ // If the value is an object then we need to put it in a local section.
+ if ($key == 'import-external-urls') {
+ $import_urls = explode ("\n", $value);
+ } else {
+ $result[] = $this->getKey($key) . ': ' . $this->getValue($value);
+ }
+ }
+
+ $output = '';
+ if (is_array ($import_urls)) {
+ foreach ($import_urls as $url) {
+ $output .= "@import url({$url});\n";
+ }
+ }
+
+ $output .= "\n" . implode("\n", $result);
+
+ return $output;
+ }
+
+ /**
+ * Converts an LESS variables string to name/value pair object
+ */
+ public function stringToObject($data, array $options = array())
+ {
+ // If no lines present just return the object.
+ if (empty($data))
+ {
+ return new stdClass;
+ }
+
+ // Initialize variables.
+ $obj = new stdClass;
+ $lines = explode("\n", $data);
+ $import_urls = array();
+
+ // Process the lines.
+ foreach ($lines as $line)
+ {
+ // Trim any unnecessary whitespace.
+ $line = trim($line);
+
+ // Ignore empty lines and comments.
+ if (empty($line) || (substr($line, 0, 1) == '/') || (substr($line, 0, 1) == '*'))
+ {
+ continue;
+ }
+
+ // if url import
+ if (preg_match ('/@import\s+url\((.+)\);/', $line, $match)) {
+ $import_urls[] = $match[1];
+ continue;
+ }
+
+ // Check that an equal sign exists and is not the first character of the line.
+ if (!strpos($line, ':'))
+ {
+ // Maybe throw exception?
+ continue;
+ }
+
+ // Get the key and value for the line.
+ list ($key, $value) = explode(':', $line, 2);
+
+ // Validate the key.
+ if (preg_match('/@[^A-Z0-9_]/i', $key))
+ {
+ // Maybe throw exception?
+ continue;
+ }
+
+ // Validate the value.
+ //if (preg_match('/[^\(\)A-Z0-9_-];$/i', $value))
+ //{
+ // Maybe throw exception?
+ // continue;
+ //}
+
+ // If the value is quoted then we assume it is a string.
+
+ $key = str_replace('@', '', $key);
+ $value = str_replace(';', '', $value);
+ $value = preg_replace('/\/\/(.*)/', '', $value);
+ $value = trim($value);
+ $obj->$key = $value;
+ }
+
+ // update font import
+ $key = 'import-external-urls';
+ $obj->$key = implode ("\n", $import_urls);
+
+ // Cache the string to save cpu cycles -- thus the world :)
+
+ return $obj;
+ }
+
+ /**
+ * Method to get a value in an INI format.
+ *
+ * @param mixed $value The value to convert to INI format.
+ *
+ * @return string The value in INI format.
+ *
+ * @since 11.1
+ */
+ protected function getValue($value)
+ {
+ return $value . ';';
+ }
+
+ /**
+ * Method to get a value in an INI format.
+ *
+ * @param mixed $key
+ *
+ * @return string The value in INI format.
+ *
+ * @since 11.1
+ */
+ protected function getKey($key)
+ {
+ return '@' . $key;
+ }
+}
diff --git a/plugins/system/t3/includes/gfont/T3GFont.php b/plugins/system/t3/includes/gfont/T3GFont.php
new file mode 100644
index 0000000..46176b1
--- /dev/null
+++ b/plugins/system/t3/includes/gfont/T3GFont.php
@@ -0,0 +1,191 @@
+input;
+
+ $template = $input->getCmd('template');
+ $fontname = $input->getCmd('fontname');
+
+ // Get gfont path
+ $fontpath = self::getFontPath($template);
+ // Get font data
+ if ($fontpath !== false) {
+ $data = @file_get_contents($fontpath);
+ // Check to update font
+ $idx = strpos($data, '#');
+ if ($idx !== false) {
+ // Seperate time & json font list
+ $time = (int) substr($data, 0, $idx);
+ $data = substr($data, $idx + 1);
+ // Check if not update 3 days => update
+ if (time() - $time > 3 * 86400) {
+ // Get local font path
+ $fontpath = self::getFontPath($template, self::$gfontcache, true);
+ // Update font list
+ $status = self::updateFontList($fontpath);
+ // If success, re-get font list
+ if ($status) {
+ $data = @file_get_contents($fontpath);
+ $idx = strpos($data, '#');
+ if ($idx !== false) {
+ $data = substr($data, $idx + 1);
+ }
+ }
+ }
+ }
+
+ $result = '';
+
+ if($data){
+ // Parse fonts information
+ $font = json_decode($data);
+ $items = $font->items;
+ // Find suitable font by fontname
+ foreach ($items as $item) {
+ if (strcasecmp($fontname, $item->family) == 0) {
+ $result = $item;
+ break;
+ }
+ }
+ }
+
+ } else {
+ $result = '';
+ }
+
+ echo json_encode($result);
+ exit;
+ }
+
+
+ /**
+ * Get font list
+ *
+ * @return void
+ */
+ function getFontList()
+ {
+ $input = JFactory::getApplication()->input;
+
+ $template = $input->getCmd('template');
+ $fontname = $input->getCmd('fontname');
+
+ // Get gfont path
+ $fontpath = self::getFontPath($template);
+ if ($fontpath !== false) {
+ // Get font list
+ $data = @file_get_contents($fontpath);
+ // Remove time before json data
+ $idx = strpos($data, '#');
+ if ($idx !== false) {
+ $data = substr($data, $idx + 1);
+ }
+ // Parse data
+ $font = json_decode($data);
+ $items = $font->items;
+ $result = array();
+ $pattern = '/^' . $fontname . '.*/i';
+ // Find suitable font by fontname
+ foreach ($items as $item) {
+ if (preg_match($pattern, $item->family)) {
+ $result[] = $item->family;
+ }
+ }
+ } else {
+ $result = array();
+ }
+
+ echo json_encode($result);
+ exit;
+ }
+
+ /**
+ * Get gfont path
+ *
+ * @param string $template Template name
+ * @param string $filename Filename include extension
+ * @param bool $local Indicate get local path or not
+ *
+ * @return mixed Gfont file path if found, otherwise FALSE
+ */
+ function getFontPath($template, $filename = false)
+ {
+ if(!$filename){
+ $filename = self::$gfontcache;
+ }
+
+ // Check to sure that template is using new folder structure
+ // If etc folder exists, considered as template is using new folder structure
+ $filepath = JPATH_SITE . '/templates/' . $template . '/etc';
+ if (@is_dir($filepath)) {
+ $filepath .= '/' . $filename;
+ }
+
+ // Check file exists or not
+ if (@is_file($filepath)) {
+ return $filepath;
+ }
+
+ // Check file in base
+ $filepath = T3_PATH . '/etc/' . $filename;
+ if (@is_file($filepath)) {
+ return $filepath;
+ }
+
+ // Can not find google font file
+ return false;
+ }
+
+ /**
+ * Update font list from google web font page
+ *
+ * @param string $path File path store font list
+ *
+ * @return bool TRUE if update success, otherwise FALSE
+ */
+ function updateFontList($path)
+ {
+ $key = 'AIzaSyA6_mK8ERGaR4_dhK6tJVEdvJPQEdwULWg';
+ $url = 'https://www.googleapis.com/webfonts/v1/webfonts?key=' . $key;
+ $content = @file_get_contents($url);
+ if (!empty($content)) {
+ $content = time() . '#' . $content;
+ $result = file_put_contents($path, $content);
+ return ($result !== false);
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/jacssjanus/csslex.php b/plugins/system/t3/includes/jacssjanus/csslex.php
new file mode 100644
index 0000000..5fc5b61
--- /dev/null
+++ b/plugins/system/t3/includes/jacssjanus/csslex.php
@@ -0,0 +1,107 @@
+" {return cdc;}
+ # "~=" {return includes;}
+ # "|=" {return dashmatch;}
+ # {w}"{" {return lbrace;}
+ # {w}"+" {return plus;}
+ # {w}">" {return greater;}
+ # {w}"," {return comma;}
+ $csslex['punc'] = '|~=|\|=|[\{\+>,:;]';
+
+ $this->csslex = $csslex;
+ }
+
+ function __get ($name) {
+ return isset($this->csslex[$name]) ? $this->csslex[$name] : null;
+ }
+}
diff --git a/plugins/system/t3/includes/jacssjanus/ja.cssjanus.php b/plugins/system/t3/includes/jacssjanus/ja.cssjanus.php
new file mode 100644
index 0000000..f28cf6e
--- /dev/null
+++ b/plugins/system/t3/includes/jacssjanus/ja.cssjanus.php
@@ -0,0 +1,595 @@
+)*?(\,|{))',
+ $csslex->nmchar, $patterns['token_lines'], $csslex->space);
+
+
+ # these two lookaheads are to test whether or not we are within a
+ # background: url(here) situation.
+ # ref: http://www.w3.org/tr/css21/syndata.html#uri
+ $patterns['valid_after_uri_chars'] = sprintf("[\'\"]?%s", $csslex->whitespace);
+ $patterns['lookahead_not_closing_paren'] = sprintf("(?!%s?%s\))", $csslex->url_chars,
+ $patterns['valid_after_uri_chars']);
+ $patterns['lookahead_for_closing_paren'] = sprintf("(?=%s?%s\))", $csslex->url_chars,
+ $patterns['valid_after_uri_chars']);
+
+ # compile a regex to swap left and right values in 4 part notations.
+ # we need to match negatives and decimal numeric values.
+ # the case of border-radius is extra complex, so we handle it separately below.
+ # ex. 'margin: .25em -2px 3px 0' becomes 'margin: .25em 0 3px -2px'.
+
+ $patterns['possibly_negative_quantity'] = sprintf('((?:-?%s)|(?:inherit|auto))', $csslex->quantity);
+ $patterns['possibly_negative_quantity_space'] = sprintf('%s%s%s', $patterns['possibly_negative_quantity'],
+ $csslex->space,
+ $csslex->whitespace);
+ $patterns['four_notation_quantity_re'] = sprintf('/%s%s%s%s/i',
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity']
+ );
+ $patterns['color'] = sprintf('(%s|%s)', $csslex->name, $csslex->hash);
+ $patterns['color_space'] = sprintf('%s%s', $patterns['color'], $csslex->space);
+ $patterns['four_notation_color_re'] = sprintf('/(-color%s:%s)%s%s%s(%s)/i',
+ $csslex->whitespace,
+ $csslex->whitespace,
+ $patterns['color_space'],
+ $patterns['color_space'],
+ $patterns['color_space'],
+ $patterns['color']
+ );
+
+ # border-radius is very different from usual 4 part notation: abcd should
+ # change to badc (while it would be adcb in normal 4 part notation), abc
+ # should change to babc, and ab should change to ba
+ $patterns['border_radius_re'] = sprintf('/((?:%s)?)border-radius(%s:%s)'
+ .'(?:%s)?(?:%s)?(?:%s)?(?:%s)'
+ .'(?:%s\/%s(?:%s)?(?:%s)?(?:%s)?(?:%s))?/i',$csslex->ident,
+ $csslex->whitespace,
+ $csslex->whitespace,
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity'],
+ $csslex->whitespace,
+ $csslex->whitespace,
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity_space'],
+ $patterns['possibly_negative_quantity']
+ );
+
+ # compile the cursor resize regexes
+ $patterns['cursor_east_re'] = '/' . $patterns['lookbehind_not_letter'] . '([ns]?)e-resize/';
+ $patterns['cursor_west_re'] = '/' . $patterns['lookbehind_not_letter'] . '([ns]?)w-resize/';
+
+ # matches the condition where we need to replace the horizontal component
+ # of a background-position value when expressed in horizontal percentage.
+ # had to make two regexes because in the case of position-x there is only
+ # one quantity, and otherwise we don't want to match and change cases with only
+ # one quantity.
+ $patterns['bg_horizontal_percentage_re'] = sprintf('/background(-position)?(%s:%s)'
+ .'([^%%]*?)(%s)%%'
+ .'(%s(?:%s|top|center|bottom))/',
+ $csslex->whitespace,
+ $csslex->whitespace,
+ $csslex->num,
+ $csslex->whitespace,
+ $patterns['possibly_negative_quantity']
+ );
+
+ $patterns['bg_horizontal_percentage_x_re'] = sprintf('/background-position-x(%s:%s)(%s)%%/', $csslex->whitespace,
+ $csslex->whitespace,
+ $csslex->num);
+
+ # non-percentage units used for css lengths
+ $patterns['length_unit'] = '(?:em|ex|px|cm|mm|in|pt|pc)';
+ # to make sure the lone 0 is not just starting a number (like "02") or a percentage like ("0 %");
+ $patterns['lookahead_end_of_zero'] = sprintf('(?![0-9]|%s%%)', $csslex->whitespace);
+ # a length with a unit specified. matches "0" too, as it's a length, not a percentage.
+ $patterns['length'] = sprintf('(?:-?%s(?:%s%s)|0+%s)', $csslex->num,
+ $csslex->whitespace,
+ $patterns['length_unit'],
+ $patterns['lookahead_end_of_zero']);
+
+ # zero length. used in the replacement functions.
+ $patterns['zero_length'] = sprintf('/(?:-?0+(?:%s%s)|0+%s)$/', $csslex->whitespace,
+ $patterns['length_unit'],
+ $patterns['lookahead_end_of_zero']);
+
+ # matches background, background-position, and background-position-x
+ # properties when using a css length for its horizontal positioning.
+ $patterns['bg_horizontal_length_re'] = sprintf('/background(-position)?(%s:%s)'
+ .'((?:.+?%s+)??)(%s)'
+ .'((?:%s+)(?:%s|top|center|bottom))/', $csslex->whitespace,
+ $csslex->whitespace,
+ $csslex->space,
+ $patterns['length'],
+ $csslex->space,
+ $patterns['possibly_negative_quantity']);
+
+ $patterns['bg_horizontal_length_x_re'] = sprintf('/background-position-x(%s:%s)(%s)/', $csslex->whitespace,
+ $csslex->whitespace,
+ $patterns['length']);
+
+ # matches the opening of a body selector.
+ $patterns['body_selector'] = sprintf('body%s{%s', $csslex->whitespace, $csslex->whitespace);
+
+ # matches anything up until the closing of a selector.
+ $patterns['chars_within_selector'] = '[^\}]*?';
+
+ # matches the direction property in a selector.
+ $patterns['direction_re'] = sprintf('direction%s:%s', $csslex->whitespace, $csslex->whitespace);
+
+ # these allow us to swap "ltr" with "rtl" and vice versa only within the
+ # body selector and on the same line.
+ $patterns['body_direction_ltr_re'] = sprintf('/(%s)(%s)(%s)(ltr)/i',
+ $patterns['body_selector'],
+ $patterns['chars_within_selector'],
+ $patterns['direction_re']
+ );
+ $patterns['body_direction_rtl_re'] = sprintf('/(%s)(%s)(%s)(rtl)/i',
+ $patterns['body_selector'],
+ $patterns['chars_within_selector'],
+ $patterns['direction_re']
+ );
+
+
+ # allows us to swap "direction:ltr" with "direction:rtl" and
+ # vice versa anywhere in a line.
+ $patterns['direction_ltr_re'] = sprintf('/%s(ltr)/', $patterns['direction_re']);
+ $patterns['direction_rtl_re'] = sprintf('/%s(rtl)/', $patterns['direction_re']);
+
+ # we want to be able to switch left with right and vice versa anywhere
+ # we encounter left/right strings, except inside the background:url(). the next
+ # two regexes are for that purpose. we have alternate in_url versions of the
+ # regexes compiled in case the user passes the flag that they do
+ # actually want to have left and right swapped inside of background:urls.
+ $patterns['left_re'] = sprintf('/%s((?:top|bottom)?)(%s)%s%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['left'],
+ $patterns['lookahead_not_closing_paren'],
+ $patterns['lookahead_not_open_brace']
+ );
+ $patterns['right_re'] = sprintf('/%s((?:top|bottom)?)(%s)%s%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['right'],
+ $patterns['lookahead_not_closing_paren'],
+ $patterns['lookahead_not_open_brace']);
+ $patterns['left_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['left'],
+ $patterns['lookahead_for_closing_paren']);
+ $patterns['right_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['right'],
+ $patterns['lookahead_for_closing_paren']);
+ $patterns['ltr_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['ltr'],
+ $patterns['lookahead_for_closing_paren']);
+ $patterns['rtl_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
+ $patterns['rtl'],
+ $patterns['lookahead_for_closing_paren']);
+
+ $patterns['comment_re'] = sprintf('/(%s)/i', $csslex->comment);
+
+ $patterns['noflip_token'] = '\@noflip';
+ # the noflip_token inside of a comment. for now, this requires that comments
+ # be in the input, which means users of a css compiler would have to run
+ # this script first if they want this functionality.
+ $patterns['noflip_annotation'] = sprintf('\/\*%s%s%s\*\/', $csslex->whitespace,
+ $patterns['noflip_token'],
+ $csslex->whitespace);
+
+ # after a noflip_annotation, and within a class selector, we want to be able
+ # to set aside a single rule not to be flipped. we can do this by matching
+ # our noflip annotation and then using a lookahead to make sure there is not
+ # an opening brace before the match.
+ $patterns['noflip_single_re'] = sprintf('/(%s%s[^;}]+;?)/i', $patterns['noflip_annotation'],
+ $patterns['lookahead_not_open_brace']);
+
+ # after a noflip_annotation, we want to grab anything up until the next } which
+ # means the entire following class block. this will prevent all of its
+ # declarations from being flipped.
+ $patterns['noflip_class_re'] = sprintf('/(%s%s})/i', $patterns['noflip_annotation'],
+ $patterns['chars_within_selector']);
+
+ # border-radis properties and their values
+ $patterns['border_radius_tokenizer_re'] = sprintf('/((?:%s)?border-radius%s:[^;}]+;?)/i', $csslex->ident,
+ $csslex->whitespace);
+ $patterns['gradient_re'] = sprintf('/%s[\.-]gradient%s\(/i', $csslex->ident, $csslex->whitespace);
+
+ }
+
+ /**
+ * Transform an LTR stylesheet to RTL
+ * @param $css String: stylesheet to transform
+ * @param $swapLtrRtlInURL Boolean: If true, swap 'ltr' and 'rtl' in URLs
+ * @param $swapLeftRightInURL Boolean: If true, swap 'left' and 'right' in URLs
+ * @return Transformed stylesheet
+ */
+ public static function transform( $css, $swapLtrRtlInURL = false, $swapLeftRightInURL = false ) {
+ self::buildPatterns();
+ // We wrap tokens in ` , not ~ like the original implementation does.
+ // This was done because ` is not a legal character in CSS and can only
+ // occur in URLs, where we escape it to %60 before inserting our tokens.
+ $css = str_replace( self::$patterns['token_delimiter'], '%60', $css );
+
+
+ // Tokenize single line rules with /* @noflip */
+ $noFlipSingle = new CSSJanus_Tokenizer( self::$patterns['noflip_single_re'], '`NOFLIP_SINGLE`' );
+ $css = $noFlipSingle->tokenize( $css );
+
+ // Tokenize class rules with /* @noflip */
+ $noFlipClass = new CSSJanus_Tokenizer( self::$patterns['noflip_class_re'], '`NOFLIP_CLASS`' );
+ $css = $noFlipClass->tokenize( $css );
+
+ // Tokenize comments
+ $comments = new CSSJanus_Tokenizer( self::$patterns['comment_re'], '`C`' );
+ $css = $comments->tokenize( $css );
+
+ # Tokenize gradients since we don't want to mirror the values inside
+ //$comments = new CSSJanus_Tokenizer( self::$patterns['comment_re']GradientMatcher(), '`GRADIENT`' );
+ //$css = $comments->tokenize( $css );
+
+ // LTR->RTL fixes start here
+ $css = self::FixBodyDirectionLtrAndRtl( $css );
+
+ if ( $swapLtrRtlInURL ) {
+ $css = self::fixLtrRtlInURL( $css );
+ }
+
+ if ( $swapLeftRightInURL ) {
+ $css = self::fixLeftRightInURL( $css );
+ }
+ $css = self::fixLeftAndRight( $css );
+ $css = self::fixCursorProperties( $css );
+
+ $css = self::fixBorderRadius( $css );
+ # Since FourPartNotation conflicts with BorderRadius, we tokenize border-radius properties here.
+ $border_radius_tokenizer = new CSSJanus_Tokenizer( self::$patterns['border_radius_tokenizer_re'], '`BORDER_RADIUS`' );
+ $css = $border_radius_tokenizer->tokenize( $css );
+
+ $css = self::fixFourPartNotation( $css );
+
+ $css = $border_radius_tokenizer->detokenize( $css );
+
+ $css = self::fixBackgroundPosition( $css );
+
+ // Detokenize stuff we tokenized before
+ $css = $comments->detokenize( $css );
+ $css = $noFlipClass->detokenize( $css );
+ $css = $noFlipSingle->detokenize( $css );
+
+ return $css;
+ }
+
+ /**
+ * Replaces ltr with rtl and vice versa ONLY in the body direction.
+ *
+ */
+ private static function FixBodyDirectionLtrAndRtl( $css ) {
+ $css = preg_replace( self::$patterns['body_direction_ltr_re'], '\1\2\3' . self::$patterns['tmp_token'], $css );
+ $css = preg_replace( self::$patterns['body_direction_rtl_re'], '\1\2\3' . self::$patterns['ltr'], $css );
+ $css = str_replace( self::$patterns['tmp_token'], self::$patterns['rtl'], $css );
+
+ return $css;
+ }
+
+ /**
+ * Flip rules like left: , padding-right: , etc.
+ */
+ private static function fixLeftAndRight( $css ) {
+ $css = preg_replace( self::$patterns['left_re'], '\1' . self::$patterns['tmp_token'], $css );
+ $css = preg_replace( self::$patterns['right_re'], '\1' . self::$patterns['left'], $css );
+ $css = str_replace( self::$patterns['tmp_token'], self::$patterns['right'], $css );
+
+ return $css;
+ }
+
+ /**
+ * Replace 'left' with 'right' and vice versa in background URLs
+ */
+ private static function fixleftrightinurl( $css ) {
+ $css = preg_replace( self::$patterns['left_in_url_re'], self::$patterns['tmp_token'], $css );
+ $css = preg_replace( self::$patterns['right_in_url_re'], self::$patterns['left'], $css );
+ $css = str_replace( self::$patterns['tmp_token'], self::$patterns['right'], $css );
+
+ return $css;
+ }
+
+ /**
+ * replace 'ltr' with 'rtl' and vice versa in background urls
+ */
+ private static function fixltrrtlinurl( $css ) {
+ $css = preg_replace( self::$patterns['ltr_in_url_re'], self::$patterns['tmp_token'], $css );
+ $css = preg_replace( self::$patterns['rtl_in_url_re'], self::$patterns['ltr'], $css );
+ $css = str_replace( self::$patterns['tmp_token'], self::$patterns['rtl'], $css );
+
+ return $css;
+ }
+
+ /**
+ * flip east and west in rules like cursor: nw-resize;
+ */
+ private static function fixcursorproperties( $css ) {
+ $css = preg_replace( self::$patterns['cursor_east_re'], '\1' . self::$patterns['tmp_token'], $css );
+ $css = preg_replace( self::$patterns['cursor_west_re'], '\1e-resize', $css );
+ $css = str_replace( self::$patterns['tmp_token'], 'w-resize', $css );
+
+ return $css;
+ }
+
+ /**
+ * Fixes border-radius and its browser-specific variants.
+ */
+ private static function fixBorderRadius( $css ) {
+//echo self::$patterns['border_radius_re']; die();
+ $css = preg_replace_callback(self::$patterns['border_radius_re'], array( 'self', 'reorderBorderRadius' ), $css );
+
+ return $css;
+ }
+
+ /**
+ * Fixes border-radius and its browser-specific variants.
+ */
+ private static function reorderBorderRadius( $matches ) {
+ $first_group = self::reorderBorderRadiusPart(array_slice ($matches, 3, 4));
+ $second_group = self::reorderBorderRadiusPart(array_slice ($matches, 7));
+ if ($second_group == '')
+ return sprintf('%sborder-radius%s%s', $matches[1], $matches[2], $first_group);
+ else
+ return sprintf('%sborder-radius%s%s / %s', $matches[1], $matches[2], $first_group, $second_group);
+ }
+
+ /**
+ * Fixes border-radius and its browser-specific variants.
+ */
+ private static function reorderBorderRadiusPart( $ps ) {
+ # Remove any piece which may be 'None'
+ $part = array();
+ foreach ($ps as $p) {
+ if ($p != '') $part[] = $p;
+ }
+
+ if (count($part) == 4) {
+ return sprintf('%s %s %s %s', $part[1], $part[0], $part[3], $part[2]);
+ } elseif (count($part) == 3) {
+ return sprintf('%s %s %s %s', $part[1], $part[0], $part[1], $part[2]);
+ } elseif (count($part) == 2) {
+ return sprintf('%s %s', $part[1], $part[0]);
+ } elseif (count($part) == 1) {
+ return $part[0];
+ } elseif (count($part) == 0) {
+ return '';
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Swap the second and fourth parts in four-part notation rules like
+ * padding: 1px 2px 3px 4px;
+ *
+ * Unlike the original implementation, this function doesn't suffer from
+ * the bug where whitespace is not preserved when flipping four-part rules
+ * and four-part color rules with multiple whitespace characters between
+ * colors are not recognized.
+ * See http://code.google.com/p/cssjanus/issues/detail?id=16
+ */
+ private static function fixFourPartNotation( $css ) {
+ $css = preg_replace( self::$patterns['four_notation_quantity_re'], '\1 \4 \3 \2', $css );
+ $css = preg_replace( self::$patterns['four_notation_color_re'], '\1\2 \5 \4 \3', $css );
+
+ return $css;
+ }
+
+ /**
+ * Flip horizontal background percentages.
+ */
+ private static function fixBackgroundPosition( $css ) {
+ $css = preg_replace_callback( self::$patterns['bg_horizontal_percentage_re'],
+ array( 'self', 'calculateNewBackgroundPosition' ), $css );
+ $css = preg_replace_callback( self::$patterns['bg_horizontal_percentage_x_re'],
+ array( 'self', 'calculateNewBackgroundPositionX' ), $css );
+ $css = preg_replace_callback( self::$patterns['bg_horizontal_length_re'],
+ array( 'self', 'calculateNewBackgroundLengthPosition' ), $css );
+ $css = preg_replace_callback( self::$patterns['bg_horizontal_length_x_re'],
+ array( 'self', 'calculateNewBackgroundLengthPositionX' ), $css );
+
+ return $css;
+ }
+
+ /**
+ * Callback for calculateNewBackgroundPosition()
+ */
+ private static function calculateNewBackgroundPosition( $matches ) {
+ # The flipped value is the offset from 100%
+ $new_x = 100-intval($matches[4]);
+
+ # Since m.group(1) may very well be None type and we need a string..
+ if ($matches[1]){
+ $position_string = $matches[1];
+ } else {
+ $position_string = '';
+ }
+ return sprintf('background%s%s%s%s%%%s', $position_string, $matches[2], $matches[3], $new_x, $matches[5]);
+ }
+
+ /**
+ * Callback for calculateNewBackgroundPosition()
+ */
+ private static function calculateNewBackgroundPositionX( $matches ) {
+ # The flipped value is the offset from 100%
+ $new_x = 100-intval($matches[2]);
+
+ return sprintf('background-position-x%s%s%%', $matches[1], $new_x);
+ }
+
+ /**
+ * Fixes horizontal background-position lengths.
+ * Return: A string with the horizontal background position set to 100%, if zero.
+ */
+ private static function calculateNewBackgroundLengthPosition( $matches ) {
+ # return original if error
+ if ($matches[4]) {
+ return $matches[0];
+ }
+
+ # Since m.group(1) may very well be None type and we need a string..
+ if ($matches[1]){
+ $position_string = $matches[1];
+ } else {
+ $position_string = '';
+ }
+ return sprintf('background%s%s%s100%%%s', $position_string, $matches[2], $matches[3], $matches[5]);
+
+ }
+
+ /**
+ * Fixes background-position-x lengths
+ * Return: A string with the background-position-x set to 100%, if zero.
+ */
+ private static function calculateNewBackgroundLengthPositionX( $matches ) {
+ # return original if error
+ if ($matches[2]) {
+ return $matches[0];
+ }
+
+ return sprintf('background-position-x%s100%%', $matches[1]);
+ }
+}
+
+
+
+
+/**
+ * Utility class used by CSSJanus that tokenizes and untokenizes things we want
+ * to protect from being janused.
+ * @author Roan Kattouw
+ */
+class CSSJanus_Tokenizer {
+ private $regex, $token;
+ private $originals;
+
+ /**
+ * Constructor
+ * @param $regex string Regular expression whose matches to replace by a token.
+ * @param $token string Token
+ */
+ public function __construct( $regex, $token ) {
+ $this->regex = $regex;
+ $this->token = $token;
+ $this->originals = array();
+ }
+
+ /**
+ * Replace all occurrences of $regex in $str with a token and remember
+ * the original strings.
+ * @param $str String to tokenize
+ * @return string Tokenized string
+ */
+ public function tokenize( $str ) {
+ return preg_replace_callback( $this->regex, array( $this, 'tokenizeCallback' ), $str );
+ }
+
+ private function tokenizeCallback( $matches ) {
+ $this->originals[] = $matches[0];
+ return $this->token;
+ }
+
+ /**
+ * Replace tokens with their originals. If multiple strings were tokenized, it's important they be
+ * detokenized in exactly the SAME ORDER.
+ * @param $str String: previously run through tokenize()
+ * @return string Original string
+ */
+ public function detokenize( $str ) {
+ // PHP has no function to replace only the first occurrence or to
+ // replace occurrences of the same string with different values,
+ // so we use preg_replace_callback() even though we don't really need a regex
+ return preg_replace_callback( '/' . preg_quote( $this->token, '/' ) . '/',
+ array( $this, 'detokenizeCallback' ), $str );
+ }
+
+ private function detokenizeCallback( $matches ) {
+ $retval = current( $this->originals );
+ next( $this->originals );
+
+ return $retval;
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/jacssjanus/test.php b/plugins/system/t3/includes/jacssjanus/test.php
new file mode 100644
index 0000000..6eef561
--- /dev/null
+++ b/plugins/system/t3/includes/jacssjanus/test.php
@@ -0,0 +1,522 @@
+
+
+pass' : 'fail ';
+?>
+
+
+ Input \n", $input) ?>
+ Expect \n", $expect) ?>
+ Output \n", $output) ?>
+ Result
+
+
+ span.right+span.left { float: left }');
+$shouldbe = array('div.left > span.right+span.left { float: right }');
+test();
+
+$testcase = array('.thisclass .left .myclass {background:#fff;}');
+$shouldbe = array('.thisclass .left .myclass {background:#fff;}');
+test();
+
+$testcase = array('.thisclass .left .myclass #myid {background:#fff;}');
+$shouldbe = array('.thisclass .left .myclass #myid {background:#fff;}');
+test();
+
+
+$test = 'testLongLineWithMultipleDefs';
+$testcase = array('body{direction:rtl;float:right}
+ .b2{direction:ltr;float:right}');
+$shouldbe = array('body{direction:ltr;float:left}
+ .b2{direction:ltr;float:left}');
+test();
+
+$test = 'testNoFlip';
+# """Tests the /* @noflip */ annotation on classnames."""
+$testcase = array('/* @noflip */ div { float: left; }');
+$shouldbe = array('/* @noflip */ div { float: left; }');
+test();
+
+$testcase = array('/* @noflip */ div, .notme { float: left; }');
+$shouldbe = array('/* @noflip */ div, .notme { float: left; }');
+test();
+
+$testcase = array('/* @noflip */ div { float: left; } div { float: left; }');
+$shouldbe = array('/* @noflip */ div { float: left; } div { float: right; }');
+test();
+
+$testcase = array('/* @noflip */\ndiv { float: left; }\ndiv { float: left; }');
+$shouldbe = array('/* @noflip */\ndiv { float: left; }\ndiv { float: right; }');
+test();
+
+# Test @noflip on single rules within classes
+$testcase = array('div { float: left; /* @noflip */ float: left; }');
+$shouldbe = array('div { float: right; /* @noflip */ float: left; }');
+test();
+
+$testcase = array('div\n{ float: left;\n/* @noflip */\n float: left;\n }');
+$shouldbe = array('div\n{ float: right;\n/* @noflip */\n float: left;\n }');
+test();
+
+$testcase = array('div\n{ float: left;\n/* @noflip */\n text-align: left\n }');
+$shouldbe = array('div\n{ float: right;\n/* @noflip */\n text-align: left\n }');
+test();
+
+$testcase = array('div\n{ /* @noflip */\ntext-align: left;\nfloat: left\n }');
+$shouldbe = array('div\n{ /* @noflip */\ntext-align: left;\nfloat: right\n }');
+test();
+
+$testcase = array('/* @noflip */div{float:left;text-align:left;}div{float:left}');
+$shouldbe = array('/* @noflip */div{float:left;text-align:left;}div{float:right}');
+test();
+
+$testcase = array('/* @noflip */','div{float:left;text-align:left;}a{foo:left}');
+$shouldbe = array('/* @noflip */','div{float:left;text-align:left;}a{foo:right}');
+test();
+
+$test = 'testBorderRadiusNotation';
+$testcase = array('border-radius: .25em 15px 0pt 0ex');
+$shouldbe = array('border-radius: 15px .25em 0ex 0pt');
+test();
+
+$testcase = array('border-radius: 10px 15px 0px');
+$shouldbe = array('border-radius: 15px 10px 15px 0px');
+test();
+
+$testcase = array('border-radius: 7px 8px');
+$shouldbe = array('border-radius: 8px 7px');
+test();
+
+$testcase = array('border-radius: 5px');
+$shouldbe = array('border-radius: 5px');
+test();
+
+$test = 'testGradientNotation';
+$testcase = array('background-image: -moz-linear-gradient(#326cc1, #234e8c)');
+$shouldbe = array('background-image: -moz-linear-gradient(#326cc1, #234e8c)');
+test();
+
+$testcase = array('background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, from(#666666), to(#ffffff))');
+$shouldbe = array('background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, from(#666666), to(#ffffff))');
+test();
diff --git a/plugins/system/t3/includes/joomla25/html/bootstrap.php b/plugins/system/t3/includes/joomla25/html/bootstrap.php
new file mode 100644
index 0000000..9811d92
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/html/bootstrap.php
@@ -0,0 +1,914 @@
+addScriptDeclaration(
+ "(function($){
+ $('#$selector').affix($options);
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap alerts
+ *
+ * @param string $selector Common class for the alerts
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function alert($selector = 'alert')
+ {
+ // Only load once
+ if (isset(static::$loaded[__METHOD__][$selector]))
+ {
+ return;
+ }
+
+ // Include Bootstrap framework
+ static::framework();
+
+ // Attach the alerts to the document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('.$selector').alert();
+ })(jQuery);"
+ );
+
+ static::$loaded[__METHOD__][$selector] = true;
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap buttons
+ *
+ * @param string $selector Common class for the buttons
+ *
+ * @return void
+ *
+ * @since 3.1
+ */
+ public static function button($selector = 'button')
+ {
+ // Only load once
+ if (isset(static::$loaded[__METHOD__][$selector]))
+ {
+ return;
+ }
+
+ // Include Bootstrap framework
+ static::framework();
+
+ // Attach the alerts to the document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('.$selector').button();
+ })(jQuery);"
+ );
+
+ static::$loaded[__METHOD__][$selector] = true;
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap carousels
+ *
+ * @param string $selector Common class for the carousels.
+ * @param array $params An array of options for the modal.
+ * Options for the modal can be:
+ * - interval number The amount of time to delay between automatically cycling an item.
+ * If false, carousel will not automatically cycle.
+ * - pause string Pauses the cycling of the carousel on mouseenter and resumes the cycling
+ * of the carousel on mouseleave.
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function carousel($selector = 'carousel', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded[__METHOD__][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['interval'] = isset($params['interval']) ? (int) $params['interval'] : 5000;
+ $opt['pause'] = isset($params['pause']) ? $params['pause'] : 'hover';
+
+ $options = self::getJSObject($opt);
+
+ // Attach the carousel to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('.$selector').carousel($options);
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap dropdowns
+ *
+ * @param string $selector Common class for the dropdowns
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function dropdown($selector = 'dropdown-toggle')
+ {
+ // Only load once
+ if (isset(static::$loaded[__METHOD__][$selector]))
+ {
+ return;
+ }
+
+ // Include Bootstrap framework
+ static::framework();
+
+ // Attach the dropdown to the document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('.$selector').dropdown();
+ })(jQuery);"
+ );
+
+ static::$loaded[__METHOD__][$selector] = true;
+
+ return;
+ }
+
+ /**
+ * Method to load the Bootstrap JavaScript framework into the document head
+ *
+ * If debugging mode is on an uncompressed version of Bootstrap is included for easier debugging.
+ *
+ * @param mixed $debug Is debugging mode on? [optional]
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function framework($debug = null)
+ {
+ return; // T3 already load framework
+ }
+
+ /**
+ * Add javascript support for Bootstrap modals
+ *
+ * @param string $selector The ID selector for the modal.
+ * @param array $params An array of options for the modal.
+ * Options for the modal can be:
+ * - backdrop boolean Includes a modal-backdrop element.
+ * - keyboard boolean Closes the modal when escape key is pressed.
+ * - show boolean Shows the modal when initialized.
+ * - remote string An optional remote URL to load
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function modal($selector = 'modal', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded[__METHOD__][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['backdrop'] = isset($params['backdrop']) ? (boolean) $params['backdrop'] : true;
+ $opt['keyboard'] = isset($params['keyboard']) ? (boolean) $params['keyboard'] : true;
+ $opt['show'] = isset($params['show']) ? (boolean) $params['show'] : true;
+ $opt['remote'] = isset($params['remote']) ? $params['remote'] : '';
+
+ $options = self::getJSObject($opt);
+
+ // Attach the modal to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('#$selector').modal($options);
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Method to render a Bootstrap modal
+ *
+ * @param string $selector The ID selector for the modal.
+ * @param array $params An array of options for the modal.
+ * @param string $footer Optional markup for the modal footer
+ *
+ * @return string HTML markup for a modal
+ *
+ * @since 3.0
+ */
+ public static function renderModal($selector = 'modal', $params = array(), $footer = '')
+ {
+ // Ensure the behavior is loaded
+ static::modal($selector, $params);
+
+ $html = "\n";
+ $html .= "\n";
+ $html .= "
\n";
+ $html .= "
\n";
+ $html .= "
\n";
+
+ $html .= "";
+
+ return $html;
+ }
+
+ /**
+ * Add javascript support for Bootstrap popovers
+ *
+ * Use element's Title as popover content
+ *
+ * @param string $selector Selector for the popover
+ * @param array $params An array of options for the popover.
+ * Options for the popover can be:
+ * animation boolean apply a css fade transition to the popover
+ * html boolean Insert HTML into the popover. If false, jQuery's text method will be used to insert
+ * content into the dom.
+ * placement string|function how to position the popover - top | bottom | left | right
+ * selector string If a selector is provided, popover objects will be delegated to the specified targets.
+ * trigger string how popover is triggered - hover | focus | manual
+ * title string|function default title value if `title` tag isn't present
+ * content string|function default content value if `data-content` attribute isn't present
+ * delay number|object delay showing and hiding the popover (ms) - does not apply to manual trigger type
+ * If a number is supplied, delay is applied to both hide/show
+ * Object structure is: delay: { show: 500, hide: 100 }
+ * container string|boolean Appends the popover to a specific element: { container: 'body' }
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function popover($selector = '.hasPopover', $params = array())
+ {
+ // Only load once
+ if (isset(static::$loaded[__METHOD__][$selector]))
+ {
+ return;
+ }
+
+ // Include Bootstrap framework
+ static::framework();
+
+ $opt['animation'] = isset($params['animation']) ? $params['animation'] : null;
+ $opt['html'] = isset($params['html']) ? $params['html'] : true;
+ $opt['placement'] = isset($params['placement']) ? $params['placement'] : null;
+ $opt['selector'] = isset($params['selector']) ? $params['selector'] : null;
+ $opt['title'] = isset($params['title']) ? $params['title'] : null;
+ $opt['trigger'] = isset($params['trigger']) ? $params['trigger'] : 'hover focus';
+ $opt['content'] = isset($params['content']) ? $params['content'] : null;
+ $opt['delay'] = isset($params['delay']) ? $params['delay'] : null;
+ $opt['container'] = isset($params['container']) ? $params['container'] : 'body';
+
+ $options = self::getJSObject($opt);
+
+ // Attach the popover to the document
+ JFactory::getDocument()->addScriptDeclaration(
+ "jQuery(document).ready(function()
+ {
+ jQuery('" . $selector . "').popover(" . $options . ");
+ });"
+ );
+
+ static::$loaded[__METHOD__][$selector] = true;
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap ScrollSpy
+ *
+ * @param string $selector The ID selector for the ScrollSpy element.
+ * @param array $params An array of options for the ScrollSpy.
+ * Options for the modal can be:
+ * - offset number Pixels to offset from top when calculating position of scroll.
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function scrollspy($selector = 'navbar', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded[__METHOD__][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['offset'] = isset($params['offset']) ? (int) $params['offset'] : 10;
+
+ $options = self::getJSObject($opt);
+
+ // Attach ScrollSpy to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('#$selector').scrollspy($options);
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap tooltips
+ *
+ * Add a title attribute to any element in the form
+ * title="title::text"
+ *
+ * @param string $selector The ID selector for the tooltip.
+ * @param array $params An array of options for the tooltip.
+ * Options for the tooltip can be:
+ * - animation boolean Apply a CSS fade transition to the tooltip
+ * - html boolean Insert HTML into the tooltip. If false, jQuery's text method will be used to insert
+ * content into the dom.
+ * - placement string|function How to position the tooltip - top | bottom | left | right
+ * - selector string If a selector is provided, tooltip objects will be delegated to the specified targets.
+ * - title string|function Default title value if `title` tag isn't present
+ * - trigger string How tooltip is triggered - hover | focus | manual
+ * - delay integer Delay showing and hiding the tooltip (ms) - does not apply to manual trigger type
+ * If a number is supplied, delay is applied to both hide/show
+ * Object structure is: delay: { show: 500, hide: 100 }
+ * - container string|boolean Appends the popover to a specific element: { container: 'body' }
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function tooltip($selector = '.hasTooltip', $params = array())
+ {
+ if (!isset(static::$loaded[__METHOD__][$selector]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['animation'] = isset($params['animation']) ? (boolean) $params['animation'] : null;
+ $opt['html'] = isset($params['html']) ? (boolean) $params['html'] : true;
+ $opt['placement'] = isset($params['placement']) ? (string) $params['placement'] : null;
+ $opt['selector'] = isset($params['selector']) ? (string) $params['selector'] : null;
+ $opt['title'] = isset($params['title']) ? (string) $params['title'] : null;
+ $opt['trigger'] = isset($params['trigger']) ? (string) $params['trigger'] : null;
+ $opt['delay'] = isset($params['delay']) ? (int) $params['delay'] : null;
+ $opt['container'] = isset($params['container']) ? $params['container'] : 'body';
+ $opt['template'] = isset($params['template']) ? (string) $params['template'] : null;
+ $onShow = isset($params['onShow']) ? (string) $params['onShow'] : null;
+ $onShown = isset($params['onShown']) ? (string) $params['onShown'] : null;
+ $onHide = isset($params['onHide']) ? (string) $params['onHide'] : null;
+ $onHidden = isset($params['onHidden']) ? (string) $params['onHidden'] : null;
+
+ $options = self::getJSObject($opt);
+
+ // Build the script.
+ $script = array();
+ $script[] = "jQuery(document).ready(function(){";
+ $script[] = "\tjQuery('" . $selector . "').tooltip(" . $options . ");";
+
+ if ($onShow)
+ {
+ $script[] = "\tjQuery('" . $selector . "').on('show.bs.tooltip', " . $onShow . ");";
+ }
+
+ if ($onShown)
+ {
+ $script[] = "\tjQuery('" . $selector . "').on('shown.bs.tooltip', " . $onShown . ");";
+ }
+
+ if ($onHide)
+ {
+ $script[] = "\tjQuery('" . $selector . "').on('hide.bs.tooltip', " . $onHide . ");";
+ }
+
+ if ($onHidden)
+ {
+ $script[] = "\tjQuery('" . $selector . "').on('hidden.bs.tooltip', " . $onHidden . ");";
+ }
+
+ $script[] = "});";
+
+ // Attach tooltips to document
+ JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
+
+ // Set static array
+ static::$loaded[__METHOD__][$selector] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap typeahead
+ *
+ * @param string $selector The selector for the typeahead element.
+ * @param array $params An array of options for the typeahead element.
+ * Options for the tooltip can be:
+ * - source array, function The data source to query against. May be an array of strings or a function.
+ * The function is passed two arguments, the query value in the input field and the
+ * process callback. The function may be used synchronously by returning the data
+ * source directly or asynchronously via the process callback's single argument.
+ * - items number The max number of items to display in the dropdown.
+ * - minLength number The minimum character length needed before triggering autocomplete suggestions
+ * - matcher function The method used to determine if a query matches an item. Accepts a single argument,
+ * the item against which to test the query. Access the current query with this.query.
+ * Return a boolean true if query is a match.
+ * - sorter function Method used to sort autocomplete results. Accepts a single argument items and has
+ * the scope of the typeahead instance. Reference the current query with this.query.
+ * - updater function The method used to return selected item. Accepts a single argument, the item and
+ * has the scope of the typeahead instance.
+ * - highlighter function Method used to highlight autocomplete results. Accepts a single argument item and
+ * has the scope of the typeahead instance. Should return html.
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function typeahead($selector = '.typeahead', $params = array())
+ {
+ if (!isset(static::$loaded[__METHOD__][$selector]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['source'] = isset($params['source']) ? $params['source'] : '[]';
+ $opt['items'] = isset($params['items']) ? (int) $params['items'] : 8;
+ $opt['minLength'] = isset($params['minLength']) ? (int) $params['minLength'] : 1;
+ $opt['matcher'] = isset($params['matcher']) ? (string) $params['matcher'] : null;
+ $opt['sorter'] = isset($params['sorter']) ? (string) $params['sorter'] : null;
+ $opt['updater'] = isset($params['updater']) ? (string) $params['updater'] : null;
+ $opt['highlighter'] = isset($params['highlighter']) ? (int) $params['highlighter'] : null;
+
+ $options = self::getJSObject($opt);
+
+ // Attach tooltips to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "jQuery(document).ready(function()
+ {
+ jQuery('" . $selector . "').typeahead(" . $options . ");
+ });"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$selector] = true;
+ }
+
+ return;
+ }
+
+ /**
+ * Add javascript support for Bootstrap accordians and insert the accordian
+ *
+ * @param string $selector The ID selector for the tooltip.
+ * @param array $params An array of options for the tooltip.
+ * Options for the tooltip can be:
+ * - parent selector If selector then all collapsible elements under the specified parent will be closed when this
+ * collapsible item is shown. (similar to traditional accordion behavior)
+ * - toggle boolean Toggles the collapsible element on invocation
+ * - active string Sets the active slide during load
+ *
+ * @return string HTML for the accordian
+ *
+ * @since 3.0
+ */
+ public static function startAccordion($selector = 'myAccordian', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded[__METHOD__][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['parent'] = isset($params['parent']) ? (boolean) $params['parent'] : false;
+ $opt['toggle'] = isset($params['toggle']) ? (boolean) $params['toggle'] : true;
+ $opt['active'] = isset($params['active']) ? (string) $params['active'] : '';
+
+ $options = self::getJSObject($opt);
+
+ // Attach accordion to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('#$selector').collapse($options);
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ static::$loaded[__METHOD__]['active'] = $opt['active'];
+ }
+
+ return '';
+ }
+
+ /**
+ * Close the current accordion
+ *
+ * @return string HTML to close the accordian
+ *
+ * @since 3.0
+ */
+ public static function endAccordion()
+ {
+ return '
';
+ }
+
+ /**
+ * Begins the display of a new accordion slide.
+ *
+ * @param string $selector Identifier of the accordion group.
+ * @param string $text Text to display.
+ * @param string $id Identifier of the slide.
+ * @param string $class Class of the accordion group.
+ *
+ * @return string HTML to add the slide
+ *
+ * @since 3.0
+ */
+ public static function addSlide($selector, $text, $id, $class = '')
+ {
+ $in = (static::$loaded['JHtmlBootstrap::startAccordion']['active'] == $id) ? ' in' : '';
+ $class = (!empty($class)) ? ' ' . $class : '';
+
+ $html = ''
+ . '
'
+ . '
'
+ . '
';
+
+ return $html;
+ }
+
+ /**
+ * Close the current slide
+ *
+ * @return string HTML to close the slide
+ *
+ * @since 3.0
+ */
+ public static function endSlide()
+ {
+ return '
';
+ }
+
+ /**
+ * Creates a tab pane
+ *
+ * @param string $selector The pane identifier.
+ * @param array $params The parameters for the pane
+ *
+ * @return string
+ *
+ * @since 3.1
+ */
+ public static function startTabSet($selector = 'myTab', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded[__METHOD__][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['active'] = (isset($params['active']) && ($params['active'])) ? (string) $params['active'] : '';
+
+ // Attach tabs to document
+ JFactory::getDocument()
+ ->addScriptDeclaration(JLayoutHelper::render('libraries.cms.html.bootstrap.starttabsetscript', array('selector' => $selector)));
+
+ // Set static array
+ static::$loaded[__METHOD__][$sig] = true;
+ static::$loaded[__METHOD__][$selector]['active'] = $opt['active'];
+ }
+
+ $html = JLayoutHelper::render('libraries.cms.html.bootstrap.starttabset', array('selector' => $selector));
+
+ return $html;
+ }
+
+ /**
+ * Close the current tab pane
+ *
+ * @return string HTML to close the pane
+ *
+ * @since 3.1
+ */
+ public static function endTabSet()
+ {
+ $html = JLayoutHelper::render('libraries.cms.html.bootstrap.endtabset');
+
+ return $html;
+ }
+
+ /**
+ * Begins the display of a new tab content panel.
+ *
+ * @param string $selector Identifier of the panel.
+ * @param string $id The ID of the div element
+ * @param string $title The title text for the new UL tab
+ *
+ * @return string HTML to start a new panel
+ *
+ * @since 3.1
+ */
+ public static function addTab($selector, $id, $title)
+ {
+ static $tabScriptLayout = null;
+ static $tabLayout = null;
+
+ $tabScriptLayout = is_null($tabScriptLayout) ? new JLayoutFile('libraries.cms.html.bootstrap.addtabscript') : $tabScriptLayout;
+ $tabLayout = is_null($tabLayout) ? new JLayoutFile('libraries.cms.html.bootstrap.addtab') : $tabLayout;
+
+ $active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';
+
+ // Inject tab into UL
+ JFactory::getDocument()
+ ->addScriptDeclaration($tabScriptLayout->render(array('selector' => $selector,'id' => $id, 'active' => $active, 'title' => $title)));
+
+ $html = $tabLayout->render(array('id' => $id, 'active' => $active));
+
+ return $html;
+ }
+
+ /**
+ * Close the current tab content panel
+ *
+ * @return string HTML to close the pane
+ *
+ * @since 3.1
+ */
+ public static function endTab()
+ {
+ $html = JLayoutHelper::render('libraries.cms.html.bootstrap.endtab');
+
+ return $html;
+ }
+
+ /**
+ * Creates a tab pane
+ *
+ * @param string $selector The pane identifier.
+ * @param array $params The parameters for the pane
+ *
+ * @return string
+ *
+ * @since 3.0
+ * @deprecated 4.0 Use JHtml::_('bootstrap.startTabSet') instead.
+ */
+ public static function startPane($selector = 'myTab', $params = array())
+ {
+ $sig = md5(serialize(array($selector, $params)));
+
+ if (!isset(static::$loaded['JHtmlBootstrap::startTabSet'][$sig]))
+ {
+ // Include Bootstrap framework
+ static::framework();
+
+ // Setup options object
+ $opt['active'] = isset($params['active']) ? (string) $params['active'] : '';
+
+ // Attach tooltips to document
+ JFactory::getDocument()->addScriptDeclaration(
+ "(function($){
+ $('#$selector a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ });
+ })(jQuery);"
+ );
+
+ // Set static array
+ static::$loaded['JHtmlBootstrap::startTabSet'][$sig] = true;
+ static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] = $opt['active'];
+ }
+
+ return '';
+ }
+
+ /**
+ * Close the current tab pane
+ *
+ * @return string HTML to close the pane
+ *
+ * @since 3.0
+ * @deprecated 4.0 Use JHtml::_('bootstrap.endTabSet') instead.
+ */
+ public static function endPane()
+ {
+ return '
';
+ }
+
+ /**
+ * Begins the display of a new tab content panel.
+ *
+ * @param string $selector Identifier of the panel.
+ * @param string $id The ID of the div element
+ *
+ * @return string HTML to start a new panel
+ *
+ * @since 3.0
+ * @deprecated 4.0 Use JHtml::_('bootstrap.addTab') instead.
+ */
+ public static function addPanel($selector, $id)
+ {
+ $active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';
+
+ return '';
+ }
+
+ /**
+ * Close the current tab content panel
+ *
+ * @return string HTML to close the pane
+ *
+ * @since 3.0
+ * @deprecated 4.0 Use JHtml::_('bootstrap.endTab') instead.
+ */
+ public static function endPanel()
+ {
+ return '
';
+ }
+
+ /**
+ * Loads CSS files needed by Bootstrap
+ *
+ * @param boolean $includeMainCss If true, main bootstrap.css files are loaded
+ * @param string $direction rtl or ltr direction. If empty, ltr is assumed
+ * @param array $attribs Optional array of attributes to be passed to JHtml::_('stylesheet')
+ *
+ * @return void
+ *
+ * @since 3.0
+ */
+ public static function loadCss($includeMainCss = true, $direction = 'ltr', $attribs = array())
+ {
+ // Load Bootstrap main CSS
+ if ($includeMainCss)
+ {
+ JHtml::_('stylesheet', 'jui/bootstrap.min.css', $attribs, true);
+ JHtml::_('stylesheet', 'jui/bootstrap-responsive.min.css', $attribs, true);
+ JHtml::_('stylesheet', 'jui/bootstrap-extended.css', $attribs, true);
+ }
+
+ // Load Bootstrap RTL CSS
+ if ($direction === 'rtl')
+ {
+ JHtml::_('stylesheet', 'jui/bootstrap-rtl.css', $attribs, true);
+ }
+ }
+
+ /**
+ * Internal method to get a JavaScript object notation string from an array
+ *
+ * @param array $array The array to convert to JavaScript object notation
+ *
+ * @return string JavaScript object notation representation of the array
+ *
+ * @since 3.0
+ */
+ public static function getJSObject(array $array = array())
+ {
+ $elements = array();
+
+ foreach ($array as $k => $v)
+ {
+ // Don't encode either of these types
+ if (is_null($v) || is_resource($v))
+ {
+ continue;
+ }
+
+ // Safely encode as a Javascript string
+ $key = json_encode((string) $k);
+
+ if (is_bool($v))
+ {
+ $elements[] = $key . ': ' . ($v ? 'true' : 'false');
+ }
+ elseif (is_numeric($v))
+ {
+ $elements[] = $key . ': ' . ($v + 0);
+ }
+ elseif (is_string($v))
+ {
+ if (strpos($v, '\\') === 0)
+ {
+ // Items such as functions and JSON objects are prefixed with \, strip the prefix and don't encode them
+ $elements[] = $key . ': ' . substr($v, 1);
+ }
+ else
+ {
+ // The safest way to insert a string
+ $elements[] = $key . ': ' . json_encode((string) $v);
+ }
+ }
+ else
+ {
+ $elements[] = $key . ': ' . static::getJSObject(is_object($v) ? get_object_vars($v) : $v);
+ }
+ }
+
+ return '{' . implode(',', $elements) . '}';
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/html/string.php b/plugins/system/t3/includes/joomla25/html/string.php
new file mode 100644
index 0000000..f43072f
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/html/string.php
@@ -0,0 +1,296 @@
+', '> ', $text);
+ $text = str_replace(array(' ', ' '), ' ', $text);
+ $text = JString::trim(preg_replace('#\s+#mui', ' ', $text));
+
+ // Strip the tags from the input and decode entities.
+ $text = strip_tags($text);
+ $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
+
+ // Remove remaining extra spaces.
+ $text = str_replace(' ', ' ', $text);
+ $text = JString::trim(preg_replace('#\s+#mui', ' ', $text));
+ }
+
+ // Whether or not allowing HTML, truncate the item text if it is too long.
+ if ($length > 0 && JString::strlen($text) > $length)
+ {
+ $tmp = trim(JString::substr($text, 0, $length));
+
+ if (substr($tmp, 0, 1) == '<' && strpos($tmp, '>') === false)
+ {
+ return '...';
+ }
+
+ // $noSplit true means that we do not allow splitting of words.
+ if ($noSplit)
+ {
+ // Find the position of the last space within the allowed length.
+ $offset = JString::strrpos($tmp, ' ');
+ $tmp = JString::substr($tmp, 0, $offset + 1);
+
+ // If there are no spaces and the string is longer than the maximum
+ // we need to just use the ellipsis. In that case we are done.
+ if ($offset === false && strlen($text) > $length)
+ {
+ return '...';
+ }
+
+ if (JString::strlen($tmp) > $length - 3)
+ {
+ $tmp = trim(JString::substr($tmp, 0, JString::strrpos($tmp, ' ')));
+ }
+ }
+
+ if ($allowHtml)
+ {
+ // Put all opened tags into an array
+ preg_match_all("#<([a-z][a-z0-9]*)\b.*?(?!/)>#i", $tmp, $result);
+ $openedTags = $result[1];
+
+ // Some tags self close so they do not need a separate close tag.
+ $openedTags = array_diff($openedTags, array("img", "hr", "br"));
+ $openedTags = array_values($openedTags);
+
+ // Put all closed tags into an array
+ preg_match_all("#([a-z]+)>#iU", $tmp, $result);
+ $closedTags = $result[1];
+
+ $numOpened = count($openedTags);
+
+ // All tags are closed so trim the text and finish.
+ if (count($closedTags) == $numOpened)
+ {
+ return trim($tmp) . '...';
+ }
+
+ // Closing tags need to be in the reverse order of opening tags.
+ $openedTags = array_reverse($openedTags);
+
+ // Close tags
+ for ($i = 0; $i < $numOpened; $i++)
+ {
+ if (!in_array($openedTags[$i], $closedTags))
+ {
+ $tmp .= "" . $openedTags[$i] . ">";
+ }
+ else
+ {
+ unset($closedTags[array_search($openedTags[$i], $closedTags)]);
+ }
+ }
+ }
+
+ if ($tmp === false || strlen($text) > strlen($tmp))
+ {
+ $text = trim($tmp) . '...';
+ }
+ }
+
+ // Clean up any internal spaces created by the processing.
+ $text = str_replace(' ', '', $text);
+ $text = str_replace(' ...', '...', $text);
+
+ return $text;
+ }
+
+ /**
+ * Method to extend the truncate method to more complex situations
+ *
+ * The goal is to get the proper length plain text string with as much of
+ * the html intact as possible with all tags properly closed.
+ *
+ * @param string $html The content of the introtext to be truncated
+ * @param integer $maxLength The maximum number of characters to render
+ * @param boolean $noSplit Don't split a word if that is where the cutoff occurs (default: true).
+ *
+ * @return string The truncated string. If the string is truncated an ellipsis
+ * (...) will be appended.
+ *
+ * @note If a maximum length of 3 or less is selected and the text has more than
+ * that number of characters an ellipsis will be displayed.
+ * This method will not create valid HTML from malformed HTML.
+ *
+ * @since 3.1
+ */
+ public static function truncateComplex($html, $maxLength = 0, $noSplit = true)
+ {
+ // Start with some basic rules.
+ $baseLength = strlen($html);
+
+ // If the original HTML string is shorter than the $maxLength do nothing and return that.
+ if ($baseLength <= $maxLength || $maxLength == 0)
+ {
+ return $html;
+ }
+
+ // Take care of short simple cases.
+ if ($maxLength <= 3 && substr($html, 0, 1) != '<' && strpos(substr($html, 0, $maxLength - 1), '<') === false && $baseLength > $maxLength)
+ {
+ return '...';
+ }
+
+ // Deal with maximum length of 1 where the string starts with a tag.
+ if ($maxLength == 1 && substr($html, 0, 1) == '<')
+ {
+ $endTagPos = strlen(strstr($html, '>', true));
+ $tag = substr($html, 1, $endTagPos);
+
+ $l = $endTagPos + 1;
+
+ if ($noSplit)
+ {
+ return substr($html, 0, $l) . '' . $tag . '...';
+ }
+
+ // TODO: $character doesn't seem to be used...
+ $character = substr(strip_tags($html), 0, 1);
+
+ return substr($html, 0, $l) . '' . $tag . '...';
+ }
+
+ // First get the truncated plain text string. This is the rendered text we want to end up with.
+ $ptString = JHtml::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = false);
+
+ // It's all HTML, just return it.
+ if (strlen($ptString) == 0)
+ {
+ return $html;
+ }
+
+ // If the plain text is shorter than the max length the variable will not end in ...
+ // In that case we use the whole string.
+ if (substr($ptString, -3) != '...')
+ {
+ return $html;
+ }
+
+ // Regular truncate gives us the ellipsis but we want to go back for text and tags.
+ if ($ptString == '...')
+ {
+ $stripped = substr(strip_tags($html), 0, $maxLength);
+ $ptString = JHtml::_('string.truncate', $stripped, $maxLength, $noSplit, $allowHtml = false);
+ }
+
+ // We need to trim the ellipsis that truncate adds.
+ $ptString = rtrim($ptString, '.');
+
+ // Now deal with more complex truncation.
+ while ($maxLength <= $baseLength)
+ {
+ // Get the truncated string assuming HTML is allowed.
+ $htmlString = JHtml::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = true);
+
+ if ($htmlString == '...' && strlen($ptString) + 3 > $maxLength)
+ {
+ return $htmlString;
+ }
+
+ $htmlString = rtrim($htmlString, '.');
+
+ // Now get the plain text from the HTML string and trim it.
+ $htmlStringToPtString = JHtml::_('string.truncate', $htmlString, $maxLength, $noSplit, $allowHtml = false);
+ $htmlStringToPtString = rtrim($htmlStringToPtString, '.');
+
+ // If the new plain text string matches the original plain text string we are done.
+ if ($ptString == $htmlStringToPtString)
+ {
+ return $htmlString . '...';
+ }
+
+ // Get the number of HTML tag characters in the first $maxLength characters
+ $diffLength = strlen($ptString) - strlen($htmlStringToPtString);
+
+ if ($diffLength <= 0)
+ {
+ return $htmlString . '...';
+ }
+
+ // Set new $maxlength that adjusts for the HTML tags
+ $maxLength += $diffLength;
+ }
+ }
+
+ /**
+ * Abridges text strings over the specified character limit. The
+ * behavior will insert an ellipsis into the text replacing a section
+ * of variable size to ensure the string does not exceed the defined
+ * maximum length. This method is UTF-8 safe.
+ *
+ * For example, it transforms "Really long title" to "Really...title".
+ *
+ * Note that this method does not scan for HTML tags so will potentially break them.
+ *
+ * @param string $text The text to abridge.
+ * @param integer $length The maximum length of the text (default is 50).
+ * @param integer $intro The maximum length of the intro text (default is 30).
+ *
+ * @return string The abridged text.
+ *
+ * @since 1.6
+ */
+ public static function abridge($text, $length = 50, $intro = 30)
+ {
+ // Abridge the item text if it is too long.
+ if (JString::strlen($text) > $length)
+ {
+ // Determine the remaining text length.
+ $remainder = $length - ($intro + 3);
+
+ // Extract the beginning and ending text sections.
+ $beg = JString::substr($text, 0, $intro);
+ $end = JString::substr($text, JString::strlen($text) - $remainder);
+
+ // Build the resulting string.
+ $text = $beg . '...' . $end;
+ }
+
+ return $text;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/layout/base.php b/plugins/system/t3/includes/joomla25/layout/base.php
new file mode 100644
index 0000000..dd7f319
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/layout/base.php
@@ -0,0 +1,162 @@
+options = $options;
+ }
+ // Received array
+ elseif (is_array($options))
+ {
+ $this->options = new JRegistry($options);
+ }
+ else
+ {
+ $this->options = new JRegistry;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the options
+ *
+ * @return JRegistry Object with the options
+ *
+ * @since 3.2
+ */
+ public function getOptions()
+ {
+ // Always return a JRegistry instance
+ if (!($this->options instanceof JRegistry))
+ {
+ $this->resetOptions();
+ }
+
+ return $this->options;
+ }
+
+ /**
+ * Function to empty all the options
+ *
+ * @return JLayoutBase Instance of $this to allow chaining.
+ *
+ * @since 3.2
+ */
+ public function resetOptions()
+ {
+ return $this->setOptions(null);
+ }
+
+ /**
+ * Method to escape output.
+ *
+ * @param string $output The output to escape.
+ *
+ * @return string The escaped output.
+ *
+ * @since 3.0
+ */
+ public function escape($output)
+ {
+ return htmlspecialchars($output, ENT_COMPAT, 'UTF-8');
+ }
+
+ /**
+ * Get the debug messages array
+ *
+ * @return array
+ *
+ * @since 3.2
+ */
+ public function getDebugMessages()
+ {
+ return $this->debugMessages;
+ }
+
+ /**
+ * Method to render the layout.
+ *
+ * @param object $displayData Object which properties are used inside the layout file to build displayed output
+ *
+ * @return string The necessary HTML to display the layout
+ *
+ * @since 3.0
+ */
+ public function render($displayData)
+ {
+ return '';
+ }
+
+ /**
+ * Render the list of debug messages
+ *
+ * @return string Output text/HTML code
+ *
+ * @since 3.2
+ */
+ public function renderDebugMessages()
+ {
+ return implode($this->debugMessages, "\n");
+ }
+
+ /**
+ * Add a debug message to the debug messages array
+ *
+ * @param string $message Message to save
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function addDebugMessage($message)
+ {
+ $this->debugMessages[] = $message;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/layout/file.php b/plugins/system/t3/includes/joomla25/layout/file.php
new file mode 100644
index 0000000..21b8b47
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/layout/file.php
@@ -0,0 +1,441 @@
+setOptions($options);
+
+ // Main properties
+ $this->setLayout($layoutId);
+ $this->basePath = $basePath;
+
+ // Init Enviroment
+ $this->setComponent($this->options->get('component', 'auto'));
+ $this->setClient($this->options->get('client', 'auto'));
+ }
+
+ /**
+ * Method to render the layout.
+ *
+ * @param object $displayData Object which properties are used inside the layout file to build displayed output
+ *
+ * @return string The necessary HTML to display the layout
+ *
+ * @since 3.0
+ */
+ public function render($displayData)
+ {
+ $layoutOutput = '';
+
+ // Check possible overrides, and build the full path to layout file
+ $path = $this->getPath();
+
+ if ($this->options->get('debug', false))
+ {
+ echo "" . $this->renderDebugMessages() . " ";
+ }
+
+ // If there exists such a layout file, include it and collect its output
+ if (!empty($path))
+ {
+ ob_start();
+ include $path;
+ $layoutOutput = ob_get_contents();
+ ob_end_clean();
+ }
+
+ return $layoutOutput;
+ }
+
+ /**
+ * Method to finds the full real file path, checking possible overrides
+ *
+ * @return string The full path to the layout file
+ *
+ * @since 3.0
+ */
+ protected function getPath()
+ {
+ JLoader::import('joomla.filesystem.path');
+
+ if (is_null($this->fullPath) && !empty($this->layoutId))
+ {
+ $this->addDebugMessage('Layout: ' . $this->layoutId);
+
+ // Refresh paths
+ $this->refreshIncludePaths();
+
+ $this->addDebugMessage('Include Paths: ' . print_r($this->includePaths, true));
+
+ $suffixes = $this->options->get('suffixes', array());
+
+ // Search for suffixed versions. Example: tags.j31.php
+ if (!empty($suffixes))
+ {
+ $this->addDebugMessage('Suffixes: ' . print_r($suffixes, true));
+
+ foreach ($suffixes as $suffix)
+ {
+ $rawPath = str_replace('.', '/', $this->layoutId) . '.' . $suffix . '.php';
+ $this->addDebugMessage('Searching layout for: ' . $rawPath);
+
+ if ($this->fullPath = JPath::find($this->includePaths, $rawPath))
+ {
+ $this->addDebugMessage('Found layout: ' . $this->fullPath);
+
+ return $this->fullPath;
+ }
+ }
+ }
+
+ // Standard version
+ $rawPath = str_replace('.', '/', $this->layoutId) . '.php';
+ $this->addDebugMessage('Searching layout for: ' . $rawPath);
+
+ $this->fullPath = JPath::find($this->includePaths, $rawPath);
+
+ if ($this->fullPath = JPath::find($this->includePaths, $rawPath))
+ {
+ $this->addDebugMessage('Found layout: ' . $this->fullPath);
+ }
+ }
+
+ return $this->fullPath;
+ }
+
+ /**
+ * Add one path to include in layout search. Proxy of addIncludePaths()
+ *
+ * @param string $path The path to search for layouts
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function addIncludePath($path)
+ {
+ $this->addIncludePaths($path);
+ }
+
+ /**
+ * Add one or more paths to include in layout search
+ *
+ * @param string $paths The path or array of paths to search for layouts
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function addIncludePaths($paths)
+ {
+ if (!empty($paths))
+ {
+ if (is_array($paths))
+ {
+ $this->includePaths = array_unique(array_merge($paths, $this->includePaths));
+ }
+ else
+ {
+ array_unshift($this->includePaths, $paths);
+ }
+ }
+ }
+
+ /**
+ * Remove one path from the layout search
+ *
+ * @param string $path The path to remove from the layout search
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function removeIncludePath($path)
+ {
+ $this->removeIncludePaths($path);
+ }
+
+ /**
+ * Remove one or more paths to exclude in layout search
+ *
+ * @param string $paths The path or array of paths to remove for the layout search
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function removeIncludePaths($paths)
+ {
+ if (!empty($paths))
+ {
+ $paths = (array) $paths;
+
+ $this->includePaths = array_diff($this->includePaths, $paths);
+ }
+ }
+
+ /**
+ * Validate that the active component is valid
+ *
+ * @param string $option URL Option of the component. Example: com_content
+ *
+ * @return boolean
+ *
+ * @since 3.2
+ */
+ protected function validComponent($option = null)
+ {
+ // By default we will validate the active component
+ $component = ($option !== null) ? $option : $this->options->get('component', null);
+
+ if (!empty($component))
+ {
+ // Valid option format
+ if (substr_count($component, 'com_'))
+ {
+ // Latest check: component exists and is enabled
+ return JComponentHelper::isEnabled($component);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Method to change the component where search for layouts
+ *
+ * @param string $option URL Option of the component. Example: com_content
+ *
+ * @return mixed Component option string | null for none
+ *
+ * @since 3.2
+ */
+ public function setComponent($option)
+ {
+ $component = null;
+
+ switch ((string) $option)
+ {
+ case 'none':
+ $component = null;
+ break;
+
+ case 'auto':
+ if (defined('JPATH_COMPONENT'))
+ {
+ $parts = explode('/', JPATH_COMPONENT);
+ $component = end($parts);
+ }
+
+ break;
+
+ default:
+ $component = $option;
+ break;
+ }
+
+ // Extra checks
+ if (!$this->validComponent($component))
+ {
+ $component = null;
+ }
+
+ $this->options->set('component', $component);
+
+ // Refresh include paths
+ $this->refreshIncludePaths();
+ }
+
+ /**
+ * Function to initialise the application client
+ *
+ * @param mixed $client Frontend: 'site' or 0 | Backend: 'admin' or 1
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function setClient($client)
+ {
+ // Force string conversion to avoid unexpected states
+ switch ((string) $client)
+ {
+ case 'site':
+ case '0':
+ $client = 0;
+ break;
+
+ case 'admin':
+ case '1':
+ $client = 1;
+ break;
+
+ default:
+ $client = (int) JFactory::getApplication()->isAdmin();
+ break;
+ }
+
+ $this->options->set('client', $client);
+
+ // Refresh include paths
+ $this->refreshIncludePaths();
+ }
+
+ /**
+ * Change the layout
+ *
+ * @param string $layoutId Layout to render
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function setLayout($layoutId)
+ {
+ $this->layoutId = $layoutId;
+ $this->fullPath = null;
+ }
+
+ /**
+ * Refresh the list of include paths
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ protected function refreshIncludePaths()
+ {
+ // Reset includePaths
+ $this->includePaths = array();
+
+ // (1 - lower priority) Frontend base layouts
+ $this->addIncludePaths(JPATH_ROOT . '/layouts');
+
+ // (2.1) - T3 base layout overridden
+ $this->addIncludePaths(T3_PATH . '/html/layouts');
+
+ // (2) Standard Joomla! layouts overriden
+ $this->addIncludePaths(JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts');
+
+ // (2.1) - user custom layout overridden
+ if (!defined('T3_LOCAL_DISABLED')) $this->addIncludePaths(T3_LOCAL_PATH . '/html/layouts');
+
+ // Component layouts & overrides if exist
+ $component = $this->options->get('component', null);
+
+ if (!empty($component))
+ {
+ // (3) Component path
+ if ($this->options->get('client') == 0)
+ {
+ $this->addIncludePaths(JPATH_SITE . '/components/' . $component . '/layouts');
+ }
+ else
+ {
+ $this->addIncludePaths(JPATH_ADMINISTRATOR . '/components/' . $component . '/layouts');
+ }
+
+ // (4) Component template overrides path
+ $this->addIncludePath(JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts/' . $component);
+ }
+
+ // (5 - highest priority) Received a custom high priority path ?
+ if (!is_null($this->basePath))
+ {
+ $this->addIncludePath(rtrim($this->basePath, DIRECTORY_SEPARATOR));
+ }
+ }
+
+ /**
+ * Change the debug mode
+ *
+ * @param boolean $debug Enable / Disable debug
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+ public function setDebug($debug)
+ {
+ $this->options->set('debug', (boolean) $debug);
+ }
+
+ /**
+ * Render a layout with the same include paths & options
+ *
+ * @param object $layoutId Object which properties are used inside the layout file to build displayed output
+ * @param mixed $displayData Data to be rendered
+ *
+ * @return string The necessary HTML to display the layout
+ *
+ * @since 3.2
+ */
+ public function sublayout($layoutId, $displayData)
+ {
+ // Sublayouts are searched in a subfolder with the name of the current layout
+ if (!empty($this->layoutId))
+ {
+ $layoutId = $this->layoutId . '.' . $layoutId;
+ }
+
+ $sublayout = new static($layoutId, $this->basePath, $this->options);
+ $sublayout->includePaths = $this->includePaths;
+
+ return $sublayout->render($displayData);
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/layout/helper.php b/plugins/system/t3/includes/joomla25/layout/helper.php
new file mode 100644
index 0000000..e8ea900
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/layout/helper.php
@@ -0,0 +1,54 @@
+render($displayData);
+
+ return $renderedLayout;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/layout/index.html b/plugins/system/t3/includes/joomla25/layout/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/layout/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/system/t3/includes/joomla25/layout/layout.php b/plugins/system/t3/includes/joomla25/layout/layout.php
new file mode 100644
index 0000000..499f7d0
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/layout/layout.php
@@ -0,0 +1,43 @@
+
+ * @link http://www.nonumber.nl
+ * @copyright Copyright © 2011 All Rights Reserved
+ * Brandon IT Consulting (http://www.metamodpro.com)
+ * NoNumber (http://www.nonumber.nl)
+ * JoomlArt (http://www.joomlart.com)
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
+ */
+
+/**
+ * BASE ON JOOMLA CORE FILE:
+ * /libraries/joomla/application/module/helper.php
+ */
+
+/**
+ * @package Joomla.Platform
+ * @subpackage Application
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or defined('JPATH_BASE') or die;
+
+jimport('joomla.application.component.helper');
+
+/**
+ * Module helper class
+ *
+ * @package Joomla.Platform
+ * @subpackage Application
+ * @since 11.1
+ */
+abstract class JModuleHelper
+{
+ /**
+ * Get module by name (real, eg 'Breadcrumbs' or folder, eg 'mod_breadcrumbs')
+ *
+ * @param string $name The name of the module
+ * @param string $title The title of the module, optional
+ *
+ * @return object The Module object
+ *
+ * @since 11.1
+ */
+ public static function &getModule($name, $title = null)
+ {
+ $result = null;
+ $modules =& JModuleHelper::_load();
+ $total = count($modules);
+
+ for ($i = 0; $i < $total; $i++)
+ {
+ // Match the name of the module
+ if ($modules[$i]->name == $name || $modules[$i]->module == $name)
+ {
+ // Match the title if we're looking for a specific instance of the module
+ if (!$title || $modules[$i]->title == $title)
+ {
+ // Found it
+ $result = &$modules[$i];
+ break; // Found it
+ }
+ }
+ }
+
+ // If we didn't find it, and the name is mod_something, create a dummy object
+ if (is_null($result) && substr($name, 0, 4) == 'mod_')
+ {
+ $result = new stdClass;
+ $result->id = 0;
+ $result->title = '';
+ $result->module = $name;
+ $result->position = '';
+ $result->content = '';
+ $result->showtitle = 0;
+ $result->control = '';
+ $result->params = '';
+ $result->user = 0;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get modules by position
+ *
+ * @param string $position The position of the module
+ *
+ * @return array An array of module objects
+ *
+ * @since 11.1
+ */
+ public static function &getModules($position)
+ {
+ $position = strtolower($position);
+ $result = array();
+
+ $modules =& JModuleHelper::_load();
+
+ $total = count($modules);
+ for ($i = 0; $i < $total; $i++)
+ {
+ if ($modules[$i]->position == $position)
+ {
+ $result[] = &$modules[$i];
+ }
+ }
+
+ if (count($result) == 0)
+ {
+ if (JRequest::getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
+ {
+ $result[0] = JModuleHelper::getModule('mod_' . $position);
+ $result[0]->title = $position;
+ $result[0]->content = $position;
+ $result[0]->position = $position;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Checks if a module is enabled
+ *
+ * @param string $module The module name
+ *
+ * @return boolean
+ *
+ * @since 11.1
+ */
+ public static function isEnabled($module)
+ {
+ $result = JModuleHelper::getModule($module);
+
+ return !is_null($result);
+ }
+
+ /**
+ * Render the module.
+ *
+ * @param object $module A module object.
+ * @param array $attribs An array of attributes for the module (probably from the XML).
+ *
+ * @return string The HTML content of the module output.
+ *
+ * @since 11.1
+ */
+ public static function renderModule($module, $attribs = array())
+ {
+ static $chrome;
+
+ if (constant('JDEBUG'))
+ {
+ JProfiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
+ }
+
+ $app = JFactory::getApplication();
+
+ // Record the scope.
+ $scope = $app->scope;
+
+ // Set scope to component name
+ $app->scope = $module->module;
+
+ // Get module parameters
+ $params = new JRegistry;
+ $params->loadString($module->params);
+
+ // Get module path
+ $module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module);
+ $path = JPATH_BASE . '/modules/' . $module->module . '/' . $module->module . '.php';
+
+ // Load the module
+ // $module->user is a check for 1.0 custom modules and is deprecated refactoring
+ if (empty($module->user) && file_exists($path))
+ {
+ $lang = JFactory::getLanguage();
+ // 1.5 or Core then 1.6 3PD
+ $lang->load($module->module, JPATH_BASE, null, false, false) ||
+ $lang->load($module->module, dirname($path), null, false, false) ||
+ $lang->load($module->module, JPATH_BASE, $lang->getDefault(), false, false) ||
+ $lang->load($module->module, dirname($path), $lang->getDefault(), false, false);
+
+ $content = '';
+ ob_start();
+ include $path;
+ $module->content = ob_get_contents() . $content;
+ ob_end_clean();
+ }
+
+ // Load the module chrome functions
+ if (!$chrome)
+ {
+ $chrome = array();
+ }
+
+ include_once JPATH_THEMES . '/system/html/modules.php';
+ $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/modules.php';
+
+ if (!isset($chrome[$chromePath]))
+ {
+ if (file_exists($chromePath))
+ {
+ include_once $chromePath;
+ }
+
+ $chrome[$chromePath] = true;
+ }
+
+ // Make sure a style is set
+ if (!isset($attribs['style']))
+ {
+ $attribs['style'] = 'none';
+ }
+
+ // Dynamically add outline style
+ if (JRequest::getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
+ {
+ $attribs['style'] .= ' outline';
+ }
+
+ // Do 3rd party stuff to manipulate module content
+ // onRenderModule is allowed to alter the $module, $attribs
+ // and may return a boolean.
+ // true=remove, any other value = keep.
+ // $result holds an array of booleans, 1 from each plugin.
+ // we ditch the module if any of them = true.
+ $result = $app->triggerEvent( 'onRenderModule', array( &$module, &$attribs ) );
+ if (!is_array($result)) {
+ $result = array($result);
+ }
+ if ( array_search( true, $result, true ) !== false )
+ {
+ return '';
+ }
+
+ foreach (explode(' ', $attribs['style']) as $style)
+ {
+ $chromeMethod = 'modChrome_' . $style;
+
+ // Apply chrome and render module
+ if (function_exists($chromeMethod))
+ {
+ $module->style = $attribs['style'];
+
+ ob_start();
+ $chromeMethod($module, $params, $attribs);
+ $module->content = ob_get_contents();
+ ob_end_clean();
+ }
+ }
+
+ //revert the scope
+ $app->scope = $scope;
+
+ if (constant('JDEBUG'))
+ {
+ JProfiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')');
+ }
+
+ return $module->content;
+ }
+
+ /**
+ * Get the path to a layout for a module
+ *
+ * @param string $module The name of the module
+ * @param string $layout The name of the module layout. If alternative layout, in the form template:filename.
+ *
+ * @return string The path to the module layout
+ *
+ * @since 11.1
+ */
+ public static function getLayoutPath($module, $layout = 'default')
+ {
+ $template = JFactory::getApplication()->getTemplate();
+ $defaultLayout = $layout;
+
+ if (strpos($layout, ':') !== false)
+ {
+ // Get the template and file name from the string
+ $temp = explode(':', $layout);
+ $template = ($temp[0] == '_') ? $template : $temp[0];
+ $layout = $temp[1];
+ $defaultLayout = ($temp[1]) ? $temp[1] : 'default';
+ }
+
+ // Build the template and base path for the layout
+ $tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
+ $bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
+ $dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';
+
+ // Do 3rd party stuff to detect layout path for the module
+ // onGetLayoutPath should return the path to the $layout of $module or false
+ // $results holds an array of results returned from plugins, 1 from each plugin.
+ // if a path to the $layout is found and it is a file, return that path
+ $app = JFactory::getApplication();
+ $result = $app->triggerEvent( 'onGetLayoutPath', array( $module, $layout ) );
+ if (is_array($result))
+ {
+ foreach ($result as $path)
+ {
+ if ($path !== false && is_file ($path))
+ {
+ return $path;
+ }
+ }
+ }
+
+ // If the template has a layout override use it
+ if (file_exists($tPath))
+ {
+ return $tPath;
+ }
+ elseif (file_exists($bPath))
+ {
+ return $bPath;
+ }
+ else
+ {
+ return $dPath;
+ }
+ }
+
+ /**
+ * Load published modules.
+ *
+ * @return array
+ *
+ * @since 11.1
+ */
+ protected static function &_load()
+ {
+ static $clean;
+
+ if (isset($clean))
+ {
+ return $clean;
+ }
+
+ $Itemid = JRequest::getInt('Itemid');
+ $app = JFactory::getApplication();
+ $user = JFactory::getUser();
+ $groups = implode(',', $user->getAuthorisedViewLevels());
+ $lang = JFactory::getLanguage()->getTag();
+ $clientId = (int) $app->getClientId();
+
+ /*
+ $cache = JFactory::getCache('com_modules', '');
+ $cacheid = md5(serialize(array($Itemid, $groups, $clientId, $lang)));
+
+ if (!($clean = $cache->get($cacheid)))
+ {
+ */
+ $db = JFactory::getDbo();
+
+ $query = new stdClass;
+ $query->select = array();
+ $query->from = array();
+ $query->join = array();
+ $query->where = array();
+ $query->order = array();
+
+ $query->select[] = 'm.published, m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params, mm.menuid';
+ $query->from[] = '#__modules AS m';
+ $query->join[] = '#__modules_menu AS mm ON mm.moduleid = m.id';
+ $query->where[] = 'm.published = 1';
+
+ $query->join[] = '#__extensions AS e ON e.element = m.module AND e.client_id = m.client_id';
+ $query->where[] = 'e.enabled = 1';
+
+ $date = JFactory::getDate();
+ $now = $date->toSql();
+ $nullDate = $db->getNullDate();
+ $query->where[] = '(m.publish_up = ' . $db->q($nullDate) . ' OR m.publish_up <= ' . $db->q($now) . ')';
+ $query->where[] = '(m.publish_down = ' . $db->q($nullDate) . ' OR m.publish_down >= ' . $db->q($now) . ')';
+
+ $query->where[] = 'm.access IN ('.$groups.')';
+ $query->where[] = 'm.client_id = ' . $clientId;
+ $query->where[] = '(mm.menuid = ' . (int) $Itemid . ' OR mm.menuid <= 0)';
+
+ // Filter by language
+ if ($app->isSite() && $app->getLanguageFilter())
+ {
+ $query->where[] = 'm.language IN (' . $db->q($lang) . ',' . $db->q('*') . ')';
+ }
+
+ $query->order[] = 'm.position, m.ordering';
+
+ // Do 3rd party stuff to change query
+ $app->triggerEvent( 'onCreateModuleQuery', array( &$query ) );
+
+ $q = $db->getQuery(true);
+ // convert array object to query object
+ foreach ( $query as $type => $strings )
+ {
+ foreach ( $strings as $string )
+ {
+ if ( $type == 'join' )
+ {
+ $q->{$type}( 'LEFT', $string );
+ }
+ else
+ {
+ $q->{$type}( $string );
+ }
+ }
+ }
+
+ // Set the query
+ $db->setQuery($q);
+ $modules = $db->loadObjectList();
+ $clean = array();
+
+ if ($db->getErrorNum())
+ {
+ JError::raiseWarning(500, JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $db->getErrorMsg()));
+ return $clean;
+ }
+
+ // Apply negative selections and eliminate duplicates
+ $negId = $Itemid ? -(int) $Itemid : false;
+ $dupes = array();
+ for ($i = 0, $n = count($modules); $i < $n; $i++)
+ {
+ $module = &$modules[$i];
+
+ // The module is excluded if there is an explicit prohibition
+ $negHit = ($negId === (int) $module->menuid);
+
+ if (isset($dupes[$module->id]))
+ {
+ // If this item has been excluded, keep the duplicate flag set,
+ // but remove any item from the cleaned array.
+ if ($negHit)
+ {
+ unset($clean[$module->id]);
+ }
+ continue;
+ }
+
+ $dupes[$module->id] = true;
+
+ // Only accept modules without explicit exclusions.
+ if (!$negHit)
+ {
+ // Determine if this is a 1.0 style custom module (no mod_ prefix)
+ // This should be eliminated when the class is refactored.
+ // $module->user is deprecated.
+ $file = $module->module;
+ $custom = substr($file, 0, 4) == 'mod_' ? 0 : 1;
+ $module->user = $custom;
+ // 1.0 style custom module name is given by the title field, otherwise strip off "mod_"
+ $module->name = $custom ? $module->module : substr($file, 4);
+ $module->style = null;
+ $module->position = strtolower($module->position);
+ $clean[$module->id] = $module;
+ }
+ }
+
+ unset($dupes);
+
+ // Do 3rd party stuff to manipulate module array.
+ // Any plugins using this architecture may make alterations to the referenced $modules array.
+ // To remove items you can do unset($modules[n]) or $modules[n]->published = false.
+
+ // "onPrepareModuleList" may alter or add $modules, and does not need to return anything.
+ // This should be used for module addition/deletion that the user would expect to happen at an
+ // early stage.
+ $app->triggerEvent( 'onPrepareModuleList', array( &$clean ) );
+
+ // "onAlterModuleList" may alter or add $modules, and does not need to return anything.
+ $app->triggerEvent( 'onAlterModuleList', array( &$clean ) );
+
+ // "onPostProcessModuleList" allows a plugin to perform actions like parameter changes
+ // on the completed list of modules and is guaranteed to occur *after*
+ // the earlier plugins.
+ $app->triggerEvent( 'onPostProcessModuleList', array( &$clean ) );
+
+ // Remove any that were marked as disabled during the preceding steps
+ foreach ( $clean as $id => $module )
+ {
+ if ( !isset( $module->published ) || $module->published == 0 )
+ {
+ unset( $clean[$id] );
+ }
+ }
+
+
+ // Return to simple indexing that matches the query order.
+ $clean = array_values($clean);
+
+ /*
+ $cache->store($clean, $cacheid);
+ }
+ */
+
+ return $clean;
+ }
+
+ /**
+ * Module cache helper
+ *
+ * Caching modes:
+ * To be set in XML:
+ * 'static' One cache file for all pages with the same module parameters
+ * 'oldstatic' 1.5 definition of module caching, one cache file for all pages
+ * with the same module id and user aid,
+ * 'itemid' Changes on itemid change, to be called from inside the module:
+ * 'safeuri' Id created from $cacheparams->modeparams array,
+ * 'id' Module sets own cache id's
+ *
+ * @param object $module Module object
+ * @param object $moduleparams Module parameters
+ * @param object $cacheparams Module cache parameters - id or url parameters, depending on the module cache mode
+ *
+ * @return string
+ *
+ * @since 11.1
+ *
+ * @link JFilterInput::clean()
+ */
+ public static function moduleCache($module, $moduleparams, $cacheparams)
+ {
+ if (!isset($cacheparams->modeparams))
+ {
+ $cacheparams->modeparams = null;
+ }
+
+ // Add module ID to fix problem of cache for modules with the same type
+ if ($cacheparams->modeparams && is_string($cacheparams->modeparams)) {
+ $cacheparams->modeparams .= ":".$module->id;
+ }
+
+ if (!isset($cacheparams->cachegroup))
+ {
+ $cacheparams->cachegroup = $module->module;
+ }
+
+ $user = JFactory::getUser();
+ $cache = JFactory::getCache($cacheparams->cachegroup, 'callback');
+ $conf = JFactory::getConfig();
+
+ // Turn cache off for internal callers if parameters are set to off and for all logged in users
+ if ($moduleparams->get('owncache', null) === '0' || $conf->get('caching') == 0 || $user->get('id'))
+ {
+ $cache->setCaching(false);
+ }
+
+ // module cache is set in seconds, global cache in minutes, setLifeTime works in minutes
+ $cache->setLifeTime($moduleparams->get('cache_time', $conf->get('cachetime') * 60) / 60);
+
+ $wrkaroundoptions = array('nopathway' => 1, 'nohead' => 0, 'nomodules' => 1, 'modulemode' => 1, 'mergehead' => 1);
+
+ $wrkarounds = true;
+ $view_levels = md5(serialize($user->getAuthorisedViewLevels()));
+
+ switch ($cacheparams->cachemode)
+ {
+ case 'id':
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $cacheparams->modeparams,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'safeuri':
+ $secureid = null;
+ if (is_array($cacheparams->modeparams))
+ {
+ $uri = JRequest::get();
+ $safeuri = new stdClass;
+ foreach ($cacheparams->modeparams as $key => $value)
+ {
+ // Use int filter for id/catid to clean out spamy slugs
+ if (isset($uri[$key]))
+ {
+ $safeuri->$key = JRequest::_cleanVar($uri[$key], 0, $value);
+ }
+ }
+ }
+ $secureid = md5(serialize(array($safeuri, $cacheparams->method, $moduleparams)));
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels . $secureid,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'static':
+ $ret = $cache->get(
+ array($cacheparams->class,
+ $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->module . md5(serialize($cacheparams->methodparams)),
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'oldstatic': // provided for backward compatibility, not really usefull
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'itemid':
+ default:
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels . JRequest::getVar('Itemid', null, 'default', 'INT'),
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+ }
+
+ return $ret;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/pagination.php b/plugins/system/t3/includes/joomla25/pagination.php
new file mode 100644
index 0000000..cae6602
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/pagination.php
@@ -0,0 +1,757 @@
+total = (int) $total;
+ $this->limitstart = (int) max($limitstart, 0);
+ $this->limit = (int) max($limit, 0);
+ $this->prefix = $prefix;
+
+ if ($this->limit > $this->total)
+ {
+ $this->limitstart = 0;
+ }
+
+ if (!$this->limit)
+ {
+ $this->limit = $total;
+ $this->limitstart = 0;
+ }
+
+ /*
+ * If limitstart is greater than total (i.e. we are asked to display records that don't exist)
+ * then set limitstart to display the last natural page of results
+ */
+ if ($this->limitstart > $this->total - $this->limit)
+ {
+ $this->limitstart = max(0, (int) (ceil($this->total / $this->limit) - 1) * $this->limit);
+ }
+
+ // Set the total pages and current page values.
+ if ($this->limit > 0)
+ {
+ $this->set('pages.total', ceil($this->total / $this->limit));
+ $this->set('pages.current', ceil(($this->limitstart + 1) / $this->limit));
+ }
+
+ // Set the pagination iteration loop values.
+ $displayedPages = 10;
+ $this->set('pages.start', $this->get('pages.current') - ($displayedPages / 2));
+ if ($this->get('pages.start') < 1)
+ {
+ $this->set('pages.start', 1);
+ }
+ if (($this->get('pages.start') + $displayedPages) > $this->get('pages.total'))
+ {
+ $this->set('pages.stop', $this->get('pages.total'));
+ if ($this->get('pages.total') < $displayedPages)
+ {
+ $this->set('pages.start', 1);
+ }
+ else
+ {
+ $this->set('pages.start', $this->get('pages.total') - $displayedPages + 1);
+ }
+ }
+ else
+ {
+ $this->set('pages.stop', ($this->get('pages.start') + $displayedPages - 1));
+ }
+
+ // If we are viewing all records set the view all flag to true.
+ if ($limit == 0)
+ {
+ $this->_viewall = true;
+ }
+ }
+
+ /**
+ * Method to set an additional URL parameter to be added to all pagination class generated
+ * links.
+ *
+ * @param string $key The name of the URL parameter for which to set a value.
+ * @param mixed $value The value to set for the URL parameter.
+ *
+ * @return mixed The old value for the parameter.
+ *
+ * @since 11.1
+ */
+ public function setAdditionalUrlParam($key, $value)
+ {
+ // Get the old value to return and set the new one for the URL parameter.
+ $result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;
+
+ // If the passed parameter value is null unset the parameter, otherwise set it to the given value.
+ if ($value === null)
+ {
+ unset($this->_additionalUrlParams[$key]);
+ }
+ else
+ {
+ $this->_additionalUrlParams[$key] = $value;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Method to get an additional URL parameter (if it exists) to be added to
+ * all pagination class generated links.
+ *
+ * @param string $key The name of the URL parameter for which to get the value.
+ *
+ * @return mixed The value if it exists or null if it does not.
+ *
+ * @since 11.1
+ */
+ public function getAdditionalUrlParam($key)
+ {
+ $result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;
+
+ return $result;
+ }
+
+ /**
+ * Return the rationalised offset for a row with a given index.
+ *
+ * @param integer $index The row index
+ *
+ * @return integer Rationalised offset for a row with a given index.
+ *
+ * @since 11.1
+ */
+ public function getRowOffset($index)
+ {
+ return $index + 1 + $this->limitstart;
+ }
+
+ /**
+ * Return the pagination data object, only creating it if it doesn't already exist.
+ *
+ * @return object Pagination data object.
+ *
+ * @since 11.1
+ */
+ public function getData()
+ {
+ static $data;
+ if (!is_object($data))
+ {
+ $data = $this->_buildDataObject();
+ }
+ return $data;
+ }
+
+ /**
+ * Create and return the pagination pages counter string, ie. Page 2 of 4.
+ *
+ * @return string Pagination pages counter string.
+ *
+ * @since 11.1
+ */
+ public function getPagesCounter()
+ {
+ // Initialise variables.
+ $html = null;
+ if ($this->get('pages.total') > 1)
+ {
+ $html .= JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $this->get('pages.current'), $this->get('pages.total'));
+ }
+ return $html;
+ }
+
+ /**
+ * Create and return the pagination result set counter string, e.g. Results 1-10 of 42
+ *
+ * @return string Pagination result set counter string.
+ *
+ * @since 11.1
+ */
+ public function getResultsCounter()
+ {
+ // Initialise variables.
+ $html = null;
+ $fromResult = $this->limitstart + 1;
+
+ // If the limit is reached before the end of the list.
+ if ($this->limitstart + $this->limit < $this->total)
+ {
+ $toResult = $this->limitstart + $this->limit;
+ }
+ else
+ {
+ $toResult = $this->total;
+ }
+
+ // If there are results found.
+ if ($this->total > 0)
+ {
+ $msg = JText::sprintf('JLIB_HTML_RESULTS_OF', $fromResult, $toResult, $this->total);
+ $html .= "\n" . $msg;
+ }
+ else
+ {
+ $html .= "\n" . JText::_('JLIB_HTML_NO_RECORDS_FOUND');
+ }
+
+ return $html;
+ }
+
+ /**
+ * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
+ *
+ * @return string Pagination page list string.
+ *
+ * @since 11.1
+ */
+ public function getPagesLinks()
+ {
+ $app = JFactory::getApplication();
+
+ // Build the page navigation list.
+ $data = $this->_buildDataObject();
+
+ $list = array();
+ $list['prefix'] = $this->prefix;
+
+ $itemOverride = false;
+ $listOverride = false;
+
+ // T3: detect if chrome pagination.php in template or in plugin
+ $chromePath = T3Path::getPath ('html/pagination.php');
+ // $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
+ if (file_exists($chromePath))
+ {
+ include_once $chromePath;
+ if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive'))
+ {
+ $itemOverride = true;
+ }
+ if (function_exists('pagination_list_render'))
+ {
+ $listOverride = true;
+ }
+ }
+
+ // Build the select list
+ if ($data->all->base !== null)
+ {
+ $list['all']['active'] = true;
+ $list['all']['data'] = ($itemOverride) ? pagination_item_active($data->all) : $this->_item_active($data->all);
+ }
+ else
+ {
+ $list['all']['active'] = false;
+ $list['all']['data'] = ($itemOverride) ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
+ }
+
+ if ($data->start->base !== null)
+ {
+ $list['start']['active'] = true;
+ $list['start']['data'] = ($itemOverride) ? pagination_item_active($data->start) : $this->_item_active($data->start);
+ }
+ else
+ {
+ $list['start']['active'] = false;
+ $list['start']['data'] = ($itemOverride) ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
+ }
+ if ($data->previous->base !== null)
+ {
+ $list['previous']['active'] = true;
+ $list['previous']['data'] = ($itemOverride) ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
+ }
+ else
+ {
+ $list['previous']['active'] = false;
+ $list['previous']['data'] = ($itemOverride) ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
+ }
+
+ $list['pages'] = array(); //make sure it exists
+ foreach ($data->pages as $i => $page)
+ {
+ if ($page->base !== null)
+ {
+ $list['pages'][$i]['active'] = true;
+ $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_active($page) : $this->_item_active($page);
+ }
+ else
+ {
+ $list['pages'][$i]['active'] = false;
+ $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_inactive($page) : $this->_item_inactive($page);
+ }
+ }
+
+ if ($data->next->base !== null)
+ {
+ $list['next']['active'] = true;
+ $list['next']['data'] = ($itemOverride) ? pagination_item_active($data->next) : $this->_item_active($data->next);
+ }
+ else
+ {
+ $list['next']['active'] = false;
+ $list['next']['data'] = ($itemOverride) ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
+ }
+
+ if ($data->end->base !== null)
+ {
+ $list['end']['active'] = true;
+ $list['end']['data'] = ($itemOverride) ? pagination_item_active($data->end) : $this->_item_active($data->end);
+ }
+ else
+ {
+ $list['end']['active'] = false;
+ $list['end']['data'] = ($itemOverride) ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
+ }
+
+ if ($this->total > $this->limit)
+ {
+ return ($listOverride) ? pagination_list_render($list) : $this->_list_render($list);
+ }
+ else
+ {
+ return '';
+ }
+ }
+
+ /**
+ * Return the pagination footer.
+ *
+ * @return string Pagination footer.
+ *
+ * @since 11.1
+ */
+ public function getListFooter()
+ {
+ $app = JFactory::getApplication();
+
+ $list = array();
+ $list['prefix'] = $this->prefix;
+ $list['limit'] = $this->limit;
+ $list['limitstart'] = $this->limitstart;
+ $list['total'] = $this->total;
+ $list['limitfield'] = $this->getLimitBox();
+ $list['pagescounter'] = $this->getPagesCounter();
+ $list['pageslinks'] = $this->getPagesLinks();
+
+ // T3: detect if chrome pagination.php in template or in plugin
+ $chromePath = T3Path::getPath ('html/pagination.php');
+ // $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
+ if (file_exists($chromePath))
+ {
+ include_once $chromePath;
+ if (function_exists('pagination_list_footer'))
+ {
+ return pagination_list_footer($list);
+ }
+ }
+ return $this->_list_footer($list);
+ }
+
+ /**
+ * Creates a dropdown box for selecting how many records to show per page.
+ *
+ * @return string The HTML for the limit # input box.
+ *
+ * @since 11.1
+ */
+ public function getLimitBox()
+ {
+ $app = JFactory::getApplication();
+
+ // Initialise variables.
+ $limits = array();
+
+ // Make the option list.
+ for ($i = 5; $i <= 30; $i += 5)
+ {
+ $limits[] = JHtml::_('select.option', "$i");
+ }
+ $limits[] = JHtml::_('select.option', '50', JText::_('J50'));
+ $limits[] = JHtml::_('select.option', '100', JText::_('J100'));
+ $limits[] = JHtml::_('select.option', '0', JText::_('JALL'));
+
+ $selected = $this->_viewall ? 0 : $this->limit;
+
+ // Build the select list.
+ if ($app->isAdmin())
+ {
+ $html = JHtml::_(
+ 'select.genericlist',
+ $limits,
+ $this->prefix . 'limit',
+ 'class="inputbox" size="1" onchange="Joomla.submitform();"',
+ 'value',
+ 'text',
+ $selected
+ );
+ }
+ else
+ {
+ $html = JHtml::_(
+ 'select.genericlist',
+ $limits,
+ $this->prefix . 'limit',
+ 'class="inputbox" size="1" onchange="this.form.submit()"',
+ 'value',
+ 'text',
+ $selected
+ );
+ }
+ return $html;
+ }
+
+ /**
+ * Return the icon to move an item UP.
+ *
+ * @param integer $i The row index.
+ * @param boolean $condition True to show the icon.
+ * @param string $task The task to fire.
+ * @param string $alt The image alternative text string.
+ * @param boolean $enabled An optional setting for access control on the action.
+ * @param string $checkbox An optional prefix for checkboxes.
+ *
+ * @return string Either the icon to move an item up or a space.
+ *
+ * @since 11.1
+ */
+ public function orderUpIcon($i, $condition = true, $task = 'orderup', $alt = 'JLIB_HTML_MOVE_UP', $enabled = true, $checkbox = 'cb')
+ {
+ if (($i > 0 || ($i + $this->limitstart > 0)) && $condition)
+ {
+ return JHtml::_('jgrid.orderUp', $i, $task, '', $alt, $enabled, $checkbox);
+ }
+ else
+ {
+ return ' ';
+ }
+ }
+
+ /**
+ * Return the icon to move an item DOWN.
+ *
+ * @param integer $i The row index.
+ * @param integer $n The number of items in the list.
+ * @param boolean $condition True to show the icon.
+ * @param string $task The task to fire.
+ * @param string $alt The image alternative text string.
+ * @param boolean $enabled An optional setting for access control on the action.
+ * @param string $checkbox An optional prefix for checkboxes.
+ *
+ * @return string Either the icon to move an item down or a space.
+ *
+ * @since 11.1
+ */
+ public function orderDownIcon($i, $n, $condition = true, $task = 'orderdown', $alt = 'JLIB_HTML_MOVE_DOWN', $enabled = true, $checkbox = 'cb')
+ {
+ if (($i < $n - 1 || $i + $this->limitstart < $this->total - 1) && $condition)
+ {
+ return JHtml::_('jgrid.orderDown', $i, $task, '', $alt, $enabled, $checkbox);
+ }
+ else
+ {
+ return ' ';
+ }
+ }
+
+ /**
+ * Create the HTML for a list footer
+ *
+ * @param array $list Pagination list data structure.
+ *
+ * @return string HTML for a list footer
+ *
+ * @since 11.1
+ */
+ protected function _list_footer($list)
+ {
+ $html = "";
+
+ return $html;
+ }
+
+ /**
+ * Create the html for a list footer
+ *
+ * @param array $list Pagination list data structure.
+ *
+ * @return string HTML for a list start, previous, next,end
+ *
+ * @since 11.1
+ */
+ protected function _list_render($list)
+ {
+ // Reverse output rendering for right-to-left display.
+ $html = '';
+ $html .= '';
+ $html .= '';
+ foreach ($list['pages'] as $page)
+ {
+ $html .= '' . $page['data'] . ' ';
+ }
+ $html .= '';
+ $html .= '';
+ $html .= ' ';
+
+ return $html;
+ }
+
+ /**
+ * Method to create an active pagination link to the item
+ *
+ * @param JPaginationObject &$item The object with which to make an active link.
+ *
+ * @return string HTML link
+ *
+ * @since 11.1
+ */
+ protected function _item_active(&$item)
+ {
+ $app = JFactory::getApplication();
+ if ($app->isAdmin())
+ {
+ if ($item->base > 0)
+ {
+ return "text . "\" onclick=\"document.adminForm." . $this->prefix . "limitstart.value=" . $item->base
+ . "; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ else
+ {
+ return "text . "\" onclick=\"document.adminForm." . $this->prefix
+ . "limitstart.value=0; Joomla.submitform();return false;\">" . $item->text . " ";
+ }
+ }
+ else
+ {
+ return "text . "\" href=\"" . $item->link . "\" class=\"pagenav\">" . $item->text . " ";
+ }
+ }
+
+ /**
+ * Method to create an inactive pagination string
+ *
+ * @param object &$item The item to be processed
+ *
+ * @return string
+ *
+ * @since 11.1
+ */
+ protected function _item_inactive(&$item)
+ {
+ $app = JFactory::getApplication();
+ if ($app->isAdmin())
+ {
+ return "" . $item->text . " ";
+ }
+ else
+ {
+ return "" . $item->text . " ";
+ }
+ }
+
+ /**
+ * Create and return the pagination data object.
+ *
+ * @return object Pagination data object.
+ *
+ * @since 11.1
+ */
+ protected function _buildDataObject()
+ {
+ // Initialise variables.
+ $data = new stdClass;
+
+ // Build the additional URL parameters string.
+ $params = '';
+ if (!empty($this->_additionalUrlParams))
+ {
+ foreach ($this->_additionalUrlParams as $key => $value)
+ {
+ $params .= '&' . $key . '=' . $value;
+ }
+ }
+
+ $data->all = new JPaginationObject(JText::_('JLIB_HTML_VIEW_ALL'), $this->prefix);
+ if (!$this->_viewall)
+ {
+ $data->all->base = '0';
+ $data->all->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=');
+ }
+
+ // Set the start and previous data objects.
+ $data->start = new JPaginationObject(JText::_('JLIB_HTML_START'), $this->prefix);
+ $data->previous = new JPaginationObject(JText::_('JPREV'), $this->prefix);
+
+ if ($this->get('pages.current') > 1)
+ {
+ $page = ($this->get('pages.current') - 2) * $this->limit;
+
+ // Set the empty for removal from route
+ //$page = $page == 0 ? '' : $page;
+
+ $data->start->base = '0';
+ $data->start->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=0' . '&limit=' . $this->limit);
+ $data->previous->base = $page;
+ $data->previous->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $page . '&limit=' . $this->limit);
+ }
+
+ // Set the next and end data objects.
+ $data->next = new JPaginationObject(JText::_('JNEXT'), $this->prefix);
+ $data->end = new JPaginationObject(JText::_('JLIB_HTML_END'), $this->prefix);
+
+ if ($this->get('pages.current') < $this->get('pages.total'))
+ {
+ $next = $this->get('pages.current') * $this->limit;
+ $end = ($this->get('pages.total') - 1) * $this->limit;
+
+ $data->next->base = $next;
+ $data->next->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $next . '&limit=' . $this->limit);
+ $data->end->base = $end;
+ $data->end->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $end . '&limit=' . $this->limit);
+ }
+
+ $data->pages = array();
+ $stop = $this->get('pages.stop');
+ for ($i = $this->get('pages.start'); $i <= $stop; $i++)
+ {
+ $offset = ($i - 1) * $this->limit;
+ // Set the empty for removal from route
+ //$offset = $offset == 0 ? '' : $offset;
+
+ $data->pages[$i] = new JPaginationObject($i, $this->prefix);
+ if ($i != $this->get('pages.current') || $this->_viewall)
+ {
+ $data->pages[$i]->base = $offset;
+ $data->pages[$i]->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $offset . '&limit=' . $this->limit);
+ }
+ }
+ return $data;
+ }
+}
+
+/**
+ * Pagination object representing a particular item in the pagination lists.
+ *
+ * @package Joomla.Platform
+ * @subpackage HTML
+ * @since 11.1
+ */
+class JPaginationObject extends JObject
+{
+ /**
+ * @var string The link text.
+ * @since 11.1
+ */
+ public $text;
+
+ /**
+ * @var integer The number of rows as a base offset.
+ * @since 11.1
+ */
+ public $base;
+
+ /**
+ * @var string The link URL.
+ * @since 11.1
+ */
+ public $link;
+
+ /**
+ * @var integer The prefix used for request variables.
+ * @since 11.1
+ */
+ public $prefix;
+
+ /**
+ * Class constructor.
+ *
+ * @param string $text The link text.
+ * @param integer $prefix The prefix used for request variables.
+ * @param integer $base The number of rows as a base offset.
+ * @param string $link The link URL.
+ *
+ * @since 11.1
+ */
+ public function __construct($text, $prefix = '', $base = null, $link = null)
+ {
+ $this->text = $text;
+ $this->prefix = $prefix;
+ $this->base = $base;
+ $this->link = $link;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla25/view.php b/plugins/system/t3/includes/joomla25/view.php
new file mode 100644
index 0000000..6f84c0d
--- /dev/null
+++ b/plugins/system/t3/includes/joomla25/view.php
@@ -0,0 +1,792 @@
+ array(), 'helper' => array());
+
+ /**
+ * The name of the default template source file.
+ *
+ * @var string
+ */
+ protected $_template = null;
+
+ /**
+ * The output of the template script.
+ *
+ * @var string
+ */
+ protected $_output = null;
+
+ /**
+ * Callback for escaping.
+ *
+ * @var string
+ */
+ protected $_escape = 'htmlspecialchars';
+
+ /**
+ * Charset to use in escaping mechanisms; defaults to urf8 (UTF-8)
+ *
+ * @var string
+ */
+ protected $_charset = 'UTF-8';
+
+ /**
+ * Constructor
+ *
+ * @param array $config A named configuration array for object construction.
+ * name: the name (optional) of the view (defaults to the view class name suffix).
+ * charset: the character set to use for display
+ * escape: the name (optional) of the function to use for escaping strings
+ * base_path: the parent path (optional) of the views directory (defaults to the component folder)
+ * template_plath: the path (optional) of the layout directory (defaults to base_path + /views/ + view name
+ * helper_path: the path (optional) of the helper files (defaults to base_path + /helpers/)
+ * layout: the layout (optional) to use to display the view
+ *
+ * @since 11.1
+ */
+ public function __construct($config = array())
+ {
+ // Set the view name
+ if (empty($this->_name))
+ {
+ if (array_key_exists('name', $config))
+ {
+ $this->_name = $config['name'];
+ }
+ else
+ {
+ $this->_name = $this->getName();
+ }
+ }
+
+ // Set the charset (used by the variable escaping functions)
+ if (array_key_exists('charset', $config))
+ {
+ $this->_charset = $config['charset'];
+ }
+
+ // User-defined escaping callback
+ if (array_key_exists('escape', $config))
+ {
+ $this->setEscape($config['escape']);
+ }
+
+ // Set a base path for use by the view
+ if (array_key_exists('base_path', $config))
+ {
+ $this->_basePath = $config['base_path'];
+ }
+ else
+ {
+ $this->_basePath = JPATH_COMPONENT;
+ }
+
+ // Set the default template search path
+ if (array_key_exists('template_path', $config))
+ {
+ // User-defined dirs
+ $this->_setPath('template', $config['template_path']);
+ }
+ else
+ {
+ $this->_setPath('template', $this->_basePath . '/views/' . $this->getName() . '/tmpl');
+ }
+
+ // Set the default helper search path
+ if (array_key_exists('helper_path', $config))
+ {
+ // User-defined dirs
+ $this->_setPath('helper', $config['helper_path']);
+ }
+ else
+ {
+ $this->_setPath('helper', $this->_basePath . '/helpers');
+ }
+
+ // Set the layout
+ if (array_key_exists('layout', $config))
+ {
+ $this->setLayout($config['layout']);
+ }
+ else
+ {
+ $this->setLayout('default');
+ }
+
+ $this->baseurl = JURI::base(true);
+ }
+
+ /**
+ * Execute and display a template script.
+ *
+ * @param string $tpl The name of the template file to parse; automatically searches through the template paths.
+ *
+ * @return mixed A string if successful, otherwise a JError object.
+ *
+ * @see fetch()
+ * @since 11.1
+ */
+ public function display($tpl = null)
+ {
+ $result = $this->loadTemplate($tpl);
+ if ($result instanceof Exception)
+ {
+ return $result;
+ }
+
+ echo $result;
+ }
+
+ /**
+ * Assigns variables to the view script via differing strategies.
+ *
+ * This method is overloaded; you can assign all the properties of
+ * an object, an associative array, or a single value by name.
+ *
+ * You are not allowed to set variables that begin with an underscore;
+ * these are either private properties for JView or private variables
+ * within the template script itself.
+ *
+ *
+ * $view = new JView;
+ *
+ * // Assign directly
+ * $view->var1 = 'something';
+ * $view->var2 = 'else';
+ *
+ * // Assign by name and value
+ * $view->assign('var1', 'something');
+ * $view->assign('var2', 'else');
+ *
+ * // Assign by assoc-array
+ * $ary = array('var1' => 'something', 'var2' => 'else');
+ * $view->assign($obj);
+ *
+ * // Assign by object
+ * $obj = new stdClass;
+ * $obj->var1 = 'something';
+ * $obj->var2 = 'else';
+ * $view->assign($obj);
+ *
+ *
+ *
+ * @return boolean True on success, false on failure.
+ */
+ public function assign()
+ {
+ // Get the arguments; there may be 1 or 2.
+ $arg0 = @func_get_arg(0);
+ $arg1 = @func_get_arg(1);
+
+ // Assign by object
+ if (is_object($arg0))
+ {
+ // Assign public properties
+ foreach (get_object_vars($arg0) as $key => $val)
+ {
+ if (substr($key, 0, 1) != '_')
+ {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // Assign by associative array
+ if (is_array($arg0))
+ {
+ foreach ($arg0 as $key => $val)
+ {
+ if (substr($key, 0, 1) != '_')
+ {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // Assign by string name and mixed value.
+
+ // We use array_key_exists() instead of isset() because isset()
+ // fails if the value is set to null.
+ if (is_string($arg0) && substr($arg0, 0, 1) != '_' && func_num_args() > 1)
+ {
+ $this->$arg0 = $arg1;
+ return true;
+ }
+
+ // $arg0 was not object, array, or string.
+ return false;
+ }
+
+ /**
+ * Assign variable for the view (by reference).
+ *
+ * You are not allowed to set variables that begin with an underscore;
+ * these are either private properties for JView or private variables
+ * within the template script itself.
+ *
+ *
+ * $view = new JView;
+ *
+ * // Assign by name and value
+ * $view->assignRef('var1', $ref);
+ *
+ * // Assign directly
+ * $view->ref = &$var1;
+ *
+ *
+ * @param string $key The name for the reference in the view.
+ * @param mixed &$val The referenced variable.
+ *
+ * @return boolean True on success, false on failure.
+ *
+ * @since 11.1
+ */
+ public function assignRef($key, &$val)
+ {
+ if (is_string($key) && substr($key, 0, 1) != '_')
+ {
+ $this->$key = &$val;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Escapes a value for output in a view script.
+ *
+ * If escaping mechanism is either htmlspecialchars or htmlentities, uses
+ * {@link $_encoding} setting.
+ *
+ * @param mixed $var The output to escape.
+ *
+ * @return mixed The escaped value.
+ *
+ * @since 11.1
+ */
+ public function escape($var)
+ {
+ if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities')))
+ {
+ return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_charset);
+ }
+
+ return call_user_func($this->_escape, $var);
+ }
+
+ /**
+ * Method to get data from a registered model or a property of the view
+ *
+ * @param string $property The name of the method to call on the model or the property to get
+ * @param string $default The name of the model to reference or the default value [optional]
+ *
+ * @return mixed The return value of the method
+ *
+ * @since 11.1
+ */
+ public function get($property, $default = null)
+ {
+
+ // If $model is null we use the default model
+ if (is_null($default))
+ {
+ $model = $this->_defaultModel;
+ }
+ else
+ {
+ $model = strtolower($default);
+ }
+
+ // First check to make sure the model requested exists
+ if (isset($this->_models[$model]))
+ {
+ // Model exists, let's build the method name
+ $method = 'get' . ucfirst($property);
+
+ // Does the method exist?
+ if (method_exists($this->_models[$model], $method))
+ {
+ // The method exists, let's call it and return what we get
+ $result = $this->_models[$model]->$method();
+ return $result;
+ }
+
+ }
+
+ // Degrade to JObject::get
+ $result = parent::get($property, $default);
+
+ return $result;
+ }
+
+ /**
+ * Method to get the model object
+ *
+ * @param string $name The name of the model (optional)
+ *
+ * @return mixed JModel object
+ *
+ * @since 11.1
+ */
+ public function getModel($name = null)
+ {
+ if ($name === null)
+ {
+ $name = $this->_defaultModel;
+ }
+ return $this->_models[strtolower($name)];
+ }
+
+ /**
+ * Get the layout.
+ *
+ * @return string The layout name
+ */
+ public function getLayout()
+ {
+ return $this->_layout;
+ }
+
+ /**
+ * Get the layout template.
+ *
+ * @return string The layout template name
+ */
+ public function getLayoutTemplate()
+ {
+ return $this->_layoutTemplate;
+ }
+
+ /**
+ * Method to get the view name
+ *
+ * The model name by default parsed using the classname, or it can be set
+ * by passing a $config['name'] in the class constructor
+ *
+ * @return string The name of the model
+ *
+ * @since 11.1
+ */
+ public function getName()
+ {
+ if (empty($this->_name))
+ {
+ $r = null;
+ if (!preg_match('/View((view)*(.*(view)?.*))$/i', get_class($this), $r))
+ {
+ JError::raiseError(500, JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME'));
+ }
+ if (strpos($r[3], "view"))
+ {
+ JError::raiseWarning('SOME_ERROR_CODE', JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME_SUBSTRING'));
+ }
+ $this->_name = strtolower($r[3]);
+ }
+
+ return $this->_name;
+ }
+
+ /**
+ * Method to add a model to the view. We support a multiple model single
+ * view system by which models are referenced by classname. A caveat to the
+ * classname referencing is that any classname prepended by JModel will be
+ * referenced by the name without JModel, eg. JModelCategory is just
+ * Category.
+ *
+ * @param JModel &$model The model to add to the view.
+ * @param boolean $default Is this the default model?
+ *
+ * @return object The added model.
+ *
+ * @since 11.1
+ */
+ public function setModel(&$model, $default = false)
+ {
+ $name = strtolower($model->getName());
+ $this->_models[$name] = &$model;
+
+ if ($default)
+ {
+ $this->_defaultModel = $name;
+ }
+ return $model;
+ }
+
+ /**
+ * Sets the layout name to use
+ *
+ * @param string $layout The layout name or a string in format :
+ *
+ * @return string Previous value.
+ *
+ * @since 11.1
+ */
+ public function setLayout($layout)
+ {
+ $previous = $this->_layout;
+ if (strpos($layout, ':') === false)
+ {
+ $this->_layout = $layout;
+ }
+ else
+ {
+ // Convert parameter to array based on :
+ $temp = explode(':', $layout);
+ $this->_layout = $temp[1];
+
+ // Set layout template
+ $this->_layoutTemplate = $temp[0];
+ }
+
+ return $previous;
+ }
+
+ /**
+ * Allows a different extension for the layout files to be used
+ *
+ * @param string $value The extension.
+ *
+ * @return string Previous value
+ *
+ * @since 11.1
+ */
+ public function setLayoutExt($value)
+ {
+ $previous = $this->_layoutExt;
+ if ($value = preg_replace('#[^A-Za-z0-9]#', '', trim($value)))
+ {
+ $this->_layoutExt = $value;
+ }
+
+ return $previous;
+ }
+
+ /**
+ * Sets the _escape() callback.
+ *
+ * @param mixed $spec The callback for _escape() to use.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ public function setEscape($spec)
+ {
+ $this->_escape = $spec;
+ }
+
+ /**
+ * Adds to the stack of view script paths in LIFO order.
+ *
+ * @param mixed $path A directory path or an array of paths.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ public function addTemplatePath($path)
+ {
+ $this->_addPath('template', $path);
+ }
+
+ /**
+ * Adds to the stack of helper script paths in LIFO order.
+ *
+ * @param mixed $path A directory path or an array of paths.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ public function addHelperPath($path)
+ {
+ $this->_addPath('helper', $path);
+ }
+
+ /**
+ * Load a template file -- first look in the templates folder for an override
+ *
+ * @param string $tpl The name of the template source file; automatically searches the template paths and compiles as needed.
+ *
+ * @return string The output of the the template script.
+ *
+ * @since 11.1
+ */
+ public function loadTemplate($tpl = null)
+ {
+ // Clear prior output
+ $this->_output = null;
+
+ $template = JFactory::getApplication()->getTemplate();
+ $layout = $this->getLayout();
+ $layoutTemplate = $this->getLayoutTemplate();
+
+ // Create the template file name based on the layout
+ $file = isset($tpl) ? $layout . '_' . $tpl : $layout;
+
+ // Clean the file name
+ $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
+ $tpl = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl;
+
+ // Load the language file for the template
+ $lang = JFactory::getLanguage();
+ $lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
+ || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, false)
+ || $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
+ || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", $lang->getDefault(), false, false);
+
+ // Change the template folder if alternative layout is in different template
+ if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template)
+ {
+ $this->_path['template'] = str_replace($template, $layoutTemplate, $this->_path['template']);
+ }
+
+ // Load the template script
+ jimport('joomla.filesystem.path');
+ $filetofind = $this->_createFileName('template', array('name' => $file));
+ $this->_template = JPath::find($this->_path['template'], $filetofind);
+
+ // If alternate layout can't be found, fall back to default layout
+ if ($this->_template == false)
+ {
+ $filetofind = $this->_createFileName('', array('name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl)));
+ $this->_template = JPath::find($this->_path['template'], $filetofind);
+ }
+
+ if ($this->_template != false)
+ {
+ // Unset so as not to introduce into template scope
+ unset($tpl);
+ unset($file);
+
+ // Never allow a 'this' property
+ if (isset($this->this))
+ {
+ unset($this->this);
+ }
+
+ // Start capturing output into a buffer
+ ob_start();
+
+ // Include the requested template filename in the local scope
+ // (this will execute the view logic).
+ include $this->_template;
+
+ // Done with the requested template; get the buffer and
+ // clear it.
+ $this->_output = ob_get_contents();
+ ob_end_clean();
+
+ return $this->_output;
+ }
+ else
+ {
+ return JError::raiseError(500, JText::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file));
+ }
+ }
+
+ /**
+ * Load a helper file
+ *
+ * @param string $hlp The name of the helper source file automatically searches the helper paths and compiles as needed.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ public function loadHelper($hlp = null)
+ {
+ // Clean the file name
+ $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $hlp);
+
+ // Load the template script
+ jimport('joomla.filesystem.path');
+ $helper = JPath::find($this->_path['helper'], $this->_createFileName('helper', array('name' => $file)));
+
+ if ($helper != false)
+ {
+ // Include the requested template filename in the local scope
+ include_once $helper;
+ }
+ }
+
+ /**
+ * Sets an entire array of search paths for templates or resources.
+ *
+ * @param string $type The type of path to set, typically 'template'.
+ * @param mixed $path The new search path, or an array of search paths. If null or false, resets to the current directory only.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ protected function _setPath($type, $path)
+ {
+ $component = JApplicationHelper::getComponentName();
+ $app = JFactory::getApplication();
+
+ // Clear out the prior search dirs
+ $this->_path[$type] = array();
+
+ // Actually add the user-specified directories
+ $this->_addPath($type, $path);
+
+ // Always add the fallback directories as last resort
+ switch (strtolower($type))
+ {
+ case 'template':
+ // Set the alternative template search dir
+ if (isset($app))
+ {
+ $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
+
+ //if it is T3 template, update search path for template
+ $this->_addPath('template', T3_PATH . '/html/' . $component . '/' . $this->getName());
+
+ $fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
+ $this->_addPath('template', $fallback);
+
+ //search path for user custom folder
+ if (!defined('T3_LOCAL_DISABLED')) $this->_addPath('template', T3_LOCAL_PATH . '/html/' . $component . '/' . $this->getName());
+
+ }
+ break;
+ }
+ }
+
+ /**
+ * Adds to the search path for templates and resources.
+ *
+ * @param string $type The type of path to add.
+ * @param mixed $path The directory or stream, or an array of either, to search.
+ *
+ * @return void
+ *
+ * @since 11.1
+ */
+ protected function _addPath($type, $path)
+ {
+ // Just force to array
+ settype($path, 'array');
+
+ // Loop through the path directories
+ foreach ($path as $dir)
+ {
+ // no surrounding spaces allowed!
+ $dir = trim($dir);
+
+ // Add trailing separators as needed
+ if (substr($dir, -1) != DIRECTORY_SEPARATOR)
+ {
+ // Directory
+ $dir .= DIRECTORY_SEPARATOR;
+ }
+
+ // Add to the top of the search dirs
+ array_unshift($this->_path[$type], $dir);
+ }
+ }
+
+ /**
+ * Create the filename for a resource
+ *
+ * @param string $type The resource type to create the filename for
+ * @param array $parts An associative array of filename information
+ *
+ * @return string The filename
+ *
+ * @since 11.1
+ */
+ protected function _createFileName($type, $parts = array())
+ {
+ $filename = '';
+
+ switch ($type)
+ {
+ case 'template':
+ $filename = strtolower($parts['name']) . '.' . $this->_layoutExt;
+ break;
+
+ default:
+ $filename = strtolower($parts['name']) . '.php';
+ break;
+ }
+ return $filename;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla30/modulehelper.php b/plugins/system/t3/includes/joomla30/modulehelper.php
new file mode 100644
index 0000000..e732d26
--- /dev/null
+++ b/plugins/system/t3/includes/joomla30/modulehelper.php
@@ -0,0 +1,631 @@
+
+ * @link http://www.nonumber.nl
+ * @copyright Copyright © 2011 All Rights Reserved
+ * Brandon IT Consulting (http://www.metamodpro.com)
+ * NoNumber (http://www.nonumber.nl)
+ * JoomlArt (http://www.joomlart.com)
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
+ */
+
+/**
+ * BASE ON JOOMLA CORE FILE:
+ * /libraries/joomla/application/module/helper.php
+ */
+
+/**
+ * @package Joomla.Legacy
+ * @subpackage Module
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or defined('JPATH_BASE') or die;
+
+/**
+ * Module helper class
+ *
+ * @package Joomla.Legacy
+ * @subpackage Module
+ * @since 11.1
+ */
+abstract class JModuleHelper
+{
+ /**
+ * Get module by name (real, eg 'Breadcrumbs' or folder, eg 'mod_breadcrumbs')
+ *
+ * @param string $name The name of the module
+ * @param string $title The title of the module, optional
+ *
+ * @return object The Module object
+ *
+ * @since 11.1
+ */
+ public static function &getModule($name, $title = null)
+ {
+ $result = null;
+ $modules =& self::_load();
+ $total = count($modules);
+
+ for ($i = 0; $i < $total; $i++)
+ {
+ // Match the name of the module
+ if ($modules[$i]->name == $name || $modules[$i]->module == $name)
+ {
+ // Match the title if we're looking for a specific instance of the module
+ if (!$title || $modules[$i]->title == $title)
+ {
+ // Found it
+ $result = &$modules[$i];
+ break;
+ }
+ }
+ }
+
+ // If we didn't find it, and the name is mod_something, create a dummy object
+ if (is_null($result) && substr($name, 0, 4) == 'mod_')
+ {
+ $result = new stdClass;
+ $result->id = 0;
+ $result->title = '';
+ $result->module = $name;
+ $result->position = '';
+ $result->content = '';
+ $result->showtitle = 0;
+ $result->control = '';
+ $result->params = '';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get modules by position
+ *
+ * @param string $position The position of the module
+ *
+ * @return array An array of module objects
+ *
+ * @since 11.1
+ */
+ public static function &getModules($position)
+ {
+ $position = strtolower($position);
+ $result = array();
+ $input = JFactory::getApplication()->input;
+
+ $modules =& self::_load();
+
+ $total = count($modules);
+ for ($i = 0; $i < $total; $i++)
+ {
+ if ($modules[$i]->position == $position)
+ {
+ $result[] = &$modules[$i];
+ }
+ }
+
+ if (count($result) == 0)
+ {
+ if ($input->getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
+ {
+ $result[0] = self::getModule('mod_' . $position);
+ $result[0]->title = $position;
+ $result[0]->content = $position;
+ $result[0]->position = $position;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Checks if a module is enabled
+ *
+ * @param string $module The module name
+ *
+ * @return boolean
+ *
+ * @since 11.1
+ */
+ public static function isEnabled($module)
+ {
+ $result = self::getModule($module);
+
+ return !is_null($result);
+ }
+
+ /**
+ * Render the module.
+ *
+ * @param object $module A module object.
+ * @param array $attribs An array of attributes for the module (probably from the XML).
+ *
+ * @return string The HTML content of the module output.
+ *
+ * @since 11.1
+ */
+ public static function renderModule($module, $attribs = array())
+ {
+ static $chrome;
+
+ if (constant('JDEBUG'))
+ {
+ JProfiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
+ }
+
+ $app = JFactory::getApplication();
+
+ // Record the scope.
+ $scope = $app->scope;
+
+ // Set scope to component name
+ $app->scope = $module->module;
+
+ // Get module parameters
+ $params = new JRegistry;
+ $params->loadString($module->params);
+
+ // Get module path
+ $module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module);
+ $path = JPATH_BASE . '/modules/' . $module->module . '/' . $module->module . '.php';
+
+ // Load the module
+ if (file_exists($path))
+ {
+ $lang = JFactory::getLanguage();
+
+ // 1.5 or Core then 1.6 3PD
+ $lang->load($module->module, JPATH_BASE, null, false, false) ||
+ $lang->load($module->module, dirname($path), null, false, false) ||
+ $lang->load($module->module, JPATH_BASE, $lang->getDefault(), false, false) ||
+ $lang->load($module->module, dirname($path), $lang->getDefault(), false, false);
+
+ $content = '';
+ ob_start();
+ include $path;
+ $module->content = ob_get_contents() . $content;
+ ob_end_clean();
+ }
+
+ // Load the module chrome functions
+ if (!$chrome)
+ {
+ $chrome = array();
+ }
+
+ include_once JPATH_THEMES . '/system/html/modules.php';
+ $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/modules.php';
+
+ if (!isset($chrome[$chromePath]))
+ {
+ if (file_exists($chromePath))
+ {
+ include_once $chromePath;
+ }
+
+ $chrome[$chromePath] = true;
+ }
+
+ // Check if the current module has a style param to override template module style
+ $paramsChromeStyle = $params->get('style');
+ if ($paramsChromeStyle)
+ {
+ $attribs['style'] = preg_replace('/^(system|' . $app->getTemplate() . ')\-/i', '', $paramsChromeStyle);
+ }
+
+ // Make sure a style is set
+ if (!isset($attribs['style']))
+ {
+ $attribs['style'] = 'none';
+ }
+
+ // Dynamically add outline style
+ if ($app->input->getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
+ {
+ $attribs['style'] .= ' outline';
+ }
+
+ // Do 3rd party stuff to manipulate module content
+ // onRenderModule is allowed to alter the $module, $attribs
+ // and may return a boolean.
+ // true=remove, any other value = keep.
+ // $result holds an array of booleans, 1 from each plugin.
+ // we ditch the module if any of them = true.
+ $result = $app->triggerEvent( 'onRenderModule', array( &$module, &$attribs ) );
+ if (!is_array($result)) {
+ $result = array($result);
+ }
+ if ( array_search( true, $result, true ) !== false )
+ {
+
+ return '';
+ }
+
+ foreach (explode(' ', $attribs['style']) as $style)
+ {
+ $chromeMethod = 'modChrome_' . $style;
+
+ // Apply chrome and render module
+ if (function_exists($chromeMethod))
+ {
+ $module->style = $attribs['style'];
+
+ ob_start();
+ $chromeMethod($module, $params, $attribs);
+ $module->content = ob_get_contents();
+ ob_end_clean();
+ }
+ }
+
+ // Revert the scope
+ $app->scope = $scope;
+
+ if (constant('JDEBUG'))
+ {
+ JProfiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')');
+ }
+
+ return $module->content;
+ }
+
+ /**
+ * Get the path to a layout for a module
+ *
+ * @param string $module The name of the module
+ * @param string $layout The name of the module layout. If alternative layout, in the form template:filename.
+ *
+ * @return string The path to the module layout
+ *
+ * @since 11.1
+ */
+ public static function getLayoutPath($module, $layout = 'default')
+ {
+ $template = JFactory::getApplication()->getTemplate();
+ $defaultLayout = $layout;
+
+ if (strpos($layout, ':') !== false)
+ {
+ // Get the template and file name from the string
+ $temp = explode(':', $layout);
+ $template = ($temp[0] == '_') ? $template : $temp[0];
+ $layout = $temp[1];
+ $defaultLayout = ($temp[1]) ? $temp[1] : 'default';
+ }
+
+ // Build the template and base path for the layout
+ $tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
+ $bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
+ $dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';
+
+ // Do 3rd party stuff to detect layout path for the module
+ // onGetLayoutPath should return the path to the $layout of $module or false
+ // $results holds an array of results returned from plugins, 1 from each plugin.
+ // if a path to the $layout is found and it is a file, return that path
+ $app = JFactory::getApplication();
+ $result = $app->triggerEvent( 'onGetLayoutPath', array( $module, $layout ) );
+ if (is_array($result))
+ {
+ foreach ($result as $path)
+ {
+ if ($path !== false && is_file ($path))
+ {
+ return $path;
+ }
+ }
+ }
+
+ // If the template has a layout override use it
+ if (file_exists($tPath))
+ {
+ return $tPath;
+ }
+ elseif (file_exists($bPath))
+ {
+ return $bPath;
+ }
+ else
+ {
+ return $dPath;
+ }
+ }
+
+ /**
+ * Load published modules.
+ *
+ * @return array
+ *
+ * @since 11.1
+ */
+ protected static function &_load()
+ {
+ static $clean;
+
+ if (isset($clean))
+ {
+ return $clean;
+ }
+
+ $app = JFactory::getApplication();
+ $Itemid = $app->input->getInt('Itemid');
+ $user = JFactory::getUser();
+ $groups = implode(',', $user->getAuthorisedViewLevels());
+ $lang = JFactory::getLanguage()->getTag();
+ $clientId = (int) $app->getClientId();
+
+ $db = JFactory::getDbo();
+
+ $query = new stdClass;
+ $query->select = array();
+ $query->from = array();
+ $query->join = array();
+ $query->where = array();
+ $query->order = array();
+
+
+ $query->select[] = 'm.published, m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params, mm.menuid';
+ $query->from[] = '#__modules AS m';
+ $query->join[] = '#__modules_menu AS mm ON mm.moduleid = m.id';
+ $query->where[] = 'm.published = 1';
+
+ $query->join[] = '#__extensions AS e ON e.element = m.module AND e.client_id = m.client_id';
+ $query->where[] = 'e.enabled = 1';
+
+ $date = JFactory::getDate();
+ $now = $date->toSql();
+ $nullDate = $db->getNullDate();
+ $query->where[] = '(m.publish_up = ' . $db->q($nullDate) . ' OR m.publish_up <= ' . $db->q($now) . ')';
+ $query->where[] = '(m.publish_down = ' . $db->q($nullDate) . ' OR m.publish_down >= ' . $db->q($now) . ')';
+
+ $query->where[] = 'm.access IN ('.$groups.')';
+ $query->where[] = 'm.client_id = ' . $clientId;
+ $query->where[] = '(mm.menuid = ' . (int) $Itemid . ' OR mm.menuid <= 0)';
+
+ // Filter by language
+ if ($app->isSite() && $app->getLanguageFilter())
+ {
+ $query->where[] = 'm.language IN (' . $db->q($lang) . ',' . $db->q('*') . ')';
+ }
+
+ $query->order[] = 'm.position, m.ordering';
+
+ // Do 3rd party stuff to change query
+ $app->triggerEvent( 'onCreateModuleQuery', array( &$query ) );
+
+ $q = $db->getQuery(true);
+ // convert array object to query object
+ foreach ( $query as $type => $strings )
+ {
+ foreach ( $strings as $string )
+ {
+ if ( $type == 'join' )
+ {
+ $q->{$type}( 'LEFT', $string );
+ }
+ else
+ {
+ $q->{$type}( $string );
+ }
+ }
+ }
+
+ // Set the query
+ $db->setQuery($q);
+ $clean = array();
+
+ try
+ {
+ $modules = $db->loadObjectList();
+ }
+ catch (RuntimeException $e)
+ {
+ JLog::add(JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), JLog::WARNING, 'jerror');
+ return $clean;
+ }
+
+ // Apply negative selections and eliminate duplicates
+ $negId = $Itemid ? -(int) $Itemid : false;
+ $dupes = array();
+ for ($i = 0, $n = count($modules); $i < $n; $i++)
+ {
+ $module = &$modules[$i];
+
+ // The module is excluded if there is an explicit prohibition
+ $negHit = ($negId === (int) $module->menuid);
+
+ if (isset($dupes[$module->id]))
+ {
+ // If this item has been excluded, keep the duplicate flag set,
+ // but remove any item from the cleaned array.
+ if ($negHit)
+ {
+ unset($clean[$module->id]);
+ }
+ continue;
+ }
+
+ $dupes[$module->id] = true;
+
+ // Only accept modules without explicit exclusions.
+ if (!$negHit)
+ {
+ $module->name = substr($module->module, 4);
+ $module->style = null;
+ $module->position = strtolower($module->position);
+ $clean[$module->id] = $module;
+ }
+ }
+
+ unset($dupes);
+
+ // Do 3rd party stuff to manipulate module array.
+ // Any plugins using this architecture may make alterations to the referenced $modules array.
+ // To remove items you can do unset($modules[n]) or $modules[n]->published = false.
+
+ // "onPrepareModuleList" may alter or add $modules, and does not need to return anything.
+ // This should be used for module addition/deletion that the user would expect to happen at an
+ // early stage.
+ $app->triggerEvent( 'onPrepareModuleList', array( &$clean ) );
+
+ // "onAlterModuleList" may alter or add $modules, and does not need to return anything.
+ $app->triggerEvent( 'onAlterModuleList', array( &$clean ) );
+
+ // "onPostProcessModuleList" allows a plugin to perform actions like parameter changes
+ // on the completed list of modules and is guaranteed to occur *after*
+ // the earlier plugins.
+ $app->triggerEvent( 'onPostProcessModuleList', array( &$clean ) );
+
+ // Remove any that were marked as disabled during the preceding steps
+ foreach ( $clean as $id => $module )
+ {
+ if ( !isset( $module->published ) || $module->published == 0 )
+ {
+
+
+ unset( $clean[$id] );
+ }
+ }
+
+ // Return to simple indexing that matches the query order.
+ $clean = array_values($clean);
+
+ return $clean;
+ }
+
+ /**
+ * Module cache helper
+ *
+ * Caching modes:
+ * To be set in XML:
+ * 'static' One cache file for all pages with the same module parameters
+ * 'oldstatic' 1.5 definition of module caching, one cache file for all pages
+ * with the same module id and user aid,
+ * 'itemid' Changes on itemid change, to be called from inside the module:
+ * 'safeuri' Id created from $cacheparams->modeparams array,
+ * 'id' Module sets own cache id's
+ *
+ * @param object $module Module object
+ * @param object $moduleparams Module parameters
+ * @param object $cacheparams Module cache parameters - id or url parameters, depending on the module cache mode
+ *
+ * @return string
+ *
+ * @since 11.1
+ *
+ * @link JFilterInput::clean()
+ */
+ public static function moduleCache($module, $moduleparams, $cacheparams)
+ {
+ if (!isset($cacheparams->modeparams))
+ {
+ $cacheparams->modeparams = null;
+ }
+
+ // Add module ID to fix problem of cache for modules with the same type
+ if ($cacheparams->modeparams && is_string($cacheparams->modeparams)) {
+ $cacheparams->modeparams .= ":".$module->id;
+ }
+
+ if (!isset($cacheparams->cachegroup))
+ {
+ $cacheparams->cachegroup = $module->module;
+ }
+
+ $user = JFactory::getUser();
+ $cache = JFactory::getCache($cacheparams->cachegroup, 'callback');
+ $conf = JFactory::getConfig();
+
+ // Turn cache off for internal callers if parameters are set to off and for all logged in users
+ if ($moduleparams->get('owncache', null) === '0' || $conf->get('caching') == 0 || $user->get('id'))
+ {
+ $cache->setCaching(false);
+ }
+
+ // Module cache is set in seconds, global cache in minutes, setLifeTime works in minutes
+ $cache->setLifeTime($moduleparams->get('cache_time', $conf->get('cachetime') * 60) / 60);
+
+ $wrkaroundoptions = array('nopathway' => 1, 'nohead' => 0, 'nomodules' => 1, 'modulemode' => 1, 'mergehead' => 1);
+
+ $wrkarounds = true;
+ $view_levels = md5(serialize($user->getAuthorisedViewLevels()));
+
+ switch ($cacheparams->cachemode)
+ {
+ case 'id':
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $cacheparams->modeparams,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'safeuri':
+ $secureid = null;
+ if (is_array($cacheparams->modeparams))
+ {
+ $uri = JRequest::get();
+ $safeuri = new stdClass;
+ foreach ($cacheparams->modeparams as $key => $value)
+ {
+ // Use int filter for id/catid to clean out spamy slugs
+ if (isset($uri[$key]))
+ {
+ $noHtmlFilter = JFilterInput::getInstance();
+ $safeuri->$key = $noHtmlFilter->clean($uri[$key], $value);
+ }
+ }
+ }
+ $secureid = md5(serialize(array($safeuri, $cacheparams->method, $moduleparams)));
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels . $secureid,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'static':
+ $ret = $cache->get(
+ array($cacheparams->class,
+ $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->module . md5(serialize($cacheparams->methodparams)),
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ // Provided for backward compatibility, not really useful.
+ case 'oldstatic':
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels,
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+
+ case 'itemid':
+ default:
+ $ret = $cache->get(
+ array($cacheparams->class, $cacheparams->method),
+ $cacheparams->methodparams,
+ $module->id . $view_levels . JFactory::getApplication()->input->getInt('Itemid', null),
+ $wrkarounds,
+ $wrkaroundoptions
+ );
+ break;
+ }
+
+ return $ret;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla30/pagination.php b/plugins/system/t3/includes/joomla30/pagination.php
new file mode 100644
index 0000000..55194cd
--- /dev/null
+++ b/plugins/system/t3/includes/joomla30/pagination.php
@@ -0,0 +1,885 @@
+total = (int) $total;
+ $this->limitstart = (int) max($limitstart, 0);
+ $this->limit = (int) max($limit, 0);
+ $this->prefix = $prefix;
+
+ if ($this->limit > $this->total)
+ {
+ $this->limitstart = 0;
+ }
+
+ if (!$this->limit)
+ {
+ $this->limit = $total;
+ $this->limitstart = 0;
+ }
+
+ /*
+ * If limitstart is greater than total (i.e. we are asked to display records that don't exist)
+ * then set limitstart to display the last natural page of results
+ */
+ if ($this->limitstart > $this->total - $this->limit)
+ {
+ $this->limitstart = max(0, (int) (ceil($this->total / $this->limit) - 1) * $this->limit);
+ }
+
+ // Set the total pages and current page values.
+ if ($this->limit > 0)
+ {
+ $this->pagesTotal = ceil($this->total / $this->limit);
+ $this->pagesCurrent = ceil(($this->limitstart + 1) / $this->limit);
+ }
+
+ // Set the pagination iteration loop values.
+ $displayedPages = 10;
+ $this->pagesStart = $this->pagesCurrent - ($displayedPages / 2);
+
+ if ($this->pagesStart < 1)
+ {
+ $this->pagesStart = 1;
+ }
+
+ if ($this->pagesStart + $displayedPages > $this->pagesTotal)
+ {
+ $this->pagesStop = $this->pagesTotal;
+
+ if ($this->pagesTotal < $displayedPages)
+ {
+ $this->pagesStart = 1;
+ }
+ else
+ {
+ $this->pagesStart = $this->pagesTotal - $displayedPages + 1;
+ }
+ }
+ else
+ {
+ $this->pagesStop = $this->pagesStart + $displayedPages - 1;
+ }
+
+ // If we are viewing all records set the view all flag to true.
+ if ($limit == 0)
+ {
+ $this->viewall = true;
+ }
+ }
+
+ /**
+ * Method to set an additional URL parameter to be added to all pagination class generated
+ * links.
+ *
+ * @param string $key The name of the URL parameter for which to set a value.
+ * @param mixed $value The value to set for the URL parameter.
+ *
+ * @return mixed The old value for the parameter.
+ *
+ * @since 1.6
+ */
+ public function setAdditionalUrlParam($key, $value)
+ {
+ // Get the old value to return and set the new one for the URL parameter.
+ $result = isset($this->additionalUrlParams[$key]) ? $this->additionalUrlParams[$key] : null;
+
+ // If the passed parameter value is null unset the parameter, otherwise set it to the given value.
+ if ($value === null)
+ {
+ unset($this->additionalUrlParams[$key]);
+ }
+ else
+ {
+ $this->additionalUrlParams[$key] = $value;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Method to get an additional URL parameter (if it exists) to be added to
+ * all pagination class generated links.
+ *
+ * @param string $key The name of the URL parameter for which to get the value.
+ *
+ * @return mixed The value if it exists or null if it does not.
+ *
+ * @since 1.6
+ */
+ public function getAdditionalUrlParam($key)
+ {
+ $result = isset($this->additionalUrlParams[$key]) ? $this->additionalUrlParams[$key] : null;
+
+ return $result;
+ }
+
+ /**
+ * Return the rationalised offset for a row with a given index.
+ *
+ * @param integer $index The row index
+ *
+ * @return integer Rationalised offset for a row with a given index.
+ *
+ * @since 1.5
+ */
+ public function getRowOffset($index)
+ {
+ return $index + 1 + $this->limitstart;
+ }
+
+ /**
+ * Return the pagination data object, only creating it if it doesn't already exist.
+ *
+ * @return object Pagination data object.
+ *
+ * @since 1.5
+ */
+ public function getData()
+ {
+ static $data;
+
+ if (!is_object($data))
+ {
+ $data = $this->_buildDataObject();
+ }
+
+ return $data;
+ }
+
+ /**
+ * Create and return the pagination pages counter string, ie. Page 2 of 4.
+ *
+ * @return string Pagination pages counter string.
+ *
+ * @since 1.5
+ */
+ public function getPagesCounter()
+ {
+ $html = null;
+
+ if ($this->pagesTotal > 1)
+ {
+ $html .= JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $this->pagesCurrent, $this->pagesTotal);
+ }
+
+ return $html;
+ }
+
+ /**
+ * Create and return the pagination result set counter string, e.g. Results 1-10 of 42
+ *
+ * @return string Pagination result set counter string.
+ *
+ * @since 1.5
+ */
+ public function getResultsCounter()
+ {
+ $html = null;
+ $fromResult = $this->limitstart + 1;
+
+ // If the limit is reached before the end of the list.
+ if ($this->limitstart + $this->limit < $this->total)
+ {
+ $toResult = $this->limitstart + $this->limit;
+ }
+ else
+ {
+ $toResult = $this->total;
+ }
+
+ // If there are results found.
+ if ($this->total > 0)
+ {
+ $msg = JText::sprintf('JLIB_HTML_RESULTS_OF', $fromResult, $toResult, $this->total);
+ $html .= "\n" . $msg;
+ }
+ else
+ {
+ $html .= "\n" . JText::_('JLIB_HTML_NO_RECORDS_FOUND');
+ }
+
+ return $html;
+ }
+
+ /**
+ * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
+ *
+ * @return string Pagination page list string.
+ *
+ * @since 1.5
+ */
+ public function getPagesLinks()
+ {
+ $app = JFactory::getApplication();
+
+ // Build the page navigation list.
+ $data = $this->_buildDataObject();
+
+ $list = array();
+ $list['prefix'] = $this->prefix;
+
+ $itemOverride = false;
+ $listOverride = false;
+
+ // $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
+ // T3: detect if chrome pagination.php in template or in plugin
+ $chromePath = T3Path::getPath ('html/pagination.php');
+
+ if (file_exists($chromePath))
+ {
+ include_once $chromePath;
+
+ if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive'))
+ {
+ $itemOverride = true;
+ }
+
+ if (function_exists('pagination_list_render'))
+ {
+ $listOverride = true;
+ }
+ }
+
+ // Build the select list
+ if ($data->all->base !== null)
+ {
+ $list['all']['active'] = true;
+ $list['all']['data'] = ($itemOverride) ? pagination_item_active($data->all) : $this->_item_active($data->all);
+ }
+ else
+ {
+ $list['all']['active'] = false;
+ $list['all']['data'] = ($itemOverride) ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
+ }
+
+ if ($data->start->base !== null)
+ {
+ $list['start']['active'] = true;
+ $list['start']['data'] = ($itemOverride) ? pagination_item_active($data->start) : $this->_item_active($data->start);
+ }
+ else
+ {
+ $list['start']['active'] = false;
+ $list['start']['data'] = ($itemOverride) ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
+ }
+
+ if ($data->previous->base !== null)
+ {
+ $list['previous']['active'] = true;
+ $list['previous']['data'] = ($itemOverride) ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
+ }
+ else
+ {
+ $list['previous']['active'] = false;
+ $list['previous']['data'] = ($itemOverride) ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
+ }
+
+ // Make sure it exists
+ $list['pages'] = array();
+
+ foreach ($data->pages as $i => $page)
+ {
+ if ($page->base !== null)
+ {
+ $list['pages'][$i]['active'] = true;
+ $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_active($page) : $this->_item_active($page);
+ }
+ else
+ {
+ $list['pages'][$i]['active'] = false;
+ $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_inactive($page) : $this->_item_inactive($page);
+ }
+ }
+
+ if ($data->next->base !== null)
+ {
+ $list['next']['active'] = true;
+ $list['next']['data'] = ($itemOverride) ? pagination_item_active($data->next) : $this->_item_active($data->next);
+ }
+ else
+ {
+ $list['next']['active'] = false;
+ $list['next']['data'] = ($itemOverride) ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
+ }
+
+ if ($data->end->base !== null)
+ {
+ $list['end']['active'] = true;
+ $list['end']['data'] = ($itemOverride) ? pagination_item_active($data->end) : $this->_item_active($data->end);
+ }
+ else
+ {
+ $list['end']['active'] = false;
+ $list['end']['data'] = ($itemOverride) ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
+ }
+
+ if ($this->total > $this->limit)
+ {
+ return ($listOverride) ? pagination_list_render($list) : $this->_list_render($list);
+ }
+ else
+ {
+ return '';
+ }
+ }
+
+ /**
+ * Get the pagination links
+ *
+ * @param string $layoutId Layout to render the links
+ * @param array $options Optional array with settings for the layout
+ *
+ * @return string Pagination links.
+ *
+ * @since 3.3
+ */
+ public function getPaginationLinks($layoutId = 'joomla.pagination.links', $options = array())
+ {
+ // Allow to receive a null layout
+ $layoutId = (null === $layoutId) ? 'joomla.pagination.links' : $layoutId;
+
+ $app = JFactory::getApplication();
+
+ $list = array(
+ 'prefix' => $this->prefix,
+ 'limit' => $this->limit,
+ 'limitstart' => $this->limitstart,
+ 'total' => $this->total,
+ 'limitfield' => $this->getLimitBox(),
+ 'pagescounter' => $this->getPagesCounter(),
+ 'pages' => $this->getPaginationPages()
+ );
+
+ return JLayoutHelper::render($layoutId, array('list' => $list, 'options' => $options));
+ }
+
+ /**
+ * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
+ *
+ * @return string Pagination page list string.
+ *
+ * @since 3.3
+ */
+ public function getPaginationPages()
+ {
+ $list = array();
+
+ if ($this->total > $this->limit)
+ {
+ // Build the page navigation list.
+ $data = $this->_buildDataObject();
+
+ // All
+ $list['all']['active'] = (null !== $data->all->base);
+ $list['all']['data'] = $data->all;
+
+ // Start
+ $list['start']['active'] = (null !== $data->start->base);
+ $list['start']['data'] = $data->start;
+
+ // Previous link
+ $list['previous']['active'] = (null !== $data->previous->base);
+ $list['previous']['data'] = $data->previous;
+
+ // Make sure it exists
+ $list['pages'] = array();
+
+ foreach ($data->pages as $i => $page)
+ {
+ $list['pages'][$i]['active'] = (null !== $page->base);
+ $list['pages'][$i]['data'] = $page;
+ }
+
+ $list['next']['active'] = (null !== $data->next->base);
+ $list['next']['data'] = $data->next;
+
+ $list['end']['active'] = (null !== $data->end->base);
+ $list['end']['data'] = $data->end;
+ }
+
+ return $list;
+ }
+
+ /**
+ * Return the pagination footer.
+ *
+ * @return string Pagination footer.
+ *
+ * @since 1.5
+ */
+ public function getListFooter()
+ {
+ // Keep B/C for overrides done with chromes
+ // $chromePath = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/pagination.php';
+ // T3: detect if chrome pagination.php in template or in plugin
+ $chromePath = T3Path::getPath ('html/pagination.php');
+
+ if (file_exists($chromePath))
+ {
+ $list = array();
+ $list['prefix'] = $this->prefix;
+ $list['limit'] = $this->limit;
+ $list['limitstart'] = $this->limitstart;
+ $list['total'] = $this->total;
+ $list['limitfield'] = $this->getLimitBox();
+ $list['pagescounter'] = $this->getPagesCounter();
+ $list['pageslinks'] = $this->getPagesLinks();
+
+ include_once $chromePath;
+
+ if (function_exists('pagination_list_footer'))
+ {
+ return pagination_list_footer($list);
+ }
+ }
+
+ return $this->getPaginationLinks();
+ }
+
+ /**
+ * Creates a dropdown box for selecting how many records to show per page.
+ *
+ * @return string The HTML for the limit # input box.
+ *
+ * @since 1.5
+ */
+ public function getLimitBox()
+ {
+ $app = JFactory::getApplication();
+ $limits = array();
+
+ // Make the option list.
+ for ($i = 5; $i <= 30; $i += 5)
+ {
+ $limits[] = JHtml::_('select.option', "$i");
+ }
+
+ $limits[] = JHtml::_('select.option', '50', JText::_('J50'));
+ $limits[] = JHtml::_('select.option', '100', JText::_('J100'));
+ $limits[] = JHtml::_('select.option', '0', JText::_('JALL'));
+
+ $selected = $this->viewall ? 0 : $this->limit;
+
+ // Build the select list.
+ if ($app->isAdmin())
+ {
+ $html = JHtml::_(
+ 'select.genericlist',
+ $limits,
+ $this->prefix . 'limit',
+ 'class="inputbox input-mini" size="1" onchange="Joomla.submitform();"',
+ 'value',
+ 'text',
+ $selected
+ );
+ }
+ else
+ {
+ $html = JHtml::_(
+ 'select.genericlist',
+ $limits,
+ $this->prefix . 'limit',
+ 'class="inputbox input-mini" size="1" onchange="this.form.submit()"',
+ 'value',
+ 'text',
+ $selected
+ );
+ }
+
+ return $html;
+ }
+
+ /**
+ * Return the icon to move an item UP.
+ *
+ * @param integer $i The row index.
+ * @param boolean $condition True to show the icon.
+ * @param string $task The task to fire.
+ * @param string $alt The image alternative text string.
+ * @param boolean $enabled An optional setting for access control on the action.
+ * @param string $checkbox An optional prefix for checkboxes.
+ *
+ * @return string Either the icon to move an item up or a space.
+ *
+ * @since 1.5
+ */
+ public function orderUpIcon($i, $condition = true, $task = 'orderup', $alt = 'JLIB_HTML_MOVE_UP', $enabled = true, $checkbox = 'cb')
+ {
+ if (($i > 0 || ($i + $this->limitstart > 0)) && $condition)
+ {
+ return JHtml::_('jgrid.orderUp', $i, $task, '', $alt, $enabled, $checkbox);
+ }
+ else
+ {
+ return ' ';
+ }
+ }
+
+ /**
+ * Return the icon to move an item DOWN.
+ *
+ * @param integer $i The row index.
+ * @param integer $n The number of items in the list.
+ * @param boolean $condition True to show the icon.
+ * @param string $task The task to fire.
+ * @param string $alt The image alternative text string.
+ * @param boolean $enabled An optional setting for access control on the action.
+ * @param string $checkbox An optional prefix for checkboxes.
+ *
+ * @return string Either the icon to move an item down or a space.
+ *
+ * @since 1.5
+ */
+ public function orderDownIcon($i, $n, $condition = true, $task = 'orderdown', $alt = 'JLIB_HTML_MOVE_DOWN', $enabled = true, $checkbox = 'cb')
+ {
+ if (($i < $n - 1 || $i + $this->limitstart < $this->total - 1) && $condition)
+ {
+ return JHtml::_('jgrid.orderDown', $i, $task, '', $alt, $enabled, $checkbox);
+ }
+ else
+ {
+ return ' ';
+ }
+ }
+
+ /**
+ * Create the HTML for a list footer
+ *
+ * @param array $list Pagination list data structure.
+ *
+ * @return string HTML for a list footer
+ *
+ * @since 1.5
+ */
+ protected function _list_footer($list)
+ {
+ $html = "";
+
+ return $html;
+ }
+
+ /**
+ * Create the html for a list footer
+ *
+ * @param array $list Pagination list data structure.
+ *
+ * @return string HTML for a list start, previous, next,end
+ *
+ * @since 1.5
+ */
+ protected function _list_render($list)
+ {
+ // Reverse output rendering for right-to-left display.
+ $html = '';
+ $html .= '';
+ $html .= '';
+
+ foreach ($list['pages'] as $page)
+ {
+ $html .= '' . $page['data'] . ' ';
+ }
+
+ $html .= '';
+ $html .= '';
+ $html .= ' ';
+
+ return $html;
+ }
+
+ /**
+ * Method to create an active pagination link to the item
+ *
+ * @param JPaginationObject $item The object with which to make an active link.
+ *
+ * @return string HTML link
+ *
+ * @since 1.5
+ */
+ protected function _item_active(JPaginationObject $item)
+ {
+ $app = JFactory::getApplication();
+
+ $title = '';
+ $class = '';
+
+ if (!is_numeric($item->text))
+ {
+ JHtml::_('bootstrap.tooltip');
+ $title = ' title="' . $item->text . '"';
+ $class = 'hasTooltip ';
+ }
+
+ if ($app->isAdmin())
+ {
+ return '' . $item->text . ' ';
+ }
+ else
+ {
+ return '' . $item->text . ' ';
+ }
+ }
+
+ /**
+ * Method to create an inactive pagination string
+ *
+ * @param JPaginationObject $item The item to be processed
+ *
+ * @return string
+ *
+ * @since 1.5
+ */
+ protected function _item_inactive(JPaginationObject $item)
+ {
+ $app = JFactory::getApplication();
+
+ if ($app->isAdmin())
+ {
+ return '' . $item->text . ' ';
+ }
+ else
+ {
+ return '' . $item->text . ' ';
+ }
+ }
+
+ /**
+ * Create and return the pagination data object.
+ *
+ * @return object Pagination data object.
+ *
+ * @since 1.5
+ */
+ protected function _buildDataObject()
+ {
+ $data = new stdClass;
+
+ // Build the additional URL parameters string.
+ $params = '';
+
+ if (!empty($this->additionalUrlParams))
+ {
+ foreach ($this->additionalUrlParams as $key => $value)
+ {
+ $params .= '&' . $key . '=' . $value;
+ }
+ }
+
+ $data->all = new JPaginationObject(JText::_('JLIB_HTML_VIEW_ALL'), $this->prefix);
+
+ if (!$this->viewall)
+ {
+ $data->all->base = '0';
+ $data->all->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=');
+ }
+
+ // Set the start and previous data objects.
+ $data->start = new JPaginationObject(JText::_('JLIB_HTML_START'), $this->prefix);
+ $data->previous = new JPaginationObject(JText::_('JPREV'), $this->prefix);
+
+ if ($this->pagesCurrent > 1)
+ {
+ $page = ($this->pagesCurrent - 2) * $this->limit;
+
+ // Set the empty for removal from route
+ // @todo remove code: $page = $page == 0 ? '' : $page;
+
+ $data->start->base = '0';
+ $data->start->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=0' . '&limit=' . $this->limit);
+ $data->previous->base = $page;
+ $data->previous->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $page . '&limit=' . $this->limit);
+ }
+
+ // Set the next and end data objects.
+ $data->next = new JPaginationObject(JText::_('JNEXT'), $this->prefix);
+ $data->end = new JPaginationObject(JText::_('JLIB_HTML_END'), $this->prefix);
+
+ if ($this->pagesCurrent < $this->pagesTotal)
+ {
+ $next = $this->pagesCurrent * $this->limit;
+ $end = ($this->pagesTotal - 1) * $this->limit;
+
+ $data->next->base = $next;
+ $data->next->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $next . '&limit=' . $this->limit);
+ $data->end->base = $end;
+ $data->end->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $end . '&limit=' . $this->limit);
+ }
+
+ $data->pages = array();
+ $stop = $this->pagesStop;
+
+ for ($i = $this->pagesStart; $i <= $stop; $i++)
+ {
+ $offset = ($i - 1) * $this->limit;
+
+ $data->pages[$i] = new JPaginationObject($i, $this->prefix);
+
+ if ($i != $this->pagesCurrent || $this->viewall)
+ {
+ $data->pages[$i]->base = $offset;
+ $data->pages[$i]->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $offset . '&limit=' . $this->limit);
+ }
+ else
+ {
+ $data->pages[$i]->active = true;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Modifies a property of the object, creating it if it does not already exist.
+ *
+ * @param string $property The name of the property.
+ * @param mixed $value The value of the property to set.
+ *
+ * @return void
+ *
+ * @since 3.0
+ * @deprecated 4.0 Access the properties directly.
+ */
+ public function set($property, $value = null)
+ {
+ JLog::add('JPagination::set() is deprecated. Access the properties directly.', JLog::WARNING, 'deprecated');
+
+ if (strpos($property, '.'))
+ {
+ $prop = explode('.', $property);
+ $prop[1] = ucfirst($prop[1]);
+ $property = implode($prop);
+ }
+
+ $this->$property = $value;
+ }
+
+ /**
+ * Returns a property of the object or the default value if the property is not set.
+ *
+ * @param string $property The name of the property.
+ * @param mixed $default The default value.
+ *
+ * @return mixed The value of the property.
+ *
+ * @since 3.0
+ * @deprecated 4.0 Access the properties directly.
+ */
+ public function get($property, $default = null)
+ {
+ JLog::add('JPagination::get() is deprecated. Access the properties directly.', JLog::WARNING, 'deprecated');
+
+ if (strpos($property, '.'))
+ {
+ $prop = explode('.', $property);
+ $prop[1] = ucfirst($prop[1]);
+ $property = implode($prop);
+ }
+
+ if (isset($this->$property))
+ {
+ return $this->$property;
+ }
+
+ return $default;
+ }
+}
diff --git a/plugins/system/t3/includes/joomla30/viewlegacy.php b/plugins/system/t3/includes/joomla30/viewlegacy.php
new file mode 100644
index 0000000..f2fd4f9
--- /dev/null
+++ b/plugins/system/t3/includes/joomla30/viewlegacy.php
@@ -0,0 +1,803 @@
+ array(), 'helper' => array());
+
+ /**
+ * The name of the default template source file.
+ *
+ * @var string
+ */
+ protected $_template = null;
+
+ /**
+ * The output of the template script.
+ *
+ * @var string
+ */
+ protected $_output = null;
+
+ /**
+ * Callback for escaping.
+ *
+ * @var string
+ * @deprecated 13.3
+ */
+ protected $_escape = 'htmlspecialchars';
+
+ /**
+ * Charset to use in escaping mechanisms; defaults to urf8 (UTF-8)
+ *
+ * @var string
+ */
+ protected $_charset = 'UTF-8';
+
+ /**
+ * Constructor
+ *
+ * @param array $config A named configuration array for object construction.
+ * name: the name (optional) of the view (defaults to the view class name suffix).
+ * charset: the character set to use for display
+ * escape: the name (optional) of the function to use for escaping strings
+ * base_path: the parent path (optional) of the views directory (defaults to the component folder)
+ * template_plath: the path (optional) of the layout directory (defaults to base_path + /views/ + view name
+ * helper_path: the path (optional) of the helper files (defaults to base_path + /helpers/)
+ * layout: the layout (optional) to use to display the view
+ *
+ * @since 12.2
+ */
+ public function __construct($config = array())
+ {
+ // Set the view name
+ if (empty($this->_name))
+ {
+ if (array_key_exists('name', $config))
+ {
+ $this->_name = $config['name'];
+ }
+ else
+ {
+ $this->_name = $this->getName();
+ }
+ }
+
+ // Set the charset (used by the variable escaping functions)
+ if (array_key_exists('charset', $config))
+ {
+ JLog::add('Setting a custom charset for escaping is deprecated. Override JViewLegacy::escape() instead.', JLog::WARNING, 'deprecated');
+ $this->_charset = $config['charset'];
+ }
+
+ // User-defined escaping callback
+ if (array_key_exists('escape', $config))
+ {
+ $this->setEscape($config['escape']);
+ }
+
+ // Set a base path for use by the view
+ if (array_key_exists('base_path', $config))
+ {
+ $this->_basePath = $config['base_path'];
+ }
+ else
+ {
+ $this->_basePath = JPATH_COMPONENT;
+ }
+
+ // Set the default template search path
+ if (array_key_exists('template_path', $config))
+ {
+ // User-defined dirs
+ $this->_setPath('template', $config['template_path']);
+ }
+ else
+ {
+ $this->_setPath('template', $this->_basePath . '/views/' . $this->getName() . '/tmpl');
+ }
+
+ // Set the default helper search path
+ if (array_key_exists('helper_path', $config))
+ {
+ // User-defined dirs
+ $this->_setPath('helper', $config['helper_path']);
+ }
+ else
+ {
+ $this->_setPath('helper', $this->_basePath . '/helpers');
+ }
+
+ // Set the layout
+ if (array_key_exists('layout', $config))
+ {
+ $this->setLayout($config['layout']);
+ }
+ else
+ {
+ $this->setLayout('default');
+ }
+
+ $this->baseurl = JURI::base(true);
+ }
+
+ /**
+ * Execute and display a template script.
+ *
+ * @param string $tpl The name of the template file to parse; automatically searches through the template paths.
+ *
+ * @return mixed A string if successful, otherwise a Error object.
+ *
+ * @see fetch()
+ * @since 12.2
+ */
+ public function display($tpl = null)
+ {
+ $result = $this->loadTemplate($tpl);
+ if ($result instanceof Exception)
+ {
+ return $result;
+ }
+
+ echo $result;
+ }
+
+ /**
+ * Assigns variables to the view script via differing strategies.
+ *
+ * This method is overloaded; you can assign all the properties of
+ * an object, an associative array, or a single value by name.
+ *
+ * You are not allowed to set variables that begin with an underscore;
+ * these are either private properties for JView or private variables
+ * within the template script itself.
+ *
+ *
+ * $view = new JView;
+ *
+ * // Assign directly
+ * $view->var1 = 'something';
+ * $view->var2 = 'else';
+ *
+ * // Assign by name and value
+ * $view->assign('var1', 'something');
+ * $view->assign('var2', 'else');
+ *
+ * // Assign by assoc-array
+ * $ary = array('var1' => 'something', 'var2' => 'else');
+ * $view->assign($obj);
+ *
+ * // Assign by object
+ * $obj = new stdClass;
+ * $obj->var1 = 'something';
+ * $obj->var2 = 'else';
+ * $view->assign($obj);
+ *
+ *
+ *
+ * @return boolean True on success, false on failure.
+ *
+ * @deprecated 13.3 Use native PHP syntax.
+ */
+ public function assign()
+ {
+ JLog::add(__METHOD__ . ' is deprecated. Use native PHP syntax.', JLog::WARNING, 'deprecated');
+
+ // Get the arguments; there may be 1 or 2.
+ $arg0 = @func_get_arg(0);
+ $arg1 = @func_get_arg(1);
+
+ // Assign by object
+ if (is_object($arg0))
+ {
+ // Assign public properties
+ foreach (get_object_vars($arg0) as $key => $val)
+ {
+ if (substr($key, 0, 1) != '_')
+ {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // Assign by associative array
+ if (is_array($arg0))
+ {
+ foreach ($arg0 as $key => $val)
+ {
+ if (substr($key, 0, 1) != '_')
+ {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // Assign by string name and mixed value.
+
+ // We use array_key_exists() instead of isset() because isset()
+ // fails if the value is set to null.
+ if (is_string($arg0) && substr($arg0, 0, 1) != '_' && func_num_args() > 1)
+ {
+ $this->$arg0 = $arg1;
+ return true;
+ }
+
+ // $arg0 was not object, array, or string.
+ return false;
+ }
+
+ /**
+ * Assign variable for the view (by reference).
+ *
+ * You are not allowed to set variables that begin with an underscore;
+ * these are either private properties for JView or private variables
+ * within the template script itself.
+ *
+ *
+ * $view = new JView;
+ *
+ * // Assign by name and value
+ * $view->assignRef('var1', $ref);
+ *
+ * // Assign directly
+ * $view->ref = &$var1;
+ *
+ *
+ * @param string $key The name for the reference in the view.
+ * @param mixed &$val The referenced variable.
+ *
+ * @return boolean True on success, false on failure.
+ *
+ * @since 12.2
+ * @deprecated 13.3 Use native PHP syntax.
+ */
+ public function assignRef($key, &$val)
+ {
+ JLog::add(__METHOD__ . ' is deprecated. Use native PHP syntax.', JLog::WARNING, 'deprecated');
+
+ if (is_string($key) && substr($key, 0, 1) != '_')
+ {
+ $this->$key = &$val;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Escapes a value for output in a view script.
+ *
+ * If escaping mechanism is either htmlspecialchars or htmlentities, uses
+ * {@link $_encoding} setting.
+ *
+ * @param mixed $var The output to escape.
+ *
+ * @return mixed The escaped value.
+ *
+ * @since 12.2
+ */
+ public function escape($var)
+ {
+ if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities')))
+ {
+ return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_charset);
+ }
+
+ return call_user_func($this->_escape, $var);
+ }
+
+ /**
+ * Method to get data from a registered model or a property of the view
+ *
+ * @param string $property The name of the method to call on the model or the property to get
+ * @param string $default The name of the model to reference or the default value [optional]
+ *
+ * @return mixed The return value of the method
+ *
+ * @since 12.2
+ */
+ public function get($property, $default = null)
+ {
+ // If $model is null we use the default model
+ if (is_null($default))
+ {
+ $model = $this->_defaultModel;
+ }
+ else
+ {
+ $model = strtolower($default);
+ }
+
+ // First check to make sure the model requested exists
+ if (isset($this->_models[$model]))
+ {
+ // Model exists, let's build the method name
+ $method = 'get' . ucfirst($property);
+
+ // Does the method exist?
+ if (method_exists($this->_models[$model], $method))
+ {
+ // The method exists, let's call it and return what we get
+ $result = $this->_models[$model]->$method();
+ return $result;
+ }
+
+ }
+
+ // Degrade to JObject::get
+ $result = parent::get($property, $default);
+
+ return $result;
+ }
+
+ /**
+ * Method to get the model object
+ *
+ * @param string $name The name of the model (optional)
+ *
+ * @return mixed JModelLegacy object
+ *
+ * @since 12.2
+ */
+ public function getModel($name = null)
+ {
+ if ($name === null)
+ {
+ $name = $this->_defaultModel;
+ }
+ return $this->_models[strtolower($name)];
+ }
+
+ /**
+ * Get the layout.
+ *
+ * @return string The layout name
+ */
+ public function getLayout()
+ {
+ return $this->_layout;
+ }
+
+ /**
+ * Get the layout template.
+ *
+ * @return string The layout template name
+ */
+ public function getLayoutTemplate()
+ {
+ return $this->_layoutTemplate;
+ }
+
+ /**
+ * Method to get the view name
+ *
+ * The model name by default parsed using the classname, or it can be set
+ * by passing a $config['name'] in the class constructor
+ *
+ * @return string The name of the model
+ *
+ * @since 12.2
+ * @throws Exception
+ */
+ public function getName()
+ {
+ if (empty($this->_name))
+ {
+ $classname = get_class($this);
+ $viewpos = strpos($classname, 'View');
+
+ if ($viewpos === false)
+ {
+ throw new Exception(JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME'), 500);
+ }
+
+ $this->_name = strtolower(substr($classname, $viewpos + 4));
+ }
+
+ return $this->_name;
+ }
+
+ /**
+ * Method to add a model to the view. We support a multiple model single
+ * view system by which models are referenced by classname. A caveat to the
+ * classname referencing is that any classname prepended by JModel will be
+ * referenced by the name without JModel, eg. JModelCategory is just
+ * Category.
+ *
+ * @param JModelLegacy $model The model to add to the view.
+ * @param boolean $default Is this the default model?
+ *
+ * @return object The added model.
+ *
+ * @since 12.2
+ */
+ public function setModel($model, $default = false)
+ {
+ $name = strtolower($model->getName());
+ $this->_models[$name] = $model;
+
+ if ($default)
+ {
+ $this->_defaultModel = $name;
+ }
+ return $model;
+ }
+
+ /**
+ * Sets the layout name to use
+ *
+ * @param string $layout The layout name or a string in format :
+ *
+ * @return string Previous value.
+ *
+ * @since 12.2
+ */
+ public function setLayout($layout)
+ {
+ $previous = $this->_layout;
+ if (strpos($layout, ':') === false)
+ {
+ $this->_layout = $layout;
+ }
+ else
+ {
+ // Convert parameter to array based on :
+ $temp = explode(':', $layout);
+ $this->_layout = $temp[1];
+
+ // Set layout template
+ $this->_layoutTemplate = $temp[0];
+ }
+
+ return $previous;
+ }
+
+ /**
+ * Allows a different extension for the layout files to be used
+ *
+ * @param string $value The extension.
+ *
+ * @return string Previous value
+ *
+ * @since 12.2
+ */
+ public function setLayoutExt($value)
+ {
+ $previous = $this->_layoutExt;
+ if ($value = preg_replace('#[^A-Za-z0-9]#', '', trim($value)))
+ {
+ $this->_layoutExt = $value;
+ }
+
+ return $previous;
+ }
+
+ /**
+ * Sets the _escape() callback.
+ *
+ * @param mixed $spec The callback for _escape() to use.
+ *
+ * @return void
+ *
+ * @since 12.2
+ * @deprecated 13.3 Override JViewLegacy::escape() instead.
+ */
+ public function setEscape($spec)
+ {
+ JLog::add(__METHOD__ . ' is deprecated. Override JViewLegacy::escape() instead.', JLog::WARNING, 'deprecated');
+
+ $this->_escape = $spec;
+ }
+
+ /**
+ * Adds to the stack of view script paths in LIFO order.
+ *
+ * @param mixed $path A directory path or an array of paths.
+ *
+ * @return void
+ *
+ * @since 12.2
+ */
+ public function addTemplatePath($path)
+ {
+ $this->_addPath('template', $path);
+ }
+
+ /**
+ * Adds to the stack of helper script paths in LIFO order.
+ *
+ * @param mixed $path A directory path or an array of paths.
+ *
+ * @return void
+ *
+ * @since 12.2
+ */
+ public function addHelperPath($path)
+ {
+ $this->_addPath('helper', $path);
+ }
+
+ /**
+ * Load a template file -- first look in the templates folder for an override
+ *
+ * @param string $tpl The name of the template source file; automatically searches the template paths and compiles as needed.
+ *
+ * @return string The output of the the template script.
+ *
+ * @since 12.2
+ * @throws Exception
+ */
+ public function loadTemplate($tpl = null)
+ {
+ // Clear prior output
+ $this->_output = null;
+
+ $template = JFactory::getApplication()->getTemplate();
+ $layout = $this->getLayout();
+ $layoutTemplate = $this->getLayoutTemplate();
+
+ // Create the template file name based on the layout
+ $file = isset($tpl) ? $layout . '_' . $tpl : $layout;
+
+ // Clean the file name
+ $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
+ $tpl = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl;
+
+ // Load the language file for the template
+ $lang = JFactory::getLanguage();
+ $lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
+ || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, false)
+ || $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
+ || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", $lang->getDefault(), false, false);
+
+ // Change the template folder if alternative layout is in different template
+ if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template)
+ {
+ $this->_path['template'] = str_replace($template, $layoutTemplate, $this->_path['template']);
+ }
+
+ // Load the template script
+ jimport('joomla.filesystem.path');
+ $filetofind = $this->_createFileName('template', array('name' => $file));
+ $this->_template = JPath::find($this->_path['template'], $filetofind);
+
+ // If alternate layout can't be found, fall back to default layout
+ if ($this->_template == false)
+ {
+ $filetofind = $this->_createFileName('', array('name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl)));
+ $this->_template = JPath::find($this->_path['template'], $filetofind);
+ }
+
+ if ($this->_template != false)
+ {
+ // Unset so as not to introduce into template scope
+ unset($tpl);
+ unset($file);
+
+ // Never allow a 'this' property
+ if (isset($this->this))
+ {
+ unset($this->this);
+ }
+
+ // Start capturing output into a buffer
+ ob_start();
+
+ // Include the requested template filename in the local scope
+ // (this will execute the view logic).
+ include $this->_template;
+
+ // Done with the requested template; get the buffer and
+ // clear it.
+ $this->_output = ob_get_contents();
+ ob_end_clean();
+
+ return $this->_output;
+ }
+ else
+ {
+ throw new Exception(JText::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500);
+ }
+ }
+
+ /**
+ * Load a helper file
+ *
+ * @param string $hlp The name of the helper source file automatically searches the helper paths and compiles as needed.
+ *
+ * @return void
+ *
+ * @since 12.2
+ */
+ public function loadHelper($hlp = null)
+ {
+ // Clean the file name
+ $file = preg_replace('/[^A-Z0-9_\.-]/i', '', $hlp);
+
+ // Load the template script
+ jimport('joomla.filesystem.path');
+ $helper = JPath::find($this->_path['helper'], $this->_createFileName('helper', array('name' => $file)));
+
+ if ($helper != false)
+ {
+ // Include the requested template filename in the local scope
+ include_once $helper;
+ }
+ }
+
+ /**
+ * Sets an entire array of search paths for templates or resources.
+ *
+ * @param string $type The type of path to set, typically 'template'.
+ * @param mixed $path The new search path, or an array of search paths. If null or false, resets to the current directory only.
+ *
+ * @return void
+ *
+ * @since 12.2
+ */
+ protected function _setPath($type, $path)
+ {
+ $component = JApplicationHelper::getComponentName();
+ $app = JFactory::getApplication();
+
+ // Clear out the prior search dirs
+ $this->_path[$type] = array();
+
+ // Actually add the user-specified directories
+ $this->_addPath($type, $path);
+
+ // Always add the fallback directories as last resort
+ switch (strtolower($type))
+ {
+ case 'template':
+ // Set the alternative template search dir
+ if (isset($app))
+ {
+ $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
+
+ //if it is T3 template, update search path for template
+ $this->_addPath('template', T3_PATH . '/html/' . $component . '/' . $this->getName());
+
+ $fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
+ $this->_addPath('template', $fallback);
+
+ //search path for user custom folder
+ if (!defined('T3_LOCAL_DISABLED')) $this->_addPath('template', T3_LOCAL_PATH . '/html/' . $component . '/' . $this->getName());
+ }
+ break;
+ }
+ }
+
+ /**
+ * Adds to the search path for templates and resources.
+ *
+ * @param string $type The type of path to add.
+ * @param mixed $path The directory or stream, or an array of either, to search.
+ *
+ * @return void
+ *
+ * @since 12.2
+ */
+ protected function _addPath($type, $path)
+ {
+ // Just force to array
+ settype($path, 'array');
+
+ // Loop through the path directories
+ foreach ($path as $dir)
+ {
+ // No surrounding spaces allowed!
+ $dir = trim($dir);
+
+ // Add trailing separators as needed
+ if (substr($dir, -1) != DIRECTORY_SEPARATOR)
+ {
+ // Directory
+ $dir .= DIRECTORY_SEPARATOR;
+ }
+
+ // Add to the top of the search dirs
+ array_unshift($this->_path[$type], $dir);
+ }
+ }
+
+ /**
+ * Create the filename for a resource
+ *
+ * @param string $type The resource type to create the filename for
+ * @param array $parts An associative array of filename information
+ *
+ * @return string The filename
+ *
+ * @since 12.2
+ */
+ protected function _createFileName($type, $parts = array())
+ {
+ $filename = '';
+
+ switch ($type)
+ {
+ case 'template':
+ $filename = strtolower($parts['name']) . '.' . $this->_layoutExt;
+ break;
+
+ default:
+ $filename = strtolower($parts['name']) . '.php';
+ break;
+ }
+ return $filename;
+ }
+}
diff --git a/plugins/system/t3/includes/lessphp/legacy.less.php b/plugins/system/t3/includes/lessphp/legacy.less.php
new file mode 100644
index 0000000..5e89a18
--- /dev/null
+++ b/plugins/system/t3/includes/lessphp/legacy.less.php
@@ -0,0 +1,35 @@
+setImportDir(array_keys($importdirs));
+ $parser->setPreserveComments(true);
+ $output = $parser->compile($source);
+ return $output;
+ }
+}
diff --git a/plugins/system/t3/includes/lessphp/less.php b/plugins/system/t3/includes/lessphp/less.php
new file mode 100644
index 0000000..032fa5f
--- /dev/null
+++ b/plugins/system/t3/includes/lessphp/less.php
@@ -0,0 +1,37 @@
+SetImportDirs($importdirs);
+ $parser->parse($source);
+ $output = $parser->getCss();
+ return $output;
+ }
+}
diff --git a/plugins/system/t3/includes/lessphp/less/cache.php b/plugins/system/t3/includes/lessphp/less/cache.php
new file mode 100644
index 0000000..926104f
--- /dev/null
+++ b/plugins/system/t3/includes/lessphp/less/cache.php
@@ -0,0 +1,194 @@
+ $uri_or_less ){
+
+ //treat as less markup if there are newline characters
+ if( strpos($uri_or_less,"\n") !== false ){
+ $parser->Parse( $uri_or_less );
+ continue;
+ }
+
+ $parser->ParseFile( $file_path, $uri_or_less );
+ }
+
+ $compiled = $parser->getCss();
+
+
+ $less_files = $parser->allParsedFiles();
+
+ return $compiled;
+ }
+
+
+ private static function CompiledName( $files ){
+
+ //save the file list
+ $temp = array(Less_Version::cache_version);
+ foreach($files as $file){
+ $temp[] = filemtime($file)."\t".filesize($file)."\t".$file;
+ }
+
+ return 'lessphp_'.sha1(json_encode($temp)).'.css';
+ }
+
+
+ public static function SetCacheDir( $dir ){
+ Less_Cache::$cache_dir = $dir;
+ }
+
+ public static function CheckCacheDir(){
+
+ Less_Cache::$cache_dir = str_replace('\\','/',Less_Cache::$cache_dir);
+ Less_Cache::$cache_dir = rtrim(Less_Cache::$cache_dir,'/').'/';
+
+ if( !file_exists(Less_Cache::$cache_dir) ){
+ if( !mkdir(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir);
+ }
+
+ }elseif( !is_dir(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir);
+
+ }elseif( !is_writable(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir);
+
+ }
+
+ }
+
+
+ public static function CleanCache(){
+ static $clean = false;
+
+ if( $clean ){
+ return;
+ }
+
+ $files = scandir(Less_Cache::$cache_dir);
+ if( $files ){
+ $check_time = time() - 604800;
+ foreach($files as $file){
+ if( strpos($file,'lessphp_') !== 0 ){
+ continue;
+ }
+ $full_path = Less_Cache::$cache_dir.'/'.$file;
+ if( filemtime($full_path) > $check_time ){
+ continue;
+ }
+ unlink($full_path);
+ }
+ }
+
+ $clean = true;
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/lessphp/less/less.php b/plugins/system/t3/includes/lessphp/less/less.php
new file mode 100644
index 0000000..fac90cc
--- /dev/null
+++ b/plugins/system/t3/includes/lessphp/less/less.php
@@ -0,0 +1,10176 @@
+ false, // option - whether to compress
+ 'strictUnits' => false, // whether units need to evaluate correctly
+ 'strictMath' => false, // whether math has to be within parenthesis
+ 'relativeUrls' => true, // option - whether to adjust URL's to be relative
+ 'urlArgs' => array(), // whether to add args into url tokens
+ 'numPrecision' => 8,
+
+ 'import_dirs' => array(),
+ 'import_callback' => null,
+ 'cache_dir' => null,
+ 'cache_method' => 'php', //false, 'serialize', 'php', 'var_export';
+
+ 'sourceMap' => false, // whether to output a source map
+ 'sourceMapBasepath' => null,
+ 'sourceMapWriteTo' => null,
+ 'sourceMapURL' => null,
+
+ 'plugins' => array(),
+
+ );
+
+ public static $options = array();
+
+
+ private $input; // Less input string
+ private $input_len; // input string length
+ private $pos; // current index in `input`
+ private $saveStack = array(); // holds state for backtracking
+ private $furthest;
+
+ /**
+ * @var Less_Environment
+ */
+ private $env;
+
+ private $rules = array();
+
+ private static $imports = array();
+
+ public static $has_extends = false;
+
+ public static $next_id = 0;
+
+ /**
+ * Filename to contents of all parsed the files
+ *
+ * @var array
+ */
+ public static $contentsMap = array();
+
+
+ /**
+ * @param Less_Environment|array|null $env
+ */
+ public function __construct( $env = null ){
+
+ // Top parser on an import tree must be sure there is one "env"
+ // which will then be passed around by reference.
+ if( $env instanceof Less_Environment ){
+ $this->env = $env;
+ }else{
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->Reset( $env );
+ }
+
+ }
+
+
+ /**
+ * Reset the parser state completely
+ *
+ */
+ public function Reset( $options = null ){
+ $this->rules = array();
+ self::$imports = array();
+ self::$has_extends = false;
+ self::$imports = array();
+ self::$contentsMap = array();
+
+ $this->env = new Less_Environment($options);
+ $this->env->Init();
+
+ //set new options
+ if( is_array($options) ){
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->SetOptions($options);
+ }
+ }
+
+ /**
+ * Set one or more compiler options
+ * options: import_dirs, cache_dir, cache_method
+ *
+ */
+ public function SetOptions( $options ){
+ foreach($options as $option => $value){
+ $this->SetOption($option,$value);
+ }
+ }
+
+ /**
+ * Set one compiler option
+ *
+ */
+ public function SetOption($option,$value){
+
+ switch($option){
+
+ case 'import_dirs':
+ $this->SetImportDirs($value);
+ return;
+
+ case 'cache_dir':
+ if( is_string($value) ){
+ Less_Cache::SetCacheDir($value);
+ Less_Cache::CheckCacheDir();
+ }
+ return;
+ }
+
+ Less_Parser::$options[$option] = $value;
+ }
+
+
+
+
+ /**
+ * Get the current css buffer
+ *
+ * @return string
+ */
+ public function getCss(){
+
+ $precision = ini_get('precision');
+ @ini_set('precision',16);
+ $locale = setlocale(LC_NUMERIC, 0);
+ setlocale(LC_NUMERIC, "C");
+
+
+ $root = new Less_Tree_Ruleset(array(), $this->rules );
+ $root->root = true;
+ $root->firstRoot = true;
+
+
+ $this->PreVisitors($root);
+
+ self::$has_extends = false;
+ $evaldRoot = $root->compile($this->env);
+
+
+
+ $this->PostVisitors($evaldRoot);
+
+ if( Less_Parser::$options['sourceMap'] ){
+ $generator = new Less_SourceMap_Generator($evaldRoot, Less_Parser::$contentsMap, Less_Parser::$options );
+ // will also save file
+ // FIXME: should happen somewhere else?
+ $css = $generator->generateCSS();
+ }else{
+ $css = $evaldRoot->toCSS();
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ $css = preg_replace('/(^(\s)+)|((\s)+$)/', '', $css);
+ }
+
+ //reset php settings
+ @ini_set('precision',$precision);
+ setlocale(LC_NUMERIC, $locale);
+
+ return $css;
+ }
+
+ /**
+ * Run pre-compile visitors
+ *
+ */
+ private function PreVisitors($root){
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( !empty($plugin->isPreEvalVisitor) ){
+ $plugin->run($root);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Run post-compile visitors
+ *
+ */
+ private function PostVisitors($evaldRoot){
+
+ $visitors = array();
+ $visitors[] = new Less_Visitor_joinSelector();
+ if( self::$has_extends ){
+ $visitors[] = new Less_Visitor_processExtends();
+ }
+ $visitors[] = new Less_Visitor_toCSS();
+
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( property_exists($plugin,'isPreEvalVisitor') && $plugin->isPreEvalVisitor ){
+ continue;
+ }
+
+ if( property_exists($plugin,'isPreVisitor') && $plugin->isPreVisitor ){
+ array_unshift( $visitors, $plugin);
+ }else{
+ $visitors[] = $plugin;
+ }
+ }
+ }
+
+
+ for($i = 0; $i < count($visitors); $i++ ){
+ $visitors[$i]->run($evaldRoot);
+ }
+
+ }
+
+
+ /**
+ * Parse a Less string into css
+ *
+ * @param string $str The string to convert
+ * @param string $uri_root The url of the file
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parse( $str, $file_uri = null ){
+
+ if( !$file_uri ){
+ $uri_root = '';
+ $filename = 'anonymous-file-'.Less_Parser::$next_id++.'.less';
+ }else{
+ $file_uri = self::WinPath($file_uri);
+ $filename = basename($file_uri);
+ $uri_root = dirname($file_uri);
+ }
+
+ $previousFileInfo = $this->env->currentFileInfo;
+ $uri_root = self::WinPath($uri_root);
+ $this->SetFileInfo($filename, $uri_root);
+
+ $this->input = $str;
+ $this->_parse();
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Parse a Less string from a given file
+ *
+ * @throws Less_Exception_Parser
+ * @param string $filename The file to parse
+ * @param string $uri_root The url of the file
+ * @param bool $returnRoot Indicates whether the return value should be a css string a root node
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parseFile( $filename, $uri_root = '', $returnRoot = false){
+
+ if( !file_exists($filename) ){
+ $this->Error(sprintf('File `%s` not found.', $filename));
+ }
+
+
+ // fix uri_root?
+ // Instead of The mixture of file path for the first argument and directory path for the second argument has bee
+ if( !$returnRoot && !empty($uri_root) && basename($uri_root) == basename($filename) ){
+ $uri_root = dirname($uri_root);
+ }
+
+
+ $previousFileInfo = $this->env->currentFileInfo;
+ $filename = self::WinPath($filename);
+ $uri_root = self::WinPath($uri_root);
+ $this->SetFileInfo($filename, $uri_root);
+
+ self::AddParsedFile($filename);
+
+ if( $returnRoot ){
+ $rules = $this->GetRules( $filename );
+ $return = new Less_Tree_Ruleset(array(), $rules );
+ }else{
+ $this->_parse( $filename );
+ $return = $this;
+ }
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Allows a user to set variables values
+ * @param array $vars
+ * @return Less_Parser
+ */
+ public function ModifyVars( $vars ){
+
+ $this->input = $this->serializeVars( $vars );
+ $this->_parse();
+
+ return $this;
+ }
+
+
+ /**
+ * @param string $filename
+ */
+ public function SetFileInfo( $filename, $uri_root = ''){
+
+ $filename = Less_Environment::normalizePath($filename);
+ $dirname = preg_replace('/[^\/\\\\]*$/','',$filename);
+
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+
+ $currentFileInfo = array();
+
+ //entry info
+ if( isset($this->env->currentFileInfo) ){
+ $currentFileInfo['entryPath'] = $this->env->currentFileInfo['entryPath'];
+ $currentFileInfo['entryUri'] = $this->env->currentFileInfo['entryUri'];
+ $currentFileInfo['rootpath'] = $this->env->currentFileInfo['rootpath'];
+
+ }else{
+ $currentFileInfo['entryPath'] = $dirname;
+ $currentFileInfo['entryUri'] = $uri_root;
+ $currentFileInfo['rootpath'] = $dirname;
+ }
+
+ $currentFileInfo['currentDirectory'] = $dirname;
+ $currentFileInfo['currentUri'] = $uri_root.basename($filename);
+ $currentFileInfo['filename'] = $filename;
+ $currentFileInfo['uri_root'] = $uri_root;
+
+
+ //inherit reference
+ if( isset($this->env->currentFileInfo['reference']) && $this->env->currentFileInfo['reference'] ){
+ $currentFileInfo['reference'] = true;
+ }
+
+ $this->env->currentFileInfo = $currentFileInfo;
+ }
+
+
+ /**
+ * @deprecated 1.5.1.2
+ *
+ */
+ public function SetCacheDir( $dir ){
+
+ if( !file_exists($dir) ){
+ if( mkdir($dir) ){
+ return true;
+ }
+ throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.$dir);
+
+ }elseif( !is_dir($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.$dir);
+
+ }elseif( !is_writable($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.$dir);
+
+ }else{
+ $dir = self::WinPath($dir);
+ Less_Cache::$cache_dir = rtrim($dir,'/').'/';
+ return true;
+ }
+ }
+
+
+ /**
+ * Set a list of directories or callbacks the parser should use for determining import paths
+ *
+ * @param array $dirs
+ */
+ public function SetImportDirs( $dirs ){
+ Less_Parser::$options['import_dirs'] = array();
+
+ foreach($dirs as $path => $uri_root){
+
+ $path = self::WinPath($path);
+ if( !empty($path) ){
+ $path = rtrim($path,'/').'/';
+ }
+
+ if ( !is_callable($uri_root) ){
+ $uri_root = self::WinPath($uri_root);
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+ }
+
+ Less_Parser::$options['import_dirs'][$path] = $uri_root;
+ }
+ }
+
+ /**
+ * @param string $file_path
+ */
+ private function _parse( $file_path = null ){
+ $this->rules = array_merge($this->rules, $this->GetRules( $file_path ));
+ }
+
+
+ /**
+ * Return the results of parsePrimary for $file_path
+ * Use cache and save cached results if possible
+ *
+ * @param string|null $file_path
+ */
+ private function GetRules( $file_path ){
+
+ $this->SetInput($file_path);
+
+ $cache_file = $this->CacheFile( $file_path );
+ if( $cache_file && file_exists($cache_file) ){
+ switch(Less_Parser::$options['cache_method']){
+
+ // Using serialize
+ // Faster but uses more memory
+ case 'serialize':
+ $cache = unserialize(file_get_contents($cache_file));
+ if( $cache ){
+ touch($cache_file);
+ $this->UnsetInput();
+ return $cache;
+ }
+ break;
+
+
+ // Using generated php code
+ case 'var_export':
+ case 'php':
+ $this->UnsetInput();
+ return include($cache_file);
+ }
+ }
+
+ $rules = $this->parsePrimary();
+
+ if( $this->pos < $this->input_len ){
+ throw new Less_Exception_Chunk($this->input, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ $this->UnsetInput();
+
+
+ //save the cache
+ if( $cache_file ){
+
+ //msg('write cache file');
+ switch(Less_Parser::$options['cache_method']){
+ case 'serialize':
+ file_put_contents( $cache_file, serialize($rules) );
+ break;
+ case 'php':
+ file_put_contents( $cache_file, '' );
+ break;
+ case 'var_export':
+ //Requires __set_state()
+ file_put_contents( $cache_file, '' );
+ break;
+ }
+
+ Less_Cache::CleanCache();
+ }
+
+ return $rules;
+ }
+
+
+ /**
+ * Set up the input buffer
+ *
+ */
+ public function SetInput( $file_path ){
+
+ if( $file_path ){
+ $this->input = file_get_contents( $file_path );
+ }
+
+ $this->pos = $this->furthest = 0;
+
+ // Remove potential UTF Byte Order Mark
+ $this->input = preg_replace('/\\G\xEF\xBB\xBF/', '', $this->input);
+ $this->input_len = strlen($this->input);
+
+
+ if( Less_Parser::$options['sourceMap'] && $this->env->currentFileInfo ){
+ $uri = $this->env->currentFileInfo['currentUri'];
+ Less_Parser::$contentsMap[$uri] = $this->input;
+ }
+
+ }
+
+
+ /**
+ * Free up some memory
+ *
+ */
+ public function UnsetInput(){
+ unset($this->input, $this->pos, $this->input_len, $this->furthest);
+ $this->saveStack = array();
+ }
+
+
+ public function CacheFile( $file_path ){
+
+ if( $file_path && Less_Parser::$options['cache_method'] && Less_Cache::$cache_dir ){
+
+ $env = get_object_vars($this->env);
+ unset($env['frames']);
+
+ $parts = array();
+ $parts[] = $file_path;
+ $parts[] = filesize( $file_path );
+ $parts[] = filemtime( $file_path );
+ $parts[] = $env;
+ $parts[] = Less_Version::cache_version;
+ $parts[] = Less_Parser::$options['cache_method'];
+ return Less_Cache::$cache_dir.'lessphp_'.base_convert( sha1(json_encode($parts) ), 16, 36).'.lesscache';
+ }
+ }
+
+
+ static function AddParsedFile($file){
+ self::$imports[] = $file;
+ }
+
+ static function AllParsedFiles(){
+ return self::$imports;
+ }
+
+ /**
+ * @param string $file
+ */
+ static function FileParsed($file){
+ return in_array($file,self::$imports);
+ }
+
+
+ function save() {
+ $this->saveStack[] = $this->pos;
+ }
+
+ private function restore() {
+ $this->pos = array_pop($this->saveStack);
+ }
+
+ private function forget(){
+ array_pop($this->saveStack);
+ }
+
+
+ private function isWhitespace($offset = 0) {
+ return preg_match('/\s/',$this->input[ $this->pos + $offset]);
+ }
+
+ /**
+ * Parse from a token, regexp or string, and move forward if match
+ *
+ * @param array $toks
+ * @return array
+ */
+ private function match($toks){
+
+ // The match is confirmed, add the match length to `this::pos`,
+ // and consume any extra white-space characters (' ' || '\n')
+ // which come after that. The reason for this is that LeSS's
+ // grammar is mostly white-space insensitive.
+ //
+
+ foreach($toks as $tok){
+
+ $char = $tok[0];
+
+ if( $char === '/' ){
+ $match = $this->MatchReg($tok);
+
+ if( $match ){
+ return count($match) === 1 ? $match[0] : $match;
+ }
+
+ }elseif( $char === '#' ){
+ $match = $this->MatchChar($tok[1]);
+
+ }else{
+ // Non-terminal, match using a function call
+ $match = $this->$tok();
+
+ }
+
+ if( $match ){
+ return $match;
+ }
+ }
+ }
+
+ /**
+ * @param string[] $toks
+ *
+ * @return string
+ */
+ private function MatchFuncs($toks){
+
+ foreach($toks as $tok){
+ $match = $this->$tok();
+ if( $match ){
+ return $match;
+ }
+ }
+
+ }
+
+ // Match a single character in the input,
+ private function MatchChar($tok){
+ if( ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok) ){
+ $this->skipWhitespace(1);
+ return $tok;
+ }
+ }
+
+ // Match a regexp from the current start point
+ private function MatchReg($tok){
+
+ if( preg_match($tok, $this->input, $match, 0, $this->pos) ){
+ $this->skipWhitespace(strlen($match[0]));
+ return $match;
+ }
+ }
+
+
+ /**
+ * Same as match(), but don't change the state of the parser,
+ * just return the match.
+ *
+ * @param string $tok
+ * @return integer
+ */
+ public function PeekReg($tok){
+ return preg_match($tok, $this->input, $match, 0, $this->pos);
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function PeekChar($tok){
+ //return ($this->input[$this->pos] === $tok );
+ return ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok );
+ }
+
+
+ /**
+ * @param integer $length
+ */
+ public function skipWhitespace($length){
+
+ $this->pos += $length;
+
+ for(; $this->pos < $this->input_len; $this->pos++ ){
+ $c = $this->input[$this->pos];
+
+ if( ($c !== "\n") && ($c !== "\r") && ($c !== "\t") && ($c !== ' ') ){
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * @param string $tok
+ * @param string|null $msg
+ */
+ public function expect($tok, $msg = NULL) {
+ $result = $this->match( array($tok) );
+ if (!$result) {
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ } else {
+ return $result;
+ }
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function expectChar($tok, $msg = null ){
+ $result = $this->MatchChar($tok);
+ if( !$result ){
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ }else{
+ return $result;
+ }
+ }
+
+ //
+ // Here in, the parsing rules/functions
+ //
+ // The basic structure of the syntax tree generated is as follows:
+ //
+ // Ruleset -> Rule -> Value -> Expression -> Entity
+ //
+ // Here's some LESS code:
+ //
+ // .class {
+ // color: #fff;
+ // border: 1px solid #000;
+ // width: @w + 4px;
+ // > .child {...}
+ // }
+ //
+ // And here's what the parse tree might look like:
+ //
+ // Ruleset (Selector '.class', [
+ // Rule ("color", Value ([Expression [Color #fff]]))
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
+ // Ruleset (Selector [Element '>', '.child'], [...])
+ // ])
+ //
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
+ // first, before parsing, that's when we use `peek()`.
+ //
+
+ //
+ // The `primary` rule is the *entry* and *exit* point of the parser.
+ // The rules here can appear at any level of the parse tree.
+ //
+ // The recursive nature of the grammar is an interplay between the `block`
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
+ // as represented by this simplified grammar:
+ //
+ // primary → (ruleset | rule)+
+ // ruleset → selector+ block
+ // block → '{' primary '}'
+ //
+ // Only at one point is the primary rule not called from the
+ // block rule: at the root level.
+ //
+ private function parsePrimary(){
+ $root = array();
+
+ while( true ){
+
+ if( $this->pos >= $this->input_len ){
+ break;
+ }
+
+ $node = $this->parseExtend(true);
+ if( $node ){
+ $root = array_merge($root,$node);
+ continue;
+ }
+
+ //$node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseDirective'));
+ $node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseNameValue', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseRulesetCall', 'parseDirective'));
+
+ if( $node ){
+ $root[] = $node;
+ }elseif( !$this->MatchReg('/\\G[\s\n;]+/') ){
+ break;
+ }
+
+ if( $this->PeekChar('}') ){
+ break;
+ }
+ }
+
+ return $root;
+ }
+
+
+
+ // We create a Comment node for CSS comments `/* */`,
+ // but keep the LeSS comments `//` silent, by just skipping
+ // over them.
+ private function parseComment(){
+
+ if( $this->input[$this->pos] !== '/' ){
+ return;
+ }
+
+ if( $this->input[$this->pos+1] === '/' ){
+ $match = $this->MatchReg('/\\G\/\/.*/');
+ return $this->NewObj4('Less_Tree_Comment',array($match[0], true, $this->pos, $this->env->currentFileInfo));
+ }
+
+ //$comment = $this->MatchReg('/\\G\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/');
+ $comment = $this->MatchReg('/\\G\/\*(?s).*?\*+\/\n?/');//not the same as less.js to prevent fatal errors
+ if( $comment ){
+ return $this->NewObj4('Less_Tree_Comment',array($comment[0], false, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+
+ private function parseComments(){
+ $comments = array();
+
+ while( $this->pos < $this->input_len ){
+ $comment = $this->parseComment();
+ if( !$comment ){
+ break;
+ }
+
+ $comments[] = $comment;
+ }
+
+ return $comments;
+ }
+
+
+
+ //
+ // A string, which supports escaping " and '
+ //
+ // "milky way" 'he\'s the one!'
+ //
+ private function parseEntitiesQuoted() {
+ $j = $this->pos;
+ $e = false;
+ $index = $this->pos;
+
+ if( $this->input[$this->pos] === '~' ){
+ $j++;
+ $e = true; // Escaped strings
+ }
+
+ if( $this->input[$j] != '"' && $this->input[$j] !== "'" ){
+ return;
+ }
+
+ if ($e) {
+ $this->MatchChar('~');
+ }
+ $str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.)*)"|\'((?:[^\'\\\\\r\n]|\\\\.)*)\'/');
+ if( $str ){
+ $result = $str[0][0] == '"' ? $str[1] : $str[2];
+ return $this->NewObj5('Less_Tree_Quoted',array($str[0], $result, $e, $index, $this->env->currentFileInfo) );
+ }
+ return;
+ }
+
+
+ //
+ // A catch-all word, such as:
+ //
+ // black border-collapse
+ //
+ private function parseEntitiesKeyword(){
+
+ //$k = $this->MatchReg('/\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ $k = $this->MatchReg('/\\G%|\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ if( $k ){
+ $k = $k[0];
+ $color = $this->fromKeyword($k);
+ if( $color ){
+ return $color;
+ }
+ return $this->NewObj1('Less_Tree_Keyword',$k);
+ }
+ }
+
+ // duplicate of Less_Tree_Color::FromKeyword
+ private function FromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return $this->NewObj1('Less_Tree_Color',substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return $this->NewObj3('Less_Tree_Color', array( array(0, 0, 0), 0, true));
+ }
+ }
+
+ //
+ // A function call
+ //
+ // rgb(255, 0, 255)
+ //
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
+ // deal with the details.
+ //
+ // The arguments are parsed with the `entities.arguments` parser.
+ //
+ private function parseEntitiesCall(){
+ $index = $this->pos;
+
+ if( !preg_match('/\\G([\w-]+|%|progid:[\w\.]+)\(/', $this->input, $name,0,$this->pos) ){
+ return;
+ }
+ $name = $name[1];
+ $nameLC = strtolower($name);
+
+ if ($nameLC === 'url') {
+ return null;
+ }
+
+ $this->pos += strlen($name);
+
+ if( $nameLC === 'alpha' ){
+ $alpha_ret = $this->parseAlpha();
+ if( $alpha_ret ){
+ return $alpha_ret;
+ }
+ }
+
+ $this->MatchChar('('); // Parse the '(' and consume whitespace.
+
+ $args = $this->parseEntitiesArguments();
+
+ if( !$this->MatchChar(')') ){
+ return;
+ }
+
+ if ($name) {
+ return $this->NewObj4('Less_Tree_Call',array($name, $args, $index, $this->env->currentFileInfo) );
+ }
+ }
+
+ /**
+ * Parse a list of arguments
+ *
+ * @return array
+ */
+ private function parseEntitiesArguments(){
+
+ $args = array();
+ while( true ){
+ $arg = $this->MatchFuncs( array('parseEntitiesAssignment','parseExpression') );
+ if( !$arg ){
+ break;
+ }
+
+ $args[] = $arg;
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ }
+ return $args;
+ }
+
+ private function parseEntitiesLiteral(){
+ return $this->MatchFuncs( array('parseEntitiesDimension','parseEntitiesColor','parseEntitiesQuoted','parseUnicodeDescriptor') );
+ }
+
+ // Assignments are argument entities for calls.
+ // They are present in ie filter properties as shown below.
+ //
+ // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
+ //
+ private function parseEntitiesAssignment() {
+
+ $key = $this->MatchReg('/\\G\w+(?=\s?=)/');
+ if( !$key ){
+ return;
+ }
+
+ if( !$this->MatchChar('=') ){
+ return;
+ }
+
+ $value = $this->parseEntity();
+ if( $value ){
+ return $this->NewObj2('Less_Tree_Assignment',array($key[0], $value));
+ }
+ }
+
+ //
+ // Parse url() tokens
+ //
+ // We use a specific rule for urls, because they don't really behave like
+ // standard function calls. The difference is that the argument doesn't have
+ // to be enclosed within a string, so it can't be parsed as an Expression.
+ //
+ private function parseEntitiesUrl(){
+
+
+ if( $this->input[$this->pos] !== 'u' || !$this->matchReg('/\\Gurl\(/') ){
+ return;
+ }
+
+ $value = $this->match( array('parseEntitiesQuoted','parseEntitiesVariable','/\\Gdata\:.*?[^\)]+/','/\\G(?:(?:\\\\[\(\)\'"])|[^\(\)\'"])+/') );
+ if( !$value ){
+ $value = '';
+ }
+
+
+ $this->expectChar(')');
+
+
+ if( isset($value->value) || $value instanceof Less_Tree_Variable ){
+ return $this->NewObj2('Less_Tree_Url',array($value, $this->env->currentFileInfo));
+ }
+
+ return $this->NewObj2('Less_Tree_Url', array( $this->NewObj1('Less_Tree_Anonymous',$value), $this->env->currentFileInfo) );
+ }
+
+
+ //
+ // A Variable entity, such as `@fink`, in
+ //
+ // width: @fink + 2px
+ //
+ // We use a different parser for variable definitions,
+ // see `parsers.variable`.
+ //
+ private function parseEntitiesVariable(){
+ $index = $this->pos;
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G@@?[\w-]+/'))) {
+ return $this->NewObj3('Less_Tree_Variable', array( $name[0], $index, $this->env->currentFileInfo));
+ }
+ }
+
+
+ // A variable entity useing the protective {} e.g. @{var}
+ private function parseEntitiesVariableCurly() {
+ $index = $this->pos;
+
+ if( $this->input_len > ($this->pos+1) && $this->input[$this->pos] === '@' && ($curly = $this->MatchReg('/\\G@\{([\w-]+)\}/')) ){
+ return $this->NewObj3('Less_Tree_Variable',array('@'.$curly[1], $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // A Hexadecimal color
+ //
+ // #4F3C2F
+ //
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
+ //
+ private function parseEntitiesColor(){
+ if ($this->PeekChar('#') && ($rgb = $this->MatchReg('/\\G#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/'))) {
+ return $this->NewObj1('Less_Tree_Color',$rgb[1]);
+ }
+ }
+
+ //
+ // A Dimension, that is, a number and a unit
+ //
+ // 0.5em 95%
+ //
+ private function parseEntitiesDimension(){
+
+ $c = @ord($this->input[$this->pos]);
+
+ //Is the first char of the dimension 0-9, '.', '+' or '-'
+ if (($c > 57 || $c < 43) || $c === 47 || $c == 44){
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G([+-]?\d*\.?\d+)(%|[a-z]+)?/');
+ if( $value ){
+
+ if( isset($value[2]) ){
+ return $this->NewObj2('Less_Tree_Dimension', array($value[1],$value[2]));
+ }
+ return $this->NewObj1('Less_Tree_Dimension',$value[1]);
+ }
+ }
+
+
+ //
+ // A unicode descriptor, as is used in unicode-range
+ //
+ // U+0?? or U+00A1-00A9
+ //
+ function parseUnicodeDescriptor() {
+ $ud = $this->MatchReg('/\\G(U\+[0-9a-fA-F?]+)(\-[0-9a-fA-F?]+)?/');
+ if( $ud ){
+ return $this->NewObj1('Less_Tree_UnicodeDescriptor', $ud[0]);
+ }
+ }
+
+
+ //
+ // JavaScript code to be evaluated
+ //
+ // `window.location.href`
+ //
+ private function parseEntitiesJavascript(){
+ $e = false;
+ $j = $this->pos;
+ if( $this->input[$j] === '~' ){
+ $j++;
+ $e = true;
+ }
+ if( $this->input[$j] !== '`' ){
+ return;
+ }
+ if( $e ){
+ $this->MatchChar('~');
+ }
+ $str = $this->MatchReg('/\\G`([^`]*)`/');
+ if( $str ){
+ return $this->NewObj3('Less_Tree_Javascript', array($str[1], $this->pos, $e));
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink:
+ //
+ private function parseVariable(){
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*:/'))) {
+ return $name[1];
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink();
+ //
+ private function parseRulesetCall(){
+
+ if( $this->input[$this->pos] === '@' && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*\(\s*\)\s*;/')) ){
+ return $this->NewObj1('Less_Tree_RulesetCall', $name[1] );
+ }
+ }
+
+
+ //
+ // extend syntax - used to extend selectors
+ //
+ function parseExtend($isRule = false){
+
+ $index = $this->pos;
+ $extendList = array();
+
+
+ if( !$this->MatchReg( $isRule ? '/\\G&:extend\(/' : '/\\G:extend\(/' ) ){ return; }
+
+ do{
+ $option = null;
+ $elements = array();
+ while( true ){
+ $option = $this->MatchReg('/\\G(all)(?=\s*(\)|,))/');
+ if( $option ){ break; }
+ $e = $this->parseElement();
+ if( !$e ){ break; }
+ $elements[] = $e;
+ }
+
+ if( $option ){
+ $option = $option[1];
+ }
+
+ $extendList[] = $this->NewObj3('Less_Tree_Extend', array( $this->NewObj1('Less_Tree_Selector',$elements), $option, $index ));
+
+ }while( $this->MatchChar(",") );
+
+ $this->expect('/\\G\)/');
+
+ if( $isRule ){
+ $this->expect('/\\G;/');
+ }
+
+ return $extendList;
+ }
+
+
+ //
+ // A Mixin call, with an optional argument list
+ //
+ // #mixins > .square(#fff);
+ // .rounded(4px, black);
+ // .button;
+ //
+ // The `while` loop is there because mixins can be
+ // namespaced, but we only support the child and descendant
+ // selector for now.
+ //
+ private function parseMixinCall(){
+
+ $char = $this->input[$this->pos];
+ if( $char !== '.' && $char !== '#' ){
+ return;
+ }
+
+ $index = $this->pos;
+ $this->save(); // stop us absorbing part of an invalid selector
+
+ $elements = $this->parseMixinCallElements();
+
+ if( $elements ){
+
+ if( $this->MatchChar('(') ){
+ $returned = $this->parseMixinArgs(true);
+ $args = $returned['args'];
+ $this->expectChar(')');
+ }else{
+ $args = array();
+ }
+
+ $important = $this->parseImportant();
+
+ if( $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Call', array( $elements, $args, $index, $this->env->currentFileInfo, $important));
+ }
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseMixinCallElements(){
+ $elements = array();
+ $c = null;
+
+ while( true ){
+ $elemIndex = $this->pos;
+ $e = $this->MatchReg('/\\G[#.](?:[\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/');
+ if( !$e ){
+ break;
+ }
+ $elements[] = $this->NewObj4('Less_Tree_Element', array($c, $e[0], $elemIndex, $this->env->currentFileInfo));
+ $c = $this->MatchChar('>');
+ }
+
+ return $elements;
+ }
+
+
+
+ /**
+ * @param boolean $isCall
+ */
+ private function parseMixinArgs( $isCall ){
+ $expressions = array();
+ $argsSemiColon = array();
+ $isSemiColonSeperated = null;
+ $argsComma = array();
+ $expressionContainsNamed = null;
+ $name = null;
+ $returner = array('args'=>array(), 'variadic'=> false);
+
+ $this->save();
+
+ while( true ){
+ if( $isCall ){
+ $arg = $this->MatchFuncs( array( 'parseDetachedRuleset','parseExpression' ) );
+ } else {
+ $this->parseComments();
+ if( $this->input[ $this->pos ] === '.' && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('variadic'=>true);
+ }else{
+ $argsComma[] = array('variadic'=>true);
+ }
+ break;
+ }
+ $arg = $this->MatchFuncs( array('parseEntitiesVariable','parseEntitiesLiteral','parseEntitiesKeyword') );
+ }
+
+ if( !$arg ){
+ break;
+ }
+
+
+ $nameLoop = null;
+ if( $arg instanceof Less_Tree_Expression ){
+ $arg->throwAwayComments();
+ }
+ $value = $arg;
+ $val = null;
+
+ if( $isCall ){
+ // Variable
+ if( property_exists($arg,'value') && count($arg->value) == 1 ){
+ $val = $arg->value[0];
+ }
+ } else {
+ $val = $arg;
+ }
+
+
+ if( $val instanceof Less_Tree_Variable ){
+
+ if( $this->MatchChar(':') ){
+ if( $expressions ){
+ if( $isSemiColonSeperated ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+ $expressionContainsNamed = true;
+ }
+
+ // we do not support setting a ruleset as a default variable - it doesn't make sense
+ // However if we do want to add it, there is nothing blocking it, just don't error
+ // and remove isCall dependency below
+ $value = null;
+ if( $isCall ){
+ $value = $this->parseDetachedRuleset();
+ }
+ if( !$value ){
+ $value = $this->parseExpression();
+ }
+
+ if( !$value ){
+ if( $isCall ){
+ $this->Error('could not understand value for named argument');
+ } else {
+ $this->restore();
+ $returner['args'] = array();
+ return $returner;
+ }
+ }
+
+ $nameLoop = ($name = $val->name);
+ }elseif( !$isCall && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('name'=> $arg->name, 'variadic' => true);
+ }else{
+ $argsComma[] = array('name'=> $arg->name, 'variadic' => true);
+ }
+ break;
+ }elseif( !$isCall ){
+ $name = $nameLoop = $val->name;
+ $value = null;
+ }
+ }
+
+ if( $value ){
+ $expressions[] = $value;
+ }
+
+ $argsComma[] = array('name'=>$nameLoop, 'value'=>$value );
+
+ if( $this->MatchChar(',') ){
+ continue;
+ }
+
+ if( $this->MatchChar(';') || $isSemiColonSeperated ){
+
+ if( $expressionContainsNamed ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+
+ $isSemiColonSeperated = true;
+
+ if( count($expressions) > 1 ){
+ $value = $this->NewObj1('Less_Tree_Value', $expressions);
+ }
+ $argsSemiColon[] = array('name'=>$name, 'value'=>$value );
+
+ $name = null;
+ $expressions = array();
+ $expressionContainsNamed = false;
+ }
+ }
+
+ $this->forget();
+ $returner['args'] = ($isSemiColonSeperated ? $argsSemiColon : $argsComma);
+ return $returner;
+ }
+
+
+
+ //
+ // A Mixin definition, with a list of parameters
+ //
+ // .rounded (@radius: 2px, @color) {
+ // ...
+ // }
+ //
+ // Until we have a finer grained state-machine, we have to
+ // do a look-ahead, to make sure we don't have a mixin call.
+ // See the `rule` function for more information.
+ //
+ // We start by matching `.rounded (`, and then proceed on to
+ // the argument list, which has optional default values.
+ // We store the parameters in `params`, with a `value` key,
+ // if there is a value, such as in the case of `@radius`.
+ //
+ // Once we've got our params list, and a closing `)`, we parse
+ // the `{...}` block.
+ //
+ private function parseMixinDefinition(){
+ $cond = null;
+
+ $char = $this->input[$this->pos];
+ if( ($char !== '.' && $char !== '#') || ($char === '{' && $this->PeekReg('/\\G[^{]*\}/')) ){
+ return;
+ }
+
+ $this->save();
+
+ $match = $this->MatchReg('/\\G([#.](?:[\w-]|\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/');
+ if( $match ){
+ $name = $match[1];
+
+ $argInfo = $this->parseMixinArgs( false );
+ $params = $argInfo['args'];
+ $variadic = $argInfo['variadic'];
+
+
+ // .mixincall("@{a}");
+ // looks a bit like a mixin definition..
+ // also
+ // .mixincall(@a: {rule: set;});
+ // so we have to be nice and restore
+ if( !$this->MatchChar(')') ){
+ $this->furthest = $this->pos;
+ $this->restore();
+ return;
+ }
+
+
+ $this->parseComments();
+
+ if ($this->MatchReg('/\\Gwhen/')) { // Guard
+ $cond = $this->expect('parseConditions', 'Expected conditions');
+ }
+
+ $ruleset = $this->parseBlock();
+
+ if( is_array($ruleset) ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Definition', array( $name, $params, $ruleset, $cond, $variadic));
+ }
+
+ $this->restore();
+ }else{
+ $this->forget();
+ }
+ }
+
+ //
+ // Entities are the smallest recognized token,
+ // and can be found inside a rule's value.
+ //
+ private function parseEntity(){
+
+ return $this->MatchFuncs( array('parseEntitiesLiteral','parseEntitiesVariable','parseEntitiesUrl','parseEntitiesCall','parseEntitiesKeyword','parseEntitiesJavascript','parseComment') );
+ }
+
+ //
+ // A Rule terminator. Note that we use `peek()` to check for '}',
+ // because the `block` rule will be expecting it, but we still need to make sure
+ // it's there, if ';' was ommitted.
+ //
+ private function parseEnd(){
+ return $this->MatchChar(';') || $this->PeekChar('}');
+ }
+
+ //
+ // IE's alpha function
+ //
+ // alpha(opacity=88)
+ //
+ private function parseAlpha(){
+
+ if ( ! $this->MatchReg('/\\G\(opacity=/i')) {
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G[0-9]+/');
+ if( $value ){
+ $value = $value[0];
+ }else{
+ $value = $this->parseEntitiesVariable();
+ if( !$value ){
+ return;
+ }
+ }
+
+ $this->expectChar(')');
+ return $this->NewObj1('Less_Tree_Alpha',$value);
+ }
+
+
+ //
+ // A Selector Element
+ //
+ // div
+ // + h1
+ // #socks
+ // input[type="text"]
+ //
+ // Elements are the building blocks for Selectors,
+ // they are made out of a `Combinator` (see combinator rule),
+ // and an element name, such as a tag a class, or `*`.
+ //
+ private function parseElement(){
+ $c = $this->parseCombinator();
+ $index = $this->pos;
+
+ $e = $this->match( array('/\\G(?:\d+\.\d+|\d+)%/', '/\\G(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/',
+ '#*', '#&', 'parseAttribute', '/\\G\([^()@]+\)/', '/\\G[\.#](?=@)/', 'parseEntitiesVariableCurly') );
+
+ if( is_null($e) ){
+ $this->save();
+ if( $this->MatchChar('(') ){
+ if( ($v = $this->parseSelector()) && $this->MatchChar(')') ){
+ $e = $this->NewObj1('Less_Tree_Paren',$v);
+ $this->forget();
+ }else{
+ $this->restore();
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ if( !is_null($e) ){
+ return $this->NewObj4('Less_Tree_Element',array( $c, $e, $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // Combinators combine elements together, in a Selector.
+ //
+ // Because our parser isn't white-space sensitive, special care
+ // has to be taken, when parsing the descendant combinator, ` `,
+ // as it's an empty space. We have to check the previous character
+ // in the input, to see if it's a ` ` character.
+ //
+ private function parseCombinator(){
+ $c = $this->input[$this->pos];
+ if ($c === '>' || $c === '+' || $c === '~' || $c === '|' || $c === '^' ){
+
+ $this->pos++;
+ if( $this->input[$this->pos] === '^' ){
+ $c = '^^';
+ $this->pos++;
+ }
+
+ $this->skipWhitespace(0);
+
+ return $c;
+ }
+
+ if( $this->pos > 0 && $this->isWhitespace(-1) ){
+ return ' ';
+ }
+ }
+
+ //
+ // A CSS selector (see selector below)
+ // with less extensions e.g. the ability to extend and guard
+ //
+ private function parseLessSelector(){
+ return $this->parseSelector(true);
+ }
+
+ //
+ // A CSS Selector
+ //
+ // .class > div + h1
+ // li a:hover
+ //
+ // Selectors are made out of one or more Elements, see above.
+ //
+ private function parseSelector( $isLess = false ){
+ $elements = array();
+ $extendList = array();
+ $condition = null;
+ $when = false;
+ $extend = false;
+ $e = null;
+ $c = null;
+ $index = $this->pos;
+
+ while( ($isLess && ($extend = $this->parseExtend())) || ($isLess && ($when = $this->MatchReg('/\\Gwhen/') )) || ($e = $this->parseElement()) ){
+ if( $when ){
+ $condition = $this->expect('parseConditions', 'expected condition');
+ }elseif( $condition ){
+ //error("CSS guard can only be used at the end of selector");
+ }elseif( $extend ){
+ $extendList = array_merge($extendList,$extend);
+ }else{
+ //if( count($extendList) ){
+ //error("Extend can only be used at the end of selector");
+ //}
+ $c = $this->input[ $this->pos ];
+ $elements[] = $e;
+ $e = null;
+ }
+
+ if( $c === '{' || $c === '}' || $c === ';' || $c === ',' || $c === ')') { break; }
+ }
+
+ if( $elements ){
+ return $this->NewObj5('Less_Tree_Selector',array($elements, $extendList, $condition, $index, $this->env->currentFileInfo));
+ }
+ if( $extendList ) {
+ $this->Error('Extend must be used to extend a selector, it cannot be used on its own');
+ }
+ }
+
+ private function parseTag(){
+ return ( $tag = $this->MatchReg('/\\G[A-Za-z][A-Za-z-]*[0-9]?/') ) ? $tag : $this->MatchChar('*');
+ }
+
+ private function parseAttribute(){
+
+ $val = null;
+
+ if( !$this->MatchChar('[') ){
+ return;
+ }
+
+ $key = $this->parseEntitiesVariableCurly();
+ if( !$key ){
+ $key = $this->expect('/\\G(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\\\.)+/');
+ }
+
+ $op = $this->MatchReg('/\\G[|~*$^]?=/');
+ if( $op ){
+ $val = $this->match( array('parseEntitiesQuoted','/\\G[0-9]+%/','/\\G[\w-]+/','parseEntitiesVariableCurly') );
+ }
+
+ $this->expectChar(']');
+
+ return $this->NewObj3('Less_Tree_Attribute',array( $key, $op[0], $val));
+ }
+
+ //
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
+ // It's a wrapper around the `primary` rule, with added `{}`.
+ //
+ private function parseBlock(){
+ if( $this->MatchChar('{') ){
+ $content = $this->parsePrimary();
+ if( $this->MatchChar('}') ){
+ return $content;
+ }
+ }
+ }
+
+ private function parseBlockRuleset(){
+ $block = $this->parseBlock();
+
+ if( $block ){
+ $block = $this->NewObj2('Less_Tree_Ruleset',array( null, $block));
+ }
+
+ return $block;
+ }
+
+ private function parseDetachedRuleset(){
+ $blockRuleset = $this->parseBlockRuleset();
+ if( $blockRuleset ){
+ return $this->NewObj1('Less_Tree_DetachedRuleset',$blockRuleset);
+ }
+ }
+
+ //
+ // div, .class, body > p {...}
+ //
+ private function parseRuleset(){
+ $selectors = array();
+
+ $this->save();
+
+ while( true ){
+ $s = $this->parseLessSelector();
+ if( !$s ){
+ break;
+ }
+ $selectors[] = $s;
+ $this->parseComments();
+
+ if( $s->condition && count($selectors) > 1 ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ if( $s->condition ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+ $this->parseComments();
+ }
+
+
+ if( $selectors ){
+ $rules = $this->parseBlock();
+ if( is_array($rules) ){
+ $this->forget();
+ return $this->NewObj2('Less_Tree_Ruleset',array( $selectors, $rules)); //Less_Environment::$strictImports
+ }
+ }
+
+ // Backtrack
+ $this->furthest = $this->pos;
+ $this->restore();
+ }
+
+ /**
+ * Custom less.php parse function for finding simple name-value css pairs
+ * ex: width:100px;
+ *
+ */
+ private function parseNameValue(){
+
+ $index = $this->pos;
+ $this->save();
+
+
+ //$match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*((?:\'")?[a-zA-Z0-9\-% \.,!]+?(?:\'")?)\s*([;}])/');
+ $match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*([\'"]?[#a-zA-Z0-9\-%\.,]+?[\'"]?) *(! *important)?\s*([;}])/');
+ if( $match ){
+
+ if( $match[4] == '}' ){
+ $this->pos = $index + strlen($match[0])-1;
+ }
+
+ if( $match[3] ){
+ $match[2] .= ' !important';
+ }
+
+ return $this->NewObj4('Less_Tree_NameValue',array( $match[1], $match[2], $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseRule( $tryAnonymous = null ){
+
+ $merge = false;
+ $startOfRule = $this->pos;
+
+ $c = $this->input[$this->pos];
+ if( $c === '.' || $c === '#' || $c === '&' ){
+ return;
+ }
+
+ $this->save();
+ $name = $this->MatchFuncs( array('parseVariable','parseRuleProperty'));
+
+ if( $name ){
+
+ $isVariable = is_string($name);
+
+ $value = null;
+ if( $isVariable ){
+ $value = $this->parseDetachedRuleset();
+ }
+
+ $important = null;
+ if( !$value ){
+
+ // prefer to try to parse first if its a variable or we are compressing
+ // but always fallback on the other one
+ //if( !$tryAnonymous && is_string($name) && $name[0] === '@' ){
+ if( !$tryAnonymous && (Less_Parser::$options['compress'] || $isVariable) ){
+ $value = $this->MatchFuncs( array('parseValue','parseAnonymousValue'));
+ }else{
+ $value = $this->MatchFuncs( array('parseAnonymousValue','parseValue'));
+ }
+
+ $important = $this->parseImportant();
+
+ // a name returned by this.ruleProperty() is always an array of the form:
+ // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
+ // where each item is a tree.Keyword or tree.Variable
+ if( !$isVariable && is_array($name) ){
+ $nm = array_pop($name);
+ if( $nm->value ){
+ $merge = $nm->value;
+ }
+ }
+ }
+
+
+ if( $value && $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj6('Less_Tree_Rule',array( $name, $value, $important, $merge, $startOfRule, $this->env->currentFileInfo));
+ }else{
+ $this->furthest = $this->pos;
+ $this->restore();
+ if( $value && !$tryAnonymous ){
+ return $this->parseRule(true);
+ }
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ function parseAnonymousValue(){
+
+ if( preg_match('/\\G([^@+\/\'"*`(;{}-]*);/',$this->input, $match, 0, $this->pos) ){
+ $this->pos += strlen($match[1]);
+ return $this->NewObj1('Less_Tree_Anonymous',$match[1]);
+ }
+ }
+
+ //
+ // An @import directive
+ //
+ // @import "lib";
+ //
+ // Depending on our environment, importing is done differently:
+ // In the browser, it's an XHR request, in Node, it would be a
+ // file-system operation. The function used for importing is
+ // stored in `import`, which we pass to the Import constructor.
+ //
+ private function parseImport(){
+
+ $this->save();
+
+ $dir = $this->MatchReg('/\\G@import?\s+/');
+
+ if( $dir ){
+ $options = $this->parseImportOptions();
+ $path = $this->MatchFuncs( array('parseEntitiesQuoted','parseEntitiesUrl'));
+
+ if( $path ){
+ $features = $this->parseMediaFeatures();
+ if( $this->MatchChar(';') ){
+ if( $features ){
+ $features = $this->NewObj1('Less_Tree_Value',$features);
+ }
+
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Import',array( $path, $features, $options, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+ $this->restore();
+ }
+
+ private function parseImportOptions(){
+
+ $options = array();
+
+ // list of options, surrounded by parens
+ if( !$this->MatchChar('(') ){
+ return $options;
+ }
+ do{
+ $optionName = $this->parseImportOption();
+ if( $optionName ){
+ $value = true;
+ switch( $optionName ){
+ case "css":
+ $optionName = "less";
+ $value = false;
+ break;
+ case "once":
+ $optionName = "multiple";
+ $value = false;
+ break;
+ }
+ $options[$optionName] = $value;
+ if( !$this->MatchChar(',') ){ break; }
+ }
+ }while( $optionName );
+ $this->expectChar(')');
+ return $options;
+ }
+
+ private function parseImportOption(){
+ $opt = $this->MatchReg('/\\G(less|css|multiple|once|inline|reference)/');
+ if( $opt ){
+ return $opt[1];
+ }
+ }
+
+ private function parseMediaFeature() {
+ $nodes = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseEntitiesKeyword','parseEntitiesVariable'));
+ if( $e ){
+ $nodes[] = $e;
+ } elseif ($this->MatchChar('(')) {
+ $p = $this->parseProperty();
+ $e = $this->parseValue();
+ if ($this->MatchChar(')')) {
+ if ($p && $e) {
+ $r = $this->NewObj7('Less_Tree_Rule', array( $p, $e, null, null, $this->pos, $this->env->currentFileInfo, true));
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$r);
+ } elseif ($e) {
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$e);
+ } else {
+ return null;
+ }
+ } else
+ return null;
+ }
+ } while ($e);
+
+ if ($nodes) {
+ return $this->NewObj1('Less_Tree_Expression',$nodes);
+ }
+ }
+
+ private function parseMediaFeatures() {
+ $features = array();
+
+ do{
+ $e = $this->parseMediaFeature();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }else{
+ $e = $this->parseEntitiesVariable();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }
+ }
+ } while ($e);
+
+ return $features ? $features : null;
+ }
+
+ private function parseMedia() {
+ if( $this->MatchReg('/\\G@media/') ){
+ $features = $this->parseMediaFeatures();
+ $rules = $this->parseBlock();
+
+ if( is_array($rules) ){
+ return $this->NewObj4('Less_Tree_Media',array( $rules, $features, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+
+ //
+ // A CSS Directive
+ //
+ // @charset "utf-8";
+ //
+ private function parseDirective(){
+
+ if( !$this->PeekChar('@') ){
+ return;
+ }
+
+ $rules = null;
+ $index = $this->pos;
+ $hasBlock = true;
+ $hasIdentifier = false;
+ $hasExpression = false;
+ $hasUnknown = false;
+
+
+ $value = $this->MatchFuncs(array('parseImport','parseMedia'));
+ if( $value ){
+ return $value;
+ }
+
+ $this->save();
+
+ $name = $this->MatchReg('/\\G@[a-z-]+/');
+
+ if( !$name ) return;
+ $name = $name[0];
+
+
+ $nonVendorSpecificName = $name;
+ $pos = strpos($name,'-', 2);
+ if( $name[1] == '-' && $pos > 0 ){
+ $nonVendorSpecificName = "@" . substr($name, $pos + 1);
+ }
+
+
+ switch( $nonVendorSpecificName ){
+ /*
+ case "@font-face":
+ case "@viewport":
+ case "@top-left":
+ case "@top-left-corner":
+ case "@top-center":
+ case "@top-right":
+ case "@top-right-corner":
+ case "@bottom-left":
+ case "@bottom-left-corner":
+ case "@bottom-center":
+ case "@bottom-right":
+ case "@bottom-right-corner":
+ case "@left-top":
+ case "@left-middle":
+ case "@left-bottom":
+ case "@right-top":
+ case "@right-middle":
+ case "@right-bottom":
+ hasBlock = true;
+ break;
+ */
+ case "@charset":
+ $hasIdentifier = true;
+ $hasBlock = false;
+ break;
+ case "@namespace":
+ $hasExpression = true;
+ $hasBlock = false;
+ break;
+ case "@keyframes":
+ $hasIdentifier = true;
+ break;
+ case "@host":
+ case "@page":
+ case "@document":
+ case "@supports":
+ $hasUnknown = true;
+ break;
+ }
+
+ if( $hasIdentifier ){
+ $value = $this->parseEntity();
+ if( !$value ){
+ $this->error("expected " . $name . " identifier");
+ }
+ } else if( $hasExpression ){
+ $value = $this->parseExpression();
+ if( !$value ){
+ $this->error("expected " . $name. " expression");
+ }
+ } else if ($hasUnknown) {
+
+ $value = $this->MatchReg('/\\G[^{;]+/');
+ if( $value ){
+ $value = $this->NewObj1('Less_Tree_Anonymous',trim($value[0]));
+ }
+ }
+
+ if( $hasBlock ){
+ $rules = $this->parseBlockRuleset();
+ }
+
+ if( $rules || (!$hasBlock && $value && $this->MatchChar(';'))) {
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Directive',array($name, $value, $rules, $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ //
+ // A Value is a comma-delimited list of Expressions
+ //
+ // font-family: Baskerville, Georgia, serif;
+ //
+ // In a Rule, a Value represents everything after the `:`,
+ // and before the `;`.
+ //
+ private function parseValue(){
+ $expressions = array();
+
+ do{
+ $e = $this->parseExpression();
+ if( $e ){
+ $expressions[] = $e;
+ if (! $this->MatchChar(',')) {
+ break;
+ }
+ }
+ }while($e);
+
+ if( $expressions ){
+ return $this->NewObj1('Less_Tree_Value',$expressions);
+ }
+ }
+
+ private function parseImportant (){
+ if( $this->PeekChar('!') && $this->MatchReg('/\\G! *important/') ){
+ return ' !important';
+ }
+ }
+
+ private function parseSub (){
+
+ if( $this->MatchChar('(') ){
+ $a = $this->parseAddition();
+ if( $a ){
+ $this->expectChar(')');
+ return $this->NewObj2('Less_Tree_Expression',array( array($a), true) ); //instead of $e->parens = true so the value is cached
+ }
+ }
+ }
+
+
+ /**
+ * Parses multiplication operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ function parseMultiplication(){
+
+ $return = $m = $this->parseOperand();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ if( $this->PeekReg('/\\G\/[*\/]/') ){
+ break;
+ }
+
+ $op = $this->MatchChar('/');
+ if( !$op ){
+ $op = $this->MatchChar('*');
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseOperand();
+
+ if(!$a) { break; }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array( $op, array( $return, $a ), $isSpaced) );
+ }
+ }
+ return $return;
+
+ }
+
+
+ /**
+ * Parses an addition operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ private function parseAddition (){
+
+ $return = $m = $this->parseMultiplication();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ $op = $this->MatchReg('/\\G[-+]\s+/');
+ if( $op ){
+ $op = $op[0];
+ }else{
+ if( !$isSpaced ){
+ $op = $this->match(array('#+','#-'));
+ }
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseMultiplication();
+ if( !$a ){
+ break;
+ }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array($op, array($return, $a), $isSpaced));
+ }
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Parses the conditions
+ *
+ * @return Less_Tree_Condition|null
+ */
+ private function parseConditions() {
+ $index = $this->pos;
+ $return = $a = $this->parseCondition();
+ if( $a ){
+ while( true ){
+ if( !$this->PeekReg('/\\G,\s*(not\s*)?\(/') || !$this->MatchChar(',') ){
+ break;
+ }
+ $b = $this->parseCondition();
+ if( !$b ){
+ break;
+ }
+
+ $return = $this->NewObj4('Less_Tree_Condition',array('or', $return, $b, $index));
+ }
+ return $return;
+ }
+ }
+
+ private function parseCondition() {
+ $index = $this->pos;
+ $negate = false;
+ $c = null;
+
+ if ($this->MatchReg('/\\Gnot/')) $negate = true;
+ $this->expectChar('(');
+ $a = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+
+ if( $a ){
+ $op = $this->MatchReg('/\\G(?:>=|<=|=<|[<=>])/');
+ if( $op ){
+ $b = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+ if( $b ){
+ $c = $this->NewObj5('Less_Tree_Condition',array($op[0], $a, $b, $index, $negate));
+ } else {
+ $this->Error('Unexpected expression');
+ }
+ } else {
+ $k = $this->NewObj1('Less_Tree_Keyword','true');
+ $c = $this->NewObj5('Less_Tree_Condition',array('=', $a, $k, $index, $negate));
+ }
+ $this->expectChar(')');
+ return $this->MatchReg('/\\Gand/') ? $this->NewObj3('Less_Tree_Condition',array('and', $c, $this->parseCondition())) : $c;
+ }
+ }
+
+ /**
+ * An operand is anything that can be part of an operation,
+ * such as a Color, or a Variable
+ *
+ */
+ private function parseOperand (){
+
+ $negate = false;
+ $offset = $this->pos+1;
+ if( $offset >= $this->input_len ){
+ return;
+ }
+ $char = $this->input[$offset];
+ if( $char === '@' || $char === '(' ){
+ $negate = $this->MatchChar('-');
+ }
+
+ $o = $this->MatchFuncs(array('parseSub','parseEntitiesDimension','parseEntitiesColor','parseEntitiesVariable','parseEntitiesCall'));
+
+ if( $negate ){
+ $o->parensInOp = true;
+ $o = $this->NewObj1('Less_Tree_Negative',$o);
+ }
+
+ return $o;
+ }
+
+
+ /**
+ * Expressions either represent mathematical operations,
+ * or white-space delimited Entities.
+ *
+ * 1px solid black
+ * @var * 2
+ *
+ * @return Less_Tree_Expression|null
+ */
+ private function parseExpression (){
+ $entities = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseAddition','parseEntity'));
+ if( $e ){
+ $entities[] = $e;
+ // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
+ if( !$this->PeekReg('/\\G\/[\/*]/') ){
+ $delim = $this->MatchChar('/');
+ if( $delim ){
+ $entities[] = $this->NewObj1('Less_Tree_Anonymous',$delim);
+ }
+ }
+ }
+ }while($e);
+
+ if( $entities ){
+ return $this->NewObj1('Less_Tree_Expression',$entities);
+ }
+ }
+
+
+ /**
+ * Parse a property
+ * eg: 'min-width', 'orientation', etc
+ *
+ * @return string
+ */
+ private function parseProperty (){
+ $name = $this->MatchReg('/\\G(\*?-?[_a-zA-Z0-9-]+)\s*:/');
+ if( $name ){
+ return $name[1];
+ }
+ }
+
+
+ /**
+ * Parse a rule property
+ * eg: 'color', 'width', 'height', etc
+ *
+ * @return string
+ */
+ private function parseRuleProperty(){
+ $offset = $this->pos;
+ $name = array();
+ $index = array();
+ $length = 0;
+
+
+ $this->rulePropertyMatch('/\\G(\*?)/', $offset, $length, $index, $name );
+ while( $this->rulePropertyMatch('/\\G((?:[\w-]+)|(?:@\{[\w-]+\}))/', $offset, $length, $index, $name )); // !
+
+ if( (count($name) > 1) && $this->rulePropertyMatch('/\\G\s*((?:\+_|\+)?)\s*:/', $offset, $length, $index, $name) ){
+ // at last, we have the complete match now. move forward,
+ // convert name particles to tree objects and return:
+ $this->skipWhitespace($length);
+
+ if( $name[0] === '' ){
+ array_shift($name);
+ array_shift($index);
+ }
+ foreach($name as $k => $s ){
+ if( !$s || $s[0] !== '@' ){
+ $name[$k] = $this->NewObj1('Less_Tree_Keyword',$s);
+ }else{
+ $name[$k] = $this->NewObj3('Less_Tree_Variable',array('@' . substr($s,2,-1), $index[$k], $this->env->currentFileInfo));
+ }
+ }
+ return $name;
+ }
+
+
+ }
+
+ private function rulePropertyMatch( $re, &$offset, &$length, &$index, &$name ){
+ preg_match($re, $this->input, $a, 0, $offset);
+ if( $a ){
+ $index[] = $this->pos + $length;
+ $length += strlen($a[0]);
+ $offset += strlen($a[0]);
+ $name[] = $a[1];
+ return true;
+ }
+ }
+
+ public function serializeVars( $vars ){
+ $s = '';
+
+ foreach($vars as $name => $value){
+ $s .= (($name[0] === '@') ? '' : '@') . $name .': '. $value . ((substr($value,-1) === ';') ? '' : ';');
+ }
+
+ return $s;
+ }
+
+
+ /**
+ * Some versions of php have trouble with method_exists($a,$b) if $a is not an object
+ *
+ * @param string $b
+ */
+ public static function is_method($a,$b){
+ return is_object($a) && method_exists($a,$b);
+ }
+
+
+ /**
+ * Round numbers similarly to javascript
+ * eg: 1.499999 to 1 instead of 2
+ *
+ */
+ public static function round($i, $precision = 0){
+
+ $precision = pow(10,$precision);
+ $i = $i*$precision;
+
+ $ceil = ceil($i);
+ $floor = floor($i);
+ if( ($ceil - $i) <= ($i - $floor) ){
+ return $ceil/$precision;
+ }else{
+ return $floor/$precision;
+ }
+ }
+
+
+ /**
+ * Create Less_Tree_* objects and optionally generate a cache string
+ *
+ * @return mixed
+ */
+ public function NewObj0($class){
+ $obj = new $class();
+ if( Less_Cache::$cache_dir ){
+ $obj->cache_string = ' new '.$class.'()';
+ }
+ return $obj;
+ }
+
+ public function NewObj1($class, $arg){
+ $obj = new $class( $arg );
+ if( Less_Cache::$cache_dir ){
+ $obj->cache_string = ' new '.$class.'('.Less_Parser::ArgString($arg).')';
+ }
+ return $obj;
+ }
+
+ public function NewObj2($class, $args){
+ $obj = new $class( $args[0], $args[1] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj3($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj4($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj5($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj6($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj7($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6] );
+ if( Less_Cache::$cache_dir ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ //caching
+ public function ObjCache($obj, $class, $args=array()){
+ $obj->cache_string = ' new '.$class.'('. self::ArgCache($args).')';
+ }
+
+ public function ArgCache($args){
+ return implode(',',array_map( array('Less_Parser','ArgString'),$args));
+ }
+
+
+ /**
+ * Convert an argument to a string for use in the parser cache
+ *
+ * @return string
+ */
+ public static function ArgString($arg){
+
+ $type = gettype($arg);
+
+ if( $type === 'object'){
+ $string = $arg->cache_string;
+ unset($arg->cache_string);
+ return $string;
+
+ }elseif( $type === 'array' ){
+ $string = ' Array(';
+ foreach($arg as $k => $a){
+ $string .= var_export($k,true).' => '.self::ArgString($a).',';
+ }
+ return $string . ')';
+ }
+
+ return var_export($arg,true);
+ }
+
+ public function Error($msg){
+ throw new Less_Exception_Parser($msg, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ public static function WinPath($path){
+ return str_replace('\\', '/', $path);
+ }
+
+}
+
+
+
+
+/**
+ * Utility for css colors
+ *
+ * @package Less
+ * @subpackage color
+ */
+class Less_Colors {
+
+ public static $colors = array(
+ 'aliceblue'=>'#f0f8ff',
+ 'antiquewhite'=>'#faebd7',
+ 'aqua'=>'#00ffff',
+ 'aquamarine'=>'#7fffd4',
+ 'azure'=>'#f0ffff',
+ 'beige'=>'#f5f5dc',
+ 'bisque'=>'#ffe4c4',
+ 'black'=>'#000000',
+ 'blanchedalmond'=>'#ffebcd',
+ 'blue'=>'#0000ff',
+ 'blueviolet'=>'#8a2be2',
+ 'brown'=>'#a52a2a',
+ 'burlywood'=>'#deb887',
+ 'cadetblue'=>'#5f9ea0',
+ 'chartreuse'=>'#7fff00',
+ 'chocolate'=>'#d2691e',
+ 'coral'=>'#ff7f50',
+ 'cornflowerblue'=>'#6495ed',
+ 'cornsilk'=>'#fff8dc',
+ 'crimson'=>'#dc143c',
+ 'cyan'=>'#00ffff',
+ 'darkblue'=>'#00008b',
+ 'darkcyan'=>'#008b8b',
+ 'darkgoldenrod'=>'#b8860b',
+ 'darkgray'=>'#a9a9a9',
+ 'darkgrey'=>'#a9a9a9',
+ 'darkgreen'=>'#006400',
+ 'darkkhaki'=>'#bdb76b',
+ 'darkmagenta'=>'#8b008b',
+ 'darkolivegreen'=>'#556b2f',
+ 'darkorange'=>'#ff8c00',
+ 'darkorchid'=>'#9932cc',
+ 'darkred'=>'#8b0000',
+ 'darksalmon'=>'#e9967a',
+ 'darkseagreen'=>'#8fbc8f',
+ 'darkslateblue'=>'#483d8b',
+ 'darkslategray'=>'#2f4f4f',
+ 'darkslategrey'=>'#2f4f4f',
+ 'darkturquoise'=>'#00ced1',
+ 'darkviolet'=>'#9400d3',
+ 'deeppink'=>'#ff1493',
+ 'deepskyblue'=>'#00bfff',
+ 'dimgray'=>'#696969',
+ 'dimgrey'=>'#696969',
+ 'dodgerblue'=>'#1e90ff',
+ 'firebrick'=>'#b22222',
+ 'floralwhite'=>'#fffaf0',
+ 'forestgreen'=>'#228b22',
+ 'fuchsia'=>'#ff00ff',
+ 'gainsboro'=>'#dcdcdc',
+ 'ghostwhite'=>'#f8f8ff',
+ 'gold'=>'#ffd700',
+ 'goldenrod'=>'#daa520',
+ 'gray'=>'#808080',
+ 'grey'=>'#808080',
+ 'green'=>'#008000',
+ 'greenyellow'=>'#adff2f',
+ 'honeydew'=>'#f0fff0',
+ 'hotpink'=>'#ff69b4',
+ 'indianred'=>'#cd5c5c',
+ 'indigo'=>'#4b0082',
+ 'ivory'=>'#fffff0',
+ 'khaki'=>'#f0e68c',
+ 'lavender'=>'#e6e6fa',
+ 'lavenderblush'=>'#fff0f5',
+ 'lawngreen'=>'#7cfc00',
+ 'lemonchiffon'=>'#fffacd',
+ 'lightblue'=>'#add8e6',
+ 'lightcoral'=>'#f08080',
+ 'lightcyan'=>'#e0ffff',
+ 'lightgoldenrodyellow'=>'#fafad2',
+ 'lightgray'=>'#d3d3d3',
+ 'lightgrey'=>'#d3d3d3',
+ 'lightgreen'=>'#90ee90',
+ 'lightpink'=>'#ffb6c1',
+ 'lightsalmon'=>'#ffa07a',
+ 'lightseagreen'=>'#20b2aa',
+ 'lightskyblue'=>'#87cefa',
+ 'lightslategray'=>'#778899',
+ 'lightslategrey'=>'#778899',
+ 'lightsteelblue'=>'#b0c4de',
+ 'lightyellow'=>'#ffffe0',
+ 'lime'=>'#00ff00',
+ 'limegreen'=>'#32cd32',
+ 'linen'=>'#faf0e6',
+ 'magenta'=>'#ff00ff',
+ 'maroon'=>'#800000',
+ 'mediumaquamarine'=>'#66cdaa',
+ 'mediumblue'=>'#0000cd',
+ 'mediumorchid'=>'#ba55d3',
+ 'mediumpurple'=>'#9370d8',
+ 'mediumseagreen'=>'#3cb371',
+ 'mediumslateblue'=>'#7b68ee',
+ 'mediumspringgreen'=>'#00fa9a',
+ 'mediumturquoise'=>'#48d1cc',
+ 'mediumvioletred'=>'#c71585',
+ 'midnightblue'=>'#191970',
+ 'mintcream'=>'#f5fffa',
+ 'mistyrose'=>'#ffe4e1',
+ 'moccasin'=>'#ffe4b5',
+ 'navajowhite'=>'#ffdead',
+ 'navy'=>'#000080',
+ 'oldlace'=>'#fdf5e6',
+ 'olive'=>'#808000',
+ 'olivedrab'=>'#6b8e23',
+ 'orange'=>'#ffa500',
+ 'orangered'=>'#ff4500',
+ 'orchid'=>'#da70d6',
+ 'palegoldenrod'=>'#eee8aa',
+ 'palegreen'=>'#98fb98',
+ 'paleturquoise'=>'#afeeee',
+ 'palevioletred'=>'#d87093',
+ 'papayawhip'=>'#ffefd5',
+ 'peachpuff'=>'#ffdab9',
+ 'peru'=>'#cd853f',
+ 'pink'=>'#ffc0cb',
+ 'plum'=>'#dda0dd',
+ 'powderblue'=>'#b0e0e6',
+ 'purple'=>'#800080',
+ 'red'=>'#ff0000',
+ 'rosybrown'=>'#bc8f8f',
+ 'royalblue'=>'#4169e1',
+ 'saddlebrown'=>'#8b4513',
+ 'salmon'=>'#fa8072',
+ 'sandybrown'=>'#f4a460',
+ 'seagreen'=>'#2e8b57',
+ 'seashell'=>'#fff5ee',
+ 'sienna'=>'#a0522d',
+ 'silver'=>'#c0c0c0',
+ 'skyblue'=>'#87ceeb',
+ 'slateblue'=>'#6a5acd',
+ 'slategray'=>'#708090',
+ 'slategrey'=>'#708090',
+ 'snow'=>'#fffafa',
+ 'springgreen'=>'#00ff7f',
+ 'steelblue'=>'#4682b4',
+ 'tan'=>'#d2b48c',
+ 'teal'=>'#008080',
+ 'thistle'=>'#d8bfd8',
+ 'tomato'=>'#ff6347',
+ 'turquoise'=>'#40e0d0',
+ 'violet'=>'#ee82ee',
+ 'wheat'=>'#f5deb3',
+ 'white'=>'#ffffff',
+ 'whitesmoke'=>'#f5f5f5',
+ 'yellow'=>'#ffff00',
+ 'yellowgreen'=>'#9acd32'
+ );
+
+ public static function hasOwnProperty($color) {
+ return isset(self::$colors[$color]);
+ }
+
+
+ public static function color($color) {
+ return self::$colors[$color];
+ }
+
+}
+
+
+
+/**
+ * Environment
+ *
+ * @package Less
+ * @subpackage environment
+ */
+class Less_Environment{
+
+ //public $paths = array(); // option - unmodified - paths to search for imports on
+ //public static $files = array(); // list of files that have been imported, used for import-once
+ //public $rootpath; // option - rootpath to append to URL's
+ //public static $strictImports = null; // option -
+ //public $insecure; // option - whether to allow imports from insecure ssl hosts
+ //public $processImports; // option - whether to process imports. if false then imports will not be imported
+ //public $javascriptEnabled; // option - whether JavaScript is enabled. if undefined, defaults to true
+ //public $useFileCache; // browser only - whether to use the per file session cache
+ public $currentFileInfo; // information about the current file - for error reporting and importing and making urls relative etc.
+
+ public $importMultiple = false; // whether we are currently importing multiple copies
+
+
+ /**
+ * @var array
+ */
+ public $frames = array();
+
+ /**
+ * @var array
+ */
+ public $mediaBlocks = array();
+
+ /**
+ * @var array
+ */
+ public $mediaPath = array();
+
+ public static $parensStack = 0;
+
+ public static $tabLevel = 0;
+
+ public static $lastRule = false;
+
+ public static $_outputMap;
+
+ public static $mixin_stack = 0;
+
+
+ public function Init(){
+
+ self::$parensStack = 0;
+ self::$tabLevel = 0;
+ self::$lastRule = false;
+ self::$mixin_stack = 0;
+
+ if( Less_Parser::$options['compress'] ){
+
+ Less_Environment::$_outputMap = array(
+ ',' => ',',
+ ': ' => ':',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => '+',
+ '~' => '~',
+ '>' => '>',
+ '|' => '|',
+ '^' => '^',
+ '^^' => '^^'
+ );
+
+ }else{
+
+ Less_Environment::$_outputMap = array(
+ ',' => ', ',
+ ': ' => ': ',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => ' + ',
+ '~' => ' ~ ',
+ '>' => ' > ',
+ '|' => '|',
+ '^' => ' ^ ',
+ '^^' => ' ^^ '
+ );
+
+ }
+ }
+
+
+ public function copyEvalEnv($frames = array() ){
+ $new_env = new Less_Environment();
+ $new_env->frames = $frames;
+ return $new_env;
+ }
+
+
+ public static function isMathOn(){
+ return !Less_Parser::$options['strictMath'] || Less_Environment::$parensStack;
+ }
+
+ public static function isPathRelative($path){
+ return !preg_match('/^(?:[a-z-]+:|\/)/',$path);
+ }
+
+
+ /**
+ * Canonicalize a path by resolving references to '/./', '/../'
+ * Does not remove leading "../"
+ * @param string path or url
+ * @return string Canonicalized path
+ *
+ */
+ static function normalizePath($path){
+
+ $segments = explode('/',$path);
+ $segments = array_reverse($segments);
+
+ $path = array();
+ $path_len = 0;
+
+ while( $segments ){
+ $segment = array_pop($segments);
+ switch( $segment ) {
+
+ case '.':
+ break;
+
+ case '..':
+ if( !$path_len || ( $path[$path_len-1] === '..') ){
+ $path[] = $segment;
+ $path_len++;
+ }else{
+ array_pop($path);
+ $path_len--;
+ }
+ break;
+
+ default:
+ $path[] = $segment;
+ $path_len++;
+ break;
+ }
+ }
+
+ return implode('/',$path);
+ }
+
+
+ public function unshiftFrame($frame){
+ array_unshift($this->frames, $frame);
+ }
+
+ public function shiftFrame(){
+ return array_shift($this->frames);
+ }
+
+}
+
+
+/**
+ * Builtin functions
+ *
+ * @package Less
+ * @subpackage function
+ * @see http://lesscss.org/functions/
+ */
+class Less_Functions{
+
+ public $env;
+ public $currentFileInfo;
+
+ function __construct($env, $currentFileInfo = null ){
+ $this->env = $env;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+
+ /**
+ * @param string $op
+ */
+ static public function operate( $op, $a, $b ){
+ switch ($op) {
+ case '+': return $a + $b;
+ case '-': return $a - $b;
+ case '*': return $a * $b;
+ case '/': return $a / $b;
+ }
+ }
+
+ static public function clamp($val, $max = 1){
+ return min( max($val, 0), $max);
+ }
+
+ static function fround( $value ){
+
+ if( $value === 0 ){
+ return $value;
+ }
+
+ if( Less_Parser::$options['numPrecision'] ){
+ $p = pow(10, Less_Parser::$options['numPrecision']);
+ return round( $value * $p) / $p;
+ }
+ return $value;
+ }
+
+ static public function number($n){
+
+ if ($n instanceof Less_Tree_Dimension) {
+ return floatval( $n->unit->is('%') ? $n->value / 100 : $n->value);
+ } else if (is_numeric($n)) {
+ return $n;
+ } else {
+ throw new Less_Exception_Compiler("color functions take numbers as parameters");
+ }
+ }
+
+ static public function scaled($n, $size = 255 ){
+ if( $n instanceof Less_Tree_Dimension && $n->unit->is('%') ){
+ return (float)$n->value * $size / 100;
+ } else {
+ return Less_Functions::number($n);
+ }
+ }
+
+ public function rgb ($r, $g, $b){
+ return $this->rgba($r, $g, $b, 1.0);
+ }
+
+ public function rgba($r, $g, $b, $a){
+ $rgb = array($r, $g, $b);
+ $rgb = array_map(array('Less_Functions','scaled'),$rgb);
+
+ $a = self::number($a);
+ return new Less_Tree_Color($rgb, $a);
+ }
+
+ public function hsl($h, $s, $l){
+ return $this->hsla($h, $s, $l, 1.0);
+ }
+
+ public function hsla($h, $s, $l, $a){
+
+ $h = fmod(self::number($h), 360) / 360; // Classic % operator will change float to int
+ $s = self::clamp(self::number($s));
+ $l = self::clamp(self::number($l));
+ $a = self::clamp(self::number($a));
+
+ $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
+
+ $m1 = $l * 2 - $m2;
+
+ return $this->rgba( self::hsla_hue($h + 1/3, $m1, $m2) * 255,
+ self::hsla_hue($h, $m1, $m2) * 255,
+ self::hsla_hue($h - 1/3, $m1, $m2) * 255,
+ $a);
+ }
+
+ /**
+ * @param double $h
+ */
+ function hsla_hue($h, $m1, $m2){
+ $h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h);
+ if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
+ else if ($h * 2 < 1) return $m2;
+ else if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
+ else return $m1;
+ }
+
+ public function hsv($h, $s, $v) {
+ return $this->hsva($h, $s, $v, 1.0);
+ }
+
+ /**
+ * @param double $a
+ */
+ public function hsva($h, $s, $v, $a) {
+ $h = ((Less_Functions::number($h) % 360) / 360 ) * 360;
+ $s = Less_Functions::number($s);
+ $v = Less_Functions::number($v);
+ $a = Less_Functions::number($a);
+
+ $i = floor(($h / 60) % 6);
+ $f = ($h / 60) - $i;
+
+ $vs = array( $v,
+ $v * (1 - $s),
+ $v * (1 - $f * $s),
+ $v * (1 - (1 - $f) * $s));
+
+ $perm = array(array(0, 3, 1),
+ array(2, 0, 1),
+ array(1, 0, 3),
+ array(1, 2, 0),
+ array(3, 1, 0),
+ array(0, 1, 2));
+
+ return $this->rgba($vs[$perm[$i][0]] * 255,
+ $vs[$perm[$i][1]] * 255,
+ $vs[$perm[$i][2]] * 255,
+ $a);
+ }
+
+ public function hue($color){
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['h']));
+ }
+
+ public function saturation($color){
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['s'] * 100), '%');
+ }
+
+ public function lightness($color){
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['l'] * 100), '%');
+ }
+
+ public function hsvhue( $color ){
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['h']) );
+ }
+
+
+ public function hsvsaturation( $color ){
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['s'] * 100), '%' );
+ }
+
+ public function hsvvalue( $color ){
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['v'] * 100), '%' );
+ }
+
+ public function red($color) {
+ return new Less_Tree_Dimension( $color->rgb[0] );
+ }
+
+ public function green($color) {
+ return new Less_Tree_Dimension( $color->rgb[1] );
+ }
+
+ public function blue($color) {
+ return new Less_Tree_Dimension( $color->rgb[2] );
+ }
+
+ public function alpha($color){
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension($c['a']);
+ }
+
+ public function luma ($color) {
+ return new Less_Tree_Dimension(Less_Parser::round( $color->luma() * $color->alpha * 100), '%');
+ }
+
+ public function luminance( $color ){
+ $luminance =
+ (0.2126 * $color->rgb[0] / 255)
+ + (0.7152 * $color->rgb[1] / 255)
+ + (0.0722 * $color->rgb[2] / 255);
+
+ return new Less_Tree_Dimension(Less_Parser::round( $luminance * $color->alpha * 100), '%');
+ }
+
+ public function saturate($color, $amount = null){
+ // filter: saturate(3.2);
+ // should be kept as is, so check for color
+ if( !property_exists($color,'rgb') ){
+ return null;
+ }
+ $hsl = $color->toHSL();
+
+ $hsl['s'] += $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ /**
+ * @param Less_Tree_Dimension $amount
+ */
+ public function desaturate($color, $amount){
+ $hsl = $color->toHSL();
+
+ $hsl['s'] -= $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function lighten($color, $amount){
+ $hsl = $color->toHSL();
+
+ $hsl['l'] += $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function darken($color, $amount){
+
+ if( $color instanceof Less_Tree_Color ){
+ $hsl = $color->toHSL();
+ $hsl['l'] -= $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ Less_Functions::Expected('color',$color);
+ }
+
+ public function fadein($color, $amount){
+ $hsl = $color->toHSL();
+ $hsl['a'] += $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fadeout($color, $amount){
+ $hsl = $color->toHSL();
+ $hsl['a'] -= $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fade($color, $amount){
+ $hsl = $color->toHSL();
+
+ $hsl['a'] = $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function spin($color, $amount){
+ $hsl = $color->toHSL();
+ $hue = fmod($hsl['h'] + $amount->value, 360);
+
+ $hsl['h'] = $hue < 0 ? 360 + $hue : $hue;
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ //
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
+ // http://sass-lang.com
+ //
+
+ /**
+ * @param Less_Tree_Color $color1
+ */
+ public function mix($color1, $color2, $weight = null){
+ if (!$weight) {
+ $weight = new Less_Tree_Dimension('50', '%');
+ }
+
+ $p = $weight->value / 100.0;
+ $w = $p * 2 - 1;
+ $hsl1 = $color1->toHSL();
+ $hsl2 = $color2->toHSL();
+ $a = $hsl1['a'] - $hsl2['a'];
+
+ $w1 = (((($w * $a) == -1) ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2;
+ $w2 = 1 - $w1;
+
+ $rgb = array($color1->rgb[0] * $w1 + $color2->rgb[0] * $w2,
+ $color1->rgb[1] * $w1 + $color2->rgb[1] * $w2,
+ $color1->rgb[2] * $w1 + $color2->rgb[2] * $w2);
+
+ $alpha = $color1->alpha * $p + $color2->alpha * (1 - $p);
+
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function greyscale($color){
+ return $this->desaturate($color, new Less_Tree_Dimension(100));
+ }
+
+
+ public function contrast( $color, $dark = null, $light = null, $threshold = null){
+ // filter: contrast(3.2);
+ // should be kept as is, so check for color
+ if( !property_exists($color,'rgb') ){
+ return null;
+ }
+ if( !$light ){
+ $light = $this->rgba(255, 255, 255, 1.0);
+ }
+ if( !$dark ){
+ $dark = $this->rgba(0, 0, 0, 1.0);
+ }
+ //Figure out which is actually light and dark!
+ if( $dark->luma() > $light->luma() ){
+ $t = $light;
+ $light = $dark;
+ $dark = $t;
+ }
+ if( !$threshold ){
+ $threshold = 0.43;
+ } else {
+ $threshold = Less_Functions::number($threshold);
+ }
+
+ if( $color->luma() < $threshold ){
+ return $light;
+ } else {
+ return $dark;
+ }
+ }
+
+ public function e ($str){
+ if( is_string($str) ){
+ return new Less_Tree_Anonymous($str);
+ }
+ return new Less_Tree_Anonymous($str instanceof Less_Tree_JavaScript ? $str->expression : $str->value);
+ }
+
+ public function escape ($str){
+
+ $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'",'%3F'=>'?','%26'=>'&','%2C'=>',','%2F'=>'/','%40'=>'@','%2B'=>'+','%24'=>'$');
+
+ return new Less_Tree_Anonymous(strtr(rawurlencode($str->value), $revert));
+ }
+
+
+ /**
+ * todo: This function will need some additional work to make it work the same as less.js
+ *
+ */
+ public function replace( $string, $pattern, $replacement, $flags = null ){
+ $result = $string->value;
+
+ $expr = '/'.str_replace('/','\\/',$pattern->value).'/';
+ if( $flags && $flags->value){
+ $expr .= self::replace_flags($flags->value);
+ }
+
+ $result = preg_replace($expr,$replacement->value,$result);
+
+
+ if( property_exists($string,'quote') ){
+ return new Less_Tree_Quoted( $string->quote, $result, $string->escaped);
+ }
+ return new Less_Tree_Quoted( '', $result );
+ }
+
+ public static function replace_flags($flags){
+ $flags = str_split($flags,1);
+ $new_flags = '';
+
+ foreach($flags as $flag){
+ switch($flag){
+ case 'e':
+ case 'g':
+ break;
+
+ default:
+ $new_flags .= $flag;
+ break;
+ }
+ }
+
+ return $new_flags;
+ }
+
+ public function _percent(){
+ $string = func_get_arg(0);
+
+ $args = func_get_args();
+ array_shift($args);
+ $result = $string->value;
+
+ foreach($args as $arg){
+ if( preg_match('/%[sda]/i',$result, $token) ){
+ $token = $token[0];
+ $value = stristr($token, 's') ? $arg->value : $arg->toCSS();
+ $value = preg_match('/[A-Z]$/', $token) ? urlencode($value) : $value;
+ $result = preg_replace('/%[sda]/i',$value, $result, 1);
+ }
+ }
+ $result = str_replace('%%', '%', $result);
+
+ return new Less_Tree_Quoted( $string->quote , $result, $string->escaped);
+ }
+
+ public function unit( $val, $unit = null) {
+ if( !($val instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('The first argument to unit must be a number' . ($val instanceof Less_Tree_Operation ? '. Have you forgotten parenthesis?' : '.') );
+ }
+
+ if( $unit ){
+ if( $unit instanceof Less_Tree_Keyword ){
+ $unit = $unit->value;
+ } else {
+ $unit = $unit->toCSS();
+ }
+ } else {
+ $unit = "";
+ }
+ return new Less_Tree_Dimension($val->value, $unit );
+ }
+
+ public function convert($val, $unit){
+ return $val->convertTo($unit->value);
+ }
+
+ public function round($n, $f = false) {
+
+ $fraction = 0;
+ if( $f !== false ){
+ $fraction = $f->value;
+ }
+
+ return $this->_math('Less_Parser::round',null, $n, $fraction);
+ }
+
+ public function pi(){
+ return new Less_Tree_Dimension(M_PI);
+ }
+
+ public function mod($a, $b) {
+ return new Less_Tree_Dimension( $a->value % $b->value, $a->unit);
+ }
+
+
+
+ public function pow($x, $y) {
+ if( is_numeric($x) && is_numeric($y) ){
+ $x = new Less_Tree_Dimension($x);
+ $y = new Less_Tree_Dimension($y);
+ }elseif( !($x instanceof Less_Tree_Dimension) || !($y instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('Arguments must be numbers');
+ }
+
+ return new Less_Tree_Dimension( pow($x->value, $y->value), $x->unit );
+ }
+
+ // var mathFunctions = [{name:"ce ...
+ public function ceil( $n ){ return $this->_math('ceil', null, $n); }
+ public function floor( $n ){ return $this->_math('floor', null, $n); }
+ public function sqrt( $n ){ return $this->_math('sqrt', null, $n); }
+ public function abs( $n ){ return $this->_math('abs', null, $n); }
+
+ public function tan( $n ){ return $this->_math('tan', '', $n); }
+ public function sin( $n ){ return $this->_math('sin', '', $n); }
+ public function cos( $n ){ return $this->_math('cos', '', $n); }
+
+ public function atan( $n ){ return $this->_math('atan', 'rad', $n); }
+ public function asin( $n ){ return $this->_math('asin', 'rad', $n); }
+ public function acos( $n ){ return $this->_math('acos', 'rad', $n); }
+
+ private function _math() {
+ $args = func_get_args();
+ $fn = array_shift($args);
+ $unit = array_shift($args);
+
+ if ($args[0] instanceof Less_Tree_Dimension) {
+
+ if( $unit === null ){
+ $unit = $args[0]->unit;
+ }else{
+ $args[0] = $args[0]->unify();
+ }
+ $args[0] = (float)$args[0]->value;
+ return new Less_Tree_Dimension( call_user_func_array($fn, $args), $unit);
+ } else if (is_numeric($args[0])) {
+ return call_user_func_array($fn,$args);
+ } else {
+ throw new Less_Exception_Compiler("math functions take numbers as parameters");
+ }
+ }
+
+ /**
+ * @param boolean $isMin
+ */
+ function _minmax( $isMin, $args ){
+
+ $arg_count = count($args);
+
+ if( $arg_count < 1 ){
+ throw new Less_Exception_Compiler( 'one or more arguments required');
+ }
+
+ $j = null;
+ $unitClone = null;
+ $unitStatic = null;
+
+
+ $order = array(); // elems only contains original argument values.
+ $values = array(); // key is the unit.toString() for unified tree.Dimension values,
+ // value is the index into the order array.
+
+
+ for( $i = 0; $i < $arg_count; $i++ ){
+ $current = $args[$i];
+ if( !($current instanceof Less_Tree_Dimension) ){
+ if( is_array($args[$i]->value) ){
+ $args[] = $args[$i]->value;
+ }
+ continue;
+ }
+
+ if( $current->unit->toString() === '' && !$unitClone ){
+ $temp = new Less_Tree_Dimension($current->value, $unitClone);
+ $currentUnified = $temp->unify();
+ }else{
+ $currentUnified = $current->unify();
+ }
+
+ if( $currentUnified->unit->toString() === "" && !$unitStatic ){
+ $unit = $unitStatic;
+ }else{
+ $unit = $currentUnified->unit->toString();
+ }
+
+ if( $unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === "" ){
+ $unitStatic = $unit;
+ }
+
+ if( $unit != '' && !$unitClone ){
+ $unitClone = $current->unit->toString();
+ }
+
+ if( isset($values['']) && $unit !== '' && $unit === $unitStatic ){
+ $j = $values[''];
+ }elseif( isset($values[$unit]) ){
+ $j = $values[$unit];
+ }else{
+
+ if( $unitStatic && $unit !== $unitStatic ){
+ throw new Less_Exception_Compiler( 'incompatible types');
+ }
+ $values[$unit] = count($order);
+ $order[] = $current;
+ continue;
+ }
+
+
+ if( $order[$j]->unit->toString() === "" && $unitClone ){
+ $temp = new Less_Tree_Dimension( $order[$j]->value, $unitClone);
+ $referenceUnified = $temp->unifiy();
+ }else{
+ $referenceUnified = $order[$j]->unify();
+ }
+ if( ($isMin && $currentUnified->value < $referenceUnified->value) || (!$isMin && $currentUnified->value > $referenceUnified->value) ){
+ $order[$j] = $current;
+ }
+ }
+
+ if( count($order) == 1 ){
+ return $order[0];
+ }
+ $args = array();
+ foreach($order as $a){
+ $args[] = $a->toCSS($this->env);
+ }
+ return new Less_Tree_Anonymous( ($isMin?'min(':'max(') . implode(Less_Environment::$_outputMap[','],$args).')');
+ }
+
+ public function min(){
+ $args = func_get_args();
+ return $this->_minmax( true, $args );
+ }
+
+ public function max(){
+ $args = func_get_args();
+ return $this->_minmax( false, $args );
+ }
+
+ public function getunit($n){
+ return new Less_Tree_Anonymous($n->unit);
+ }
+
+ public function argb($color) {
+ return new Less_Tree_Anonymous($color->toARGB());
+ }
+
+ public function percentage($n) {
+ return new Less_Tree_Dimension($n->value * 100, '%');
+ }
+
+ public function color($n) {
+
+ if( $n instanceof Less_Tree_Quoted ){
+ $colorCandidate = $n->value;
+ $returnColor = Less_Tree_Color::fromKeyword($colorCandidate);
+ if( $returnColor ){
+ return $returnColor;
+ }
+ if( preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/',$colorCandidate) ){
+ return new Less_Tree_Color(substr($colorCandidate, 1));
+ }
+ throw new Less_Exception_Compiler("argument must be a color keyword or 3/6 digit hex e.g. #FFF");
+ } else {
+ throw new Less_Exception_Compiler("argument must be a string");
+ }
+ }
+
+
+ public function iscolor($n) {
+ return $this->_isa($n, 'Less_Tree_Color');
+ }
+
+ public function isnumber($n) {
+ return $this->_isa($n, 'Less_Tree_Dimension');
+ }
+
+ public function isstring($n) {
+ return $this->_isa($n, 'Less_Tree_Quoted');
+ }
+
+ public function iskeyword($n) {
+ return $this->_isa($n, 'Less_Tree_Keyword');
+ }
+
+ public function isurl($n) {
+ return $this->_isa($n, 'Less_Tree_Url');
+ }
+
+ public function ispixel($n) {
+ return $this->isunit($n, 'px');
+ }
+
+ public function ispercentage($n) {
+ return $this->isunit($n, '%');
+ }
+
+ public function isem($n) {
+ return $this->isunit($n, 'em');
+ }
+
+ /**
+ * @param string $unit
+ */
+ public function isunit( $n, $unit ){
+ return ($n instanceof Less_Tree_Dimension) && $n->unit->is( ( property_exists($unit,'value') ? $unit->value : $unit) ) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ /**
+ * @param string $type
+ */
+ private function _isa($n, $type) {
+ return is_a($n, $type) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ public function tint($color, $amount) {
+ return $this->mix( $this->rgb(255,255,255), $color, $amount);
+ }
+
+ public function shade($color, $amount) {
+ return $this->mix($this->rgb(0, 0, 0), $color, $amount);
+ }
+
+ public function extract($values, $index ){
+ $index = (int)$index->value - 1; // (1-based index)
+ // handle non-array values as an array of length 1
+ // return 'undefined' if index is invalid
+ if( property_exists($values,'value') && is_array($values->value) ){
+ if( isset($values->value[$index]) ){
+ return $values->value[$index];
+ }
+ return null;
+
+ }elseif( (int)$index === 0 ){
+ return $values;
+ }
+
+ return null;
+ }
+
+ function length($values){
+ $n = (property_exists($values,'value') && is_array($values->value)) ? count($values->value) : 1;
+ return new Less_Tree_Dimension($n);
+ }
+
+ function datauri($mimetypeNode, $filePathNode = null ) {
+
+ $filePath = ( $filePathNode ? $filePathNode->value : null );
+ $mimetype = $mimetypeNode->value;
+
+ $args = 2;
+ if( !$filePath ){
+ $filePath = $mimetype;
+ $args = 1;
+ }
+
+ $filePath = str_replace('\\','/',$filePath);
+ if( Less_Environment::isPathRelative($filePath) ){
+
+ if( Less_Parser::$options['relativeUrls'] ){
+ $temp = $this->currentFileInfo['currentDirectory'];
+ } else {
+ $temp = $this->currentFileInfo['entryPath'];
+ }
+
+ if( !empty($temp) ){
+ $filePath = Less_Environment::normalizePath(rtrim($temp,'/').'/'.$filePath);
+ }
+
+ }
+
+
+ // detect the mimetype if not given
+ if( $args < 2 ){
+
+ /* incomplete
+ $mime = require('mime');
+ mimetype = mime.lookup(path);
+
+ // use base 64 unless it's an ASCII or UTF-8 format
+ var charset = mime.charsets.lookup(mimetype);
+ useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
+ if (useBase64) mimetype += ';base64';
+ */
+
+ $mimetype = Less_Mime::lookup($filePath);
+
+ $charset = Less_Mime::charsets_lookup($mimetype);
+ $useBase64 = !in_array($charset,array('US-ASCII', 'UTF-8'));
+ if( $useBase64 ){ $mimetype .= ';base64'; }
+
+ }else{
+ $useBase64 = preg_match('/;base64$/',$mimetype);
+ }
+
+
+ if( file_exists($filePath) ){
+ $buf = @file_get_contents($filePath);
+ }else{
+ $buf = false;
+ }
+
+
+ // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
+ // and the --ieCompat flag is enabled, return a normal url() instead.
+ $DATA_URI_MAX_KB = 32;
+ $fileSizeInKB = round( strlen($buf) / 1024 );
+ if( $fileSizeInKB >= $DATA_URI_MAX_KB ){
+ $url = new Less_Tree_Url( ($filePathNode ? $filePathNode : $mimetypeNode), $this->currentFileInfo);
+ return $url->compile($this);
+ }
+
+ if( $buf ){
+ $buf = $useBase64 ? base64_encode($buf) : rawurlencode($buf);
+ $filePath = '"data:' . $mimetype . ',' . $buf . '"';
+ }
+
+ return new Less_Tree_Url( new Less_Tree_Anonymous($filePath) );
+ }
+
+ //svg-gradient
+ function svggradient( $direction ){
+
+ $throw_message = 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]';
+ $arguments = func_get_args();
+
+ if( count($arguments) < 3 ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+
+ $stops = array_slice($arguments,1);
+ $gradientType = 'linear';
+ $rectangleDimension = 'x="0" y="0" width="1" height="1"';
+ $useBase64 = true;
+ $directionValue = $direction->toCSS();
+
+
+ switch( $directionValue ){
+ case "to bottom":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
+ break;
+ case "to right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
+ break;
+ case "to bottom right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
+ break;
+ case "to top right":
+ $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
+ break;
+ case "ellipse":
+ case "ellipse at center":
+ $gradientType = "radial";
+ $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
+ $rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
+ break;
+ default:
+ throw new Less_Exception_Compiler( "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" );
+ }
+
+ $returner = '' .
+ '' .
+ '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>';
+
+ for( $i = 0; $i < count($stops); $i++ ){
+ if( is_object($stops[$i]) && property_exists($stops[$i],'value') ){
+ $color = $stops[$i]->value[0];
+ $position = $stops[$i]->value[1];
+ }else{
+ $color = $stops[$i];
+ $position = null;
+ }
+
+ if( !($color instanceof Less_Tree_Color) || (!(($i === 0 || $i+1 === count($stops)) && $position === null) && !($position instanceof Less_Tree_Dimension)) ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+ if( $position ){
+ $positionValue = $position->toCSS();
+ }elseif( $i === 0 ){
+ $positionValue = '0%';
+ }else{
+ $positionValue = '100%';
+ }
+ $alpha = $color->alpha;
+ $returner .= ' ';
+ }
+
+ $returner .= '' . $gradientType . 'Gradient> ';
+
+
+ if( $useBase64 ){
+ $returner = "'data:image/svg+xml;base64,".base64_encode($returner)."'";
+ }else{
+ $returner = "'data:image/svg+xml,".$returner."'";
+ }
+
+ return new Less_Tree_URL( new Less_Tree_Anonymous( $returner ) );
+ }
+
+
+ /**
+ * @param string $type
+ */
+ private static function Expected( $type, $arg ){
+
+ $debug = debug_backtrace();
+ array_shift($debug);
+ $last = array_shift($debug);
+ $last = array_intersect_key($last,array('function'=>'','class'=>'','line'=>''));
+
+ $message = 'Object of type '.get_class($arg).' passed to darken function. Expecting `'.$type.'`. '.$arg->toCSS().'. '.print_r($last,true);
+ throw new Less_Exception_Compiler($message);
+
+ }
+
+ /**
+ * Php version of javascript's `encodeURIComponent` function
+ *
+ * @param string $string The string to encode
+ * @return string The encoded string
+ */
+ public static function encodeURIComponent($string){
+ $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
+ return strtr(rawurlencode($string), $revert);
+ }
+
+
+ // Color Blending
+ // ref: http://www.w3.org/TR/compositing-1
+
+ public function colorBlend( $mode, $color1, $color2 ){
+ $ab = $color1->alpha; // backdrop
+ $as = $color2->alpha; // source
+ $r = array(); // result
+
+ $ar = $as + $ab * (1 - $as);
+ for( $i = 0; $i < 3; $i++ ){
+ $cb = $color1->rgb[$i] / 255;
+ $cs = $color2->rgb[$i] / 255;
+ $cr = call_user_func( $mode, $cb, $cs );
+ if( $ar ){
+ $cr = ($as * $cs + $ab * ($cb - $as * ($cb + $cs - $cr))) / $ar;
+ }
+ $r[$i] = $cr * 255;
+ }
+
+ return new Less_Tree_Color($r, $ar);
+ }
+
+ public function multiply($color1, $color2 ){
+ return $this->colorBlend( array($this,'colorBlendMultiply'), $color1, $color2 );
+ }
+
+ private function colorBlendMultiply($cb, $cs){
+ return $cb * $cs;
+ }
+
+ public function screen($color1, $color2 ){
+ return $this->colorBlend( array($this,'colorBlendScreen'), $color1, $color2 );
+ }
+
+ private function colorBlendScreen( $cb, $cs){
+ return $cb + $cs - $cb * $cs;
+ }
+
+ public function overlay($color1, $color2){
+ return $this->colorBlend( array($this,'colorBlendOverlay'), $color1, $color2 );
+ }
+
+ private function colorBlendOverlay($cb, $cs ){
+ $cb *= 2;
+ return ($cb <= 1)
+ ? $this->colorBlendMultiply($cb, $cs)
+ : $this->colorBlendScreen($cb - 1, $cs);
+ }
+
+ public function softlight($color1, $color2){
+ return $this->colorBlend( array($this,'colorBlendSoftlight'), $color1, $color2 );
+ }
+
+ private function colorBlendSoftlight($cb, $cs ){
+ $d = 1;
+ $e = $cb;
+ if( $cs > 0.5 ){
+ $e = 1;
+ $d = ($cb > 0.25) ? sqrt($cb)
+ : ((16 * $cb - 12) * $cb + 4) * $cb;
+ }
+ return $cb - (1 - 2 * $cs) * $e * ($d - $cb);
+ }
+
+ public function hardlight($color1, $color2){
+ return $this->colorBlend( array($this,'colorBlendHardlight'), $color1, $color2 );
+ }
+
+ private function colorBlendHardlight( $cb, $cs ){
+ return $this->colorBlendOverlay($cs, $cb);
+ }
+
+ public function difference($color1, $color2) {
+ return $this->colorBlend( array($this,'colorBlendDifference'), $color1, $color2 );
+ }
+
+ private function colorBlendDifference( $cb, $cs ){
+ return abs($cb - $cs);
+ }
+
+ public function exclusion( $color1, $color2 ){
+ return $this->colorBlend( array($this,'colorBlendExclusion'), $color1, $color2 );
+ }
+
+ private function colorBlendExclusion( $cb, $cs ){
+ return $cb + $cs - 2 * $cb * $cs;
+ }
+
+ public function average($color1, $color2){
+ return $this->colorBlend( array($this,'colorBlendAverage'), $color1, $color2 );
+ }
+
+ // non-w3c functions:
+ function colorBlendAverage($cb, $cs ){
+ return ($cb + $cs) / 2;
+ }
+
+ public function negation($color1, $color2 ){
+ return $this->colorBlend( array($this,'colorBlendNegation'), $color1, $color2 );
+ }
+
+ function colorBlendNegation($cb, $cs){
+ return 1 - abs($cb + $cs - 1);
+ }
+
+ // ~ End of Color Blending
+
+}
+
+
+/**
+ * Mime lookup
+ *
+ * @package Less
+ * @subpackage node
+ */
+class Less_Mime{
+
+ // this map is intentionally incomplete
+ // if you want more, install 'mime' dep
+ static $_types = array(
+ '.htm' => 'text/html',
+ '.html'=> 'text/html',
+ '.gif' => 'image/gif',
+ '.jpg' => 'image/jpeg',
+ '.jpeg'=> 'image/jpeg',
+ '.png' => 'image/png'
+ );
+
+ static function lookup( $filepath ){
+ $parts = explode('.',$filepath);
+ $ext = '.'.strtolower(array_pop($parts));
+
+ if( !isset(self::$_types[$ext]) ){
+ return null;
+ }
+ return self::$_types[$ext];
+ }
+
+ static function charsets_lookup( $type = null ){
+ // assumes all text types are UTF-8
+ return $type && preg_match('/^text\//',$type) ? 'UTF-8' : '';
+ }
+}
+
+/**
+ * Tree
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree{
+
+ public $cache_string;
+
+ public function toCSS(){
+ $output = new Less_Output();
+ $this->genCSS($output);
+ return $output->toString();
+ }
+
+
+ /**
+ * Generate CSS by adding it to the output object
+ *
+ * @param Less_Output $output The output
+ * @return void
+ */
+ public function genCSS($output){}
+
+
+ /**
+ * @param Less_Tree_Ruleset[] $rules
+ */
+ public static function outputRuleset( $output, $rules ){
+
+ $ruleCnt = count($rules);
+ Less_Environment::$tabLevel++;
+
+
+ // Compressed
+ if( Less_Parser::$options['compress'] ){
+ $output->add('{');
+ for( $i = 0; $i < $ruleCnt; $i++ ){
+ $rules[$i]->genCSS( $output );
+ }
+
+ $output->add( '}' );
+ Less_Environment::$tabLevel--;
+ return;
+ }
+
+
+ // Non-compressed
+ $tabSetStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel-1 );
+ $tabRuleStr = $tabSetStr.' ';
+
+ $output->add( " {" );
+ for($i = 0; $i < $ruleCnt; $i++ ){
+ $output->add( $tabRuleStr );
+ $rules[$i]->genCSS( $output );
+ }
+ Less_Environment::$tabLevel--;
+ $output->add( $tabSetStr.'}' );
+
+ }
+
+ public function accept($visitor){}
+
+
+ public static function ReferencedArray($rules){
+ foreach($rules as $rule){
+ if( method_exists($rule, 'markReferenced') ){
+ $rule->markReferenced();
+ }
+ }
+ }
+
+
+ /**
+ * Requires php 5.3+
+ */
+ public static function __set_state($args){
+
+ $class = get_called_class();
+ $obj = new $class(null,null,null,null);
+ foreach($args as $key => $val){
+ $obj->$key = $val;
+ }
+ return $obj;
+ }
+
+}
+
+/**
+ * Parser output
+ *
+ * @package Less
+ * @subpackage output
+ */
+class Less_Output{
+
+ /**
+ * Output holder
+ *
+ * @var string
+ */
+ protected $strs = array();
+
+ /**
+ * Adds a chunk to the stack
+ *
+ * @param string $chunk The chunk to output
+ * @param Less_FileInfo $fileInfo The file information
+ * @param integer $index The index
+ * @param mixed $mapLines
+ */
+ public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
+ $this->strs[] = $chunk;
+ }
+
+ /**
+ * Is the output empty?
+ *
+ * @return boolean
+ */
+ public function isEmpty(){
+ return count($this->strs) === 0;
+ }
+
+
+ /**
+ * Converts the output to string
+ *
+ * @return string
+ */
+ public function toString(){
+ return implode('',$this->strs);
+ }
+
+}
+
+/**
+ * Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor{
+
+ var $methods = array();
+ var $_visitFnCache = array();
+
+ function __construct(){
+ $this->_visitFnCache = get_class_methods(get_class($this));
+ $this->_visitFnCache = array_flip($this->_visitFnCache);
+ }
+
+ function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $this->$funcName( $node, $visitDeeper );
+
+ if( $visitDeeper ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ function visitArray( $nodes ){
+
+ array_map( array($this,'visitObj'), $nodes);
+ return $nodes;
+ }
+}
+
+
+
+/**
+ * Replacing Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_VisitorReplacing extends Less_Visitor{
+
+ function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $node = $this->$funcName( $node, $visitDeeper );
+
+ if( $node ){
+ if( $visitDeeper && is_object($node) ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ function visitArray( $nodes ){
+
+ $newNodes = array();
+ foreach($nodes as $node){
+ $evald = $this->visitObj($node);
+ if( $evald ){
+ if( is_array($evald) ){
+ self::flatten($evald,$newNodes);
+ }else{
+ $newNodes[] = $evald;
+ }
+ }
+ }
+ return $newNodes;
+ }
+
+ function flatten( $arr, &$out ){
+
+ foreach($arr as $item){
+ if( !is_array($item) ){
+ $out[] = $item;
+ continue;
+ }
+
+ foreach($item as $nestedItem){
+ if( is_array($nestedItem) ){
+ self::flatten( $nestedItem, $out);
+ }else{
+ $out[] = $nestedItem;
+ }
+ }
+ }
+
+ return $out;
+ }
+
+}
+
+
+
+
+/**
+ * Configurable
+ *
+ * @package Less
+ * @subpackage Core
+ */
+abstract class Less_Configurable {
+
+ /**
+ * Array of options
+ *
+ * @var array
+ */
+ protected $options = array();
+
+ /**
+ * Array of default options
+ *
+ * @var array
+ */
+ protected $defaultOptions = array();
+
+
+ /**
+ * Set options
+ *
+ * If $options is an object it will be converted into an array by called
+ * it's toArray method.
+ *
+ * @throws Exception
+ * @param array|object $options
+ *
+ */
+ public function setOptions($options){
+ $options = array_intersect_key($options,$this->defaultOptions);
+ $this->options = array_merge($this->defaultOptions, $this->options, $options);
+ }
+
+
+ /**
+ * Get an option value by name
+ *
+ * If the option is empty or not set a NULL value will be returned.
+ *
+ * @param string $name
+ * @param mixed $default Default value if confiuration of $name is not present
+ * @return mixed
+ */
+ public function getOption($name, $default = null){
+ if(isset($this->options[$name])){
+ return $this->options[$name];
+ }
+ return $default;
+ }
+
+
+ /**
+ * Set an option
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function setOption($name, $value){
+ $this->options[$name] = $value;
+ }
+
+}
+
+/**
+ * Alpha
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Alpha extends Less_Tree{
+ public $value;
+ public $type = 'Alpha';
+
+ public function __construct($val){
+ $this->value = $val;
+ }
+
+ //function accept( $visitor ){
+ // $this->value = $visitor->visit( $this->value );
+ //}
+
+ public function compile($env){
+
+ if( is_object($this->value) ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( "alpha(opacity=" );
+
+ if( is_string($this->value) ){
+ $output->add( $this->value );
+ }else{
+ $this->value->genCSS( $output);
+ }
+
+ $output->add( ')' );
+ }
+
+ public function toCSS(){
+ return "alpha(opacity=" . (is_string($this->value) ? $this->value : $this->value->toCSS()) . ")";
+ }
+
+
+}
+
+/**
+ * Anonymous
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Anonymous extends Less_Tree{
+ public $value;
+ public $quote;
+ public $index;
+ public $mapLines;
+ public $currentFileInfo;
+ public $type = 'Anonymous';
+
+ /**
+ * @param integer $index
+ * @param boolean $mapLines
+ */
+ public function __construct($value, $index = null, $currentFileInfo = null, $mapLines = null ){
+ $this->value = $value;
+ $this->index = $index;
+ $this->mapLines = $mapLines;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous($this->value, $this->index, $this->currentFileInfo, $this->mapLines);
+ }
+
+ function compare($x){
+ if( !is_object($x) ){
+ return -1;
+ }
+
+ $left = $this->toCSS();
+ $right = $x->toCSS();
+
+ if( $left === $right ){
+ return 0;
+ }
+
+ return $left < $right ? -1 : 1;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->value, $this->currentFileInfo, $this->index, $this->mapLines );
+ }
+
+ public function toCSS(){
+ return $this->value;
+ }
+
+}
+
+
+/**
+ * Assignment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Assignment extends Less_Tree{
+
+ public $key;
+ public $value;
+ public $type = 'Assignment';
+
+ function __construct($key, $val) {
+ $this->key = $key;
+ $this->value = $val;
+ }
+
+ function accept( $visitor ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+
+ public function compile($env) {
+ return new Less_Tree_Assignment( $this->key, $this->value->compile($env));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->key . '=' );
+ $this->value->genCSS( $output );
+ }
+
+ public function toCss(){
+ return $this->key . '=' . $this->value->toCSS();
+ }
+}
+
+
+/**
+ * Attribute
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Attribute extends Less_Tree{
+
+ public $key;
+ public $op;
+ public $value;
+ public $type = 'Attribute';
+
+ function __construct($key, $op, $value){
+ $this->key = $key;
+ $this->op = $op;
+ $this->value = $value;
+ }
+
+ function compile($env){
+
+ $key_obj = is_object($this->key);
+ $val_obj = is_object($this->value);
+
+ if( !$key_obj && !$val_obj ){
+ return $this;
+ }
+
+ return new Less_Tree_Attribute(
+ $key_obj ? $this->key->compile($env) : $this->key ,
+ $this->op,
+ $val_obj ? $this->value->compile($env) : $this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ function toCSS(){
+ $value = $this->key;
+
+ if( $this->op ){
+ $value .= $this->op;
+ $value .= (is_object($this->value) ? $this->value->toCSS() : $this->value);
+ }
+
+ return '[' . $value . ']';
+ }
+}
+
+
+/**
+ * Call
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Call extends Less_Tree{
+ public $value;
+
+ var $name;
+ var $args;
+ var $index;
+ var $currentFileInfo;
+ public $type = 'Call';
+
+ public function __construct($name, $args, $index, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->args = $args;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ function accept( $visitor ){
+ $this->args = $visitor->visitArray( $this->args );
+ }
+
+ //
+ // When evaluating a function call,
+ // we either find the function in `tree.functions` [1],
+ // in which case we call it, passing the evaluated arguments,
+ // or we simply print it out as it appeared originally [2].
+ //
+ // The *functions.js* file contains the built-in functions.
+ //
+ // The reason why we evaluate the arguments, is in the case where
+ // we try to pass a variable to a function, like: `saturate(@color)`.
+ // The function should receive the value, not the variable.
+ //
+ public function compile($env=null){
+ $args = array();
+ foreach($this->args as $a){
+ $args[] = $a->compile($env);
+ }
+
+ $nameLC = strtolower($this->name);
+ switch($nameLC){
+ case '%':
+ $nameLC = '_percent';
+ break;
+
+ case 'get-unit':
+ $nameLC = 'getunit';
+ break;
+
+ case 'data-uri':
+ $nameLC = 'datauri';
+ break;
+
+ case 'svg-gradient':
+ $nameLC = 'svggradient';
+ break;
+ }
+
+ $result = null;
+ if( $nameLC === 'default' ){
+ $result = Less_Tree_DefaultFunc::compile();
+
+ }else{
+
+ if( method_exists('Less_Functions',$nameLC) ){ // 1.
+ try {
+
+ $func = new Less_Functions($env, $this->currentFileInfo);
+ $result = call_user_func_array( array($func,$nameLC),$args);
+
+ } catch (Exception $e) {
+ throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
+ }
+ }
+ }
+
+ if( $result !== null ){
+ return $result;
+ }
+
+
+ return new Less_Tree_Call( $this->name, $args, $this->index, $this->currentFileInfo );
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( $this->name . '(', $this->currentFileInfo, $this->index );
+ $args_len = count($this->args);
+ for($i = 0; $i < $args_len; $i++ ){
+ $this->args[$i]->genCSS( $output );
+ if( $i + 1 < $args_len ){
+ $output->add( ', ' );
+ }
+ }
+
+ $output->add( ')' );
+ }
+
+
+ //public function toCSS(){
+ // return $this->compile()->toCSS();
+ //}
+
+}
+
+
+/**
+ * Color
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Color extends Less_Tree{
+ public $rgb;
+ public $alpha;
+ public $isTransparentKeyword;
+ public $type = 'Color';
+
+ public function __construct($rgb, $a = 1, $isTransparentKeyword = null ){
+
+ if( $isTransparentKeyword ){
+ $this->rgb = $rgb;
+ $this->alpha = $a;
+ $this->isTransparentKeyword = true;
+ return;
+ }
+
+ $this->rgb = array();
+ if( is_array($rgb) ){
+ $this->rgb = $rgb;
+ }else if( strlen($rgb) == 6 ){
+ foreach(str_split($rgb, 2) as $c){
+ $this->rgb[] = hexdec($c);
+ }
+ }else{
+ foreach(str_split($rgb, 1) as $c){
+ $this->rgb[] = hexdec($c.$c);
+ }
+ }
+ $this->alpha = is_numeric($a) ? $a : 1;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function luma(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+
+ $r = ($r <= 0.03928) ? $r / 12.92 : pow((($r + 0.055) / 1.055), 2.4);
+ $g = ($g <= 0.03928) ? $g / 12.92 : pow((($g + 0.055) / 1.055), 2.4);
+ $b = ($b <= 0.03928) ? $b / 12.92 : pow((($b + 0.055) / 1.055), 2.4);
+
+ return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ public function toCSS( $doNotCompress = false ){
+ $compress = Less_Parser::$options['compress'] && !$doNotCompress;
+ $alpha = Less_Functions::fround( $this->alpha );
+
+
+ //
+ // If we have some transparency, the only way to represent it
+ // is via `rgba`. Otherwise, we use the hex representation,
+ // which has better compatibility with older browsers.
+ // Values are capped between `0` and `255`, rounded and zero-padded.
+ //
+ if( $alpha < 1 ){
+ if( $alpha === 0 && isset($this->isTransparentKeyword) && $this->isTransparentKeyword ){
+ return 'transparent';
+ }
+
+ $values = array();
+ foreach($this->rgb as $c){
+ $values[] = Less_Functions::clamp( round($c), 255);
+ }
+ $values[] = $alpha;
+
+ $glue = ($compress ? ',' : ', ');
+ return "rgba(" . implode($glue, $values) . ")";
+ }else{
+
+ $color = $this->toRGB();
+
+ if( $compress ){
+
+ // Convert color to short format
+ if( $color[1] === $color[2] && $color[3] === $color[4] && $color[5] === $color[6]) {
+ $color = '#'.$color[1] . $color[3] . $color[5];
+ }
+ }
+
+ return $color;
+ }
+ }
+
+ //
+ // Operations have to be done per-channel, if not,
+ // channels will spill onto each other. Once we have
+ // our result, in the form of an integer triplet,
+ // we create a new Color node to hold the result.
+ //
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other) {
+ $rgb = array();
+ $alpha = $this->alpha * (1 - $other->alpha) + $other->alpha;
+ for ($c = 0; $c < 3; $c++) {
+ $rgb[$c] = Less_Functions::operate( $op, $this->rgb[$c], $other->rgb[$c]);
+ }
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function toRGB(){
+ return $this->toHex($this->rgb);
+ }
+
+ public function toHSL(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+ $l = ($max + $min) / 2;
+ $d = $max - $min;
+
+ $h = $s = 0;
+ if( $max !== $min ){
+ $s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
+
+ switch ($max) {
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h' => $h * 360, 's' => $s, 'l' => $l, 'a' => $a );
+ }
+
+ //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+ function toHSV() {
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+
+ $v = $max;
+
+ $d = $max - $min;
+ if ($max === 0) {
+ $s = 0;
+ } else {
+ $s = $d / $max;
+ }
+
+ $h = 0;
+ if( $max !== $min ){
+ switch($max){
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h'=> $h * 360, 's'=> $s, 'v'=> $v, 'a' => $a );
+ }
+
+ public function toARGB(){
+ $argb = array_merge( (array) Less_Parser::round($this->alpha * 255), $this->rgb);
+ return $this->toHex( $argb );
+ }
+
+ public function compare($x){
+
+ if( !property_exists( $x, 'rgb' ) ){
+ return -1;
+ }
+
+
+ return ($x->rgb[0] === $this->rgb[0] &&
+ $x->rgb[1] === $this->rgb[1] &&
+ $x->rgb[2] === $this->rgb[2] &&
+ $x->alpha === $this->alpha) ? 0 : -1;
+ }
+
+ function toHex( $v ){
+
+ $ret = '#';
+ foreach($v as $c){
+ $c = Less_Functions::clamp( Less_Parser::round($c), 255);
+ if( $c < 16 ){
+ $ret .= '0';
+ }
+ $ret .= dechex($c);
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * @param string $keyword
+ */
+ public static function fromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return new Less_Tree_Color(substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return new Less_Tree_Color( array(0, 0, 0), 0, true);
+ }
+ }
+
+}
+
+
+/**
+ * Comment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Comment extends Less_Tree{
+
+ public $value;
+ public $silent;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $type = 'Comment';
+
+ public function __construct($value, $silent, $index = null, $currentFileInfo = null ){
+ $this->value = $value;
+ $this->silent = !! $silent;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ //if( $this->debugInfo ){
+ //$output->add( tree.debugInfo($env, $this), $this->currentFileInfo, $this->index);
+ //}
+ $output->add( trim($this->value) );//TODO shouldn't need to trim, we shouldn't grab the \n
+ }
+
+ public function toCSS(){
+ return Less_Parser::$options['compress'] ? '' : $this->value;
+ }
+
+ public function isSilent(){
+ $isReference = ($this->currentFileInfo && isset($this->currentFileInfo['reference']) && (!isset($this->isReferenced) || !$this->isReferenced) );
+ $isCompressed = Less_Parser::$options['compress'] && !preg_match('/^\/\*!/', $this->value);
+ return $this->silent || $isReference || $isCompressed;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ }
+
+}
+
+
+/**
+ * Condition
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Condition extends Less_Tree{
+
+ public $op;
+ public $lvalue;
+ public $rvalue;
+ public $index;
+ public $negate;
+ public $type = 'Condition';
+
+ public function __construct($op, $l, $r, $i = 0, $negate = false) {
+ $this->op = trim($op);
+ $this->lvalue = $l;
+ $this->rvalue = $r;
+ $this->index = $i;
+ $this->negate = $negate;
+ }
+
+ public function accept($visitor){
+ $this->lvalue = $visitor->visitObj( $this->lvalue );
+ $this->rvalue = $visitor->visitObj( $this->rvalue );
+ }
+
+ public function compile($env) {
+ $a = $this->lvalue->compile($env);
+ $b = $this->rvalue->compile($env);
+
+ switch( $this->op ){
+ case 'and':
+ $result = $a && $b;
+ break;
+
+ case 'or':
+ $result = $a || $b;
+ break;
+
+ default:
+ if( Less_Parser::is_method($a, 'compare') ){
+ $result = $a->compare($b);
+ }elseif( Less_Parser::is_method($b, 'compare') ){
+ $result = $b->compare($a);
+ }else{
+ throw new Less_Exception_Compiler('Unable to perform comparison', null, $this->index);
+ }
+
+ switch ($result) {
+ case -1:
+ $result = $this->op === '<' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 0:
+ $result = $this->op === '=' || $this->op === '>=' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 1:
+ $result = $this->op === '>' || $this->op === '>=';
+ break;
+ }
+ break;
+ }
+
+ return $this->negate ? !$result : $result;
+ }
+
+}
+
+
+/**
+ * DefaultFunc
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DefaultFunc{
+
+ static $error_;
+ static $value_;
+
+ static function compile(){
+ if( self::$error_ ){
+ throw Exception(self::$error_);
+ }
+ if( self::$value_ !== null ){
+ return self::$value_ ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+ }
+
+ static function value( $v ){
+ self::$value_ = $v;
+ }
+
+ static function error( $e ){
+ self::$error_ = $e;
+ }
+
+ static function reset(){
+ self::$value_ = self::$error_ = null;
+ }
+}
+
+/**
+ * DetachedRuleset
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DetachedRuleset extends Less_Tree{
+
+ public $ruleset;
+ public $frames;
+ public $type = 'DetachedRuleset';
+
+ function __construct( $ruleset, $frames = null ){
+ $this->ruleset = $ruleset;
+ $this->frames = $frames;
+ }
+
+ function accept($visitor) {
+ $this->ruleset = $visitor->visitObj($this->ruleset);
+ }
+
+ function compile($env){
+ if( $this->frames ){
+ $frames = $this->frames;
+ }else{
+ $frames = $env->frames;
+ }
+ return new Less_Tree_DetachedRuleset($this->ruleset, $frames);
+ }
+
+ function callEval($env) {
+ if( $this->frames ){
+ return $this->ruleset->compile( $env->copyEvalEnv( array_merge($this->frames,$env->frames) ) );
+ }
+ return $this->ruleset->compile( $env );
+ }
+}
+
+
+
+/**
+ * Dimension
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Dimension extends Less_Tree{
+
+ public $value;
+ public $unit;
+ public $type = 'Dimension';
+
+ public function __construct($value, $unit = null){
+ $this->value = floatval($value);
+
+ if( $unit && ($unit instanceof Less_Tree_Unit) ){
+ $this->unit = $unit;
+ }elseif( $unit ){
+ $this->unit = new Less_Tree_Unit( array($unit) );
+ }else{
+ $this->unit = new Less_Tree_Unit( );
+ }
+ }
+
+ function accept( $visitor ){
+ $this->unit = $visitor->visitObj( $this->unit );
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function toColor() {
+ return new Less_Tree_Color(array($this->value, $this->value, $this->value));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( Less_Parser::$options['strictUnits'] && !$this->unit->isSingular() ){
+ throw new Less_Exception_Compiler("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".$this->unit->toString());
+ }
+
+ $value = Less_Functions::fround( $this->value );
+ $strValue = (string)$value;
+
+ if( $value !== 0 && $value < 0.000001 && $value > -0.000001 ){
+ // would be output 1e-6 etc.
+ $strValue = number_format($strValue,10);
+ $strValue = preg_replace('/\.?0+$/','', $strValue);
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ // Zero values doesn't need a unit
+ if( $value === 0 && $this->unit->isLength() ){
+ $output->add( $strValue );
+ return $strValue;
+ }
+
+ // Float values doesn't need a leading zero
+ if( $value > 0 && $value < 1 && $strValue[0] === '0' ){
+ $strValue = substr($strValue,1);
+ }
+ }
+
+ $output->add( $strValue );
+ $this->unit->genCSS( $output );
+ }
+
+ public function __toString(){
+ return $this->toCSS();
+ }
+
+ // In an operation between two Dimensions,
+ // we default to the first Dimension's unit,
+ // so `1px + 2em` will yield `3px`.
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other){
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ $unit = clone $this->unit;
+
+ if( $op === '+' || $op === '-' ){
+
+ if( !$unit->numerator && !$unit->denominator ){
+ $unit->numerator = $other->unit->numerator;
+ $unit->denominator = $other->unit->denominator;
+ }elseif( !$other->unit->numerator && !$other->unit->denominator ){
+ // do nothing
+ }else{
+ $other = $other->convertTo( $this->unit->usedUnits());
+
+ if( Less_Parser::$options['strictUnits'] && $other->unit->toString() !== $unit->toCSS() ){
+ throw new Less_Exception_Compiler("Incompatible units. Change the units or use the unit function. Bad units: '".$unit->toString() . "' and ".$other->unit->toString()+"'.");
+ }
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ }
+ }elseif( $op === '*' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->numerator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->denominator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }elseif( $op === '/' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->denominator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->numerator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Dimension) {
+
+ if( $this->unit->isEmpty() || $other->unit->isEmpty() ){
+ $a = $this;
+ $b = $other;
+ } else {
+ $a = $this->unify();
+ $b = $other->unify();
+ if( $a->unit->compare($b->unit) !== 0 ){
+ return -1;
+ }
+ }
+ $aValue = $a->value;
+ $bValue = $b->value;
+
+ if ($bValue > $aValue) {
+ return -1;
+ } elseif ($bValue < $aValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ function unify() {
+ return $this->convertTo(array('length'=> 'px', 'duration'=> 's', 'angle' => 'rad' ));
+ }
+
+ function convertTo($conversions) {
+ $value = $this->value;
+ $unit = clone $this->unit;
+
+ if( is_string($conversions) ){
+ $derivedConversions = array();
+ foreach( Less_Tree_UnitConversions::$groups as $i ){
+ if( isset(Less_Tree_UnitConversions::${$i}[$conversions]) ){
+ $derivedConversions = array( $i => $conversions);
+ }
+ }
+ $conversions = $derivedConversions;
+ }
+
+
+ foreach($conversions as $groupName => $targetUnit){
+ $group = Less_Tree_UnitConversions::${$groupName};
+
+ //numerator
+ foreach($unit->numerator as $i => $atomicUnit){
+ $atomicUnit = $unit->numerator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value * ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->numerator[$i] = $targetUnit;
+ }
+
+ //denominator
+ foreach($unit->denominator as $i => $atomicUnit){
+ $atomicUnit = $unit->denominator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value / ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->denominator[$i] = $targetUnit;
+ }
+ }
+
+ $unit->cancel();
+
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+}
+
+
+/**
+ * Directive
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Directive extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $rules;
+ public $index;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $debugInfo;
+ public $type = 'Directive';
+
+ public function __construct($name, $value = null, $rules, $index = null, $currentFileInfo = null, $debugInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ if( $rules ){
+ $this->rules = $rules;
+ $this->rules->allowImports = true;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->debugInfo = $debugInfo;
+ }
+
+
+ function accept( $visitor ){
+ if( $this->rules ){
+ $this->rules = $visitor->visitObj( $this->rules );
+ }
+ if( $this->value ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $value = $this->value;
+ $rules = $this->rules;
+ $output->add( $this->name, $this->currentFileInfo, $this->index );
+ if( $this->value ){
+ $output->add(' ');
+ $this->value->genCSS($output);
+ }
+ if( $this->rules ){
+ Less_Tree::outputRuleset( $output, array($this->rules));
+ } else {
+ $output->add(';');
+ }
+ }
+
+ public function compile($env){
+
+ $value = $this->value;
+ $rules = $this->rules;
+ if( $value ){
+ $value = $value->compile($env);
+ }
+
+ if( $rules ){
+ $rules = $rules->compile($env);
+ $rules->root = true;
+ }
+
+ return new Less_Tree_Directive( $this->name, $value, $rules, $this->index, $this->currentFileInfo, $this->debugInfo );
+ }
+
+
+ public function variable($name){
+ if( $this->rules ){
+ return $this->rules->variable($name);
+ }
+ }
+
+ public function find($selector){
+ if( $this->rules ){
+ return $this->rules->find($selector, $this);
+ }
+ }
+
+ //rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ if( $this->rules ){
+ Less_Tree::ReferencedArray($this->rules->rules);
+ }
+ }
+
+}
+
+
+/**
+ * Element
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Element extends Less_Tree{
+
+ public $combinator = '';
+ public $value = '';
+ public $index;
+ public $currentFileInfo;
+ public $type = 'Element';
+
+ public $value_is_object = false;
+
+ public function __construct($combinator, $value, $index = null, $currentFileInfo = null ){
+
+ $this->value = $value;
+ $this->value_is_object = is_object($value);
+
+ if( $combinator ){
+ $this->combinator = $combinator;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ function accept( $visitor ){
+ if( $this->value_is_object ){ //object or string
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+ public function compile($env){
+
+ if( Less_Environment::$mixin_stack ){
+ return new Less_Tree_Element($this->combinator, ($this->value_is_object ? $this->value->compile($env) : $this->value), $this->index, $this->currentFileInfo );
+ }
+
+ if( $this->value_is_object ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS(), $this->currentFileInfo, $this->index );
+ }
+
+ public function toCSS(){
+
+ if( $this->value_is_object ){
+ $value = $this->value->toCSS();
+ }else{
+ $value = $this->value;
+ }
+
+
+ if( $value === '' && $this->combinator && $this->combinator === '&' ){
+ return '';
+ }
+
+
+ return Less_Environment::$_outputMap[$this->combinator] . $value;
+ }
+
+}
+
+
+/**
+ * Expression
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Expression extends Less_Tree{
+
+ public $value = array();
+ public $parens = false;
+ public $parensInOp = false;
+ public $type = 'Expression';
+
+ public function __construct( $value, $parens = null ){
+ $this->value = $value;
+ $this->parens = $parens;
+ }
+
+ function accept( $visitor ){
+ $this->value = $visitor->visitArray( $this->value );
+ }
+
+ public function compile($env) {
+
+ $doubleParen = false;
+
+ if( $this->parens && !$this->parensInOp ){
+ Less_Environment::$parensStack++;
+ }
+
+ $returnValue = null;
+ if( $this->value ){
+
+ $count = count($this->value);
+
+ if( $count > 1 ){
+
+ $ret = array();
+ foreach($this->value as $e){
+ $ret[] = $e->compile($env);
+ }
+ $returnValue = new Less_Tree_Expression($ret);
+
+ }else{
+
+ if( ($this->value[0] instanceof Less_Tree_Expression) && $this->value[0]->parens && !$this->value[0]->parensInOp ){
+ $doubleParen = true;
+ }
+
+ $returnValue = $this->value[0]->compile($env);
+ }
+
+ } else {
+ $returnValue = $this;
+ }
+
+ if( $this->parens ){
+ if( !$this->parensInOp ){
+ Less_Environment::$parensStack--;
+
+ }elseif( !Less_Environment::isMathOn() && !$doubleParen ){
+ $returnValue = new Less_Tree_Paren($returnValue);
+
+ }
+ }
+ return $returnValue;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $val_len = count($this->value);
+ for( $i = 0; $i < $val_len; $i++ ){
+ $this->value[$i]->genCSS( $output );
+ if( $i + 1 < $val_len ){
+ $output->add( ' ' );
+ }
+ }
+ }
+
+ function throwAwayComments() {
+
+ if( is_array($this->value) ){
+ $new_value = array();
+ foreach($this->value as $v){
+ if( $v instanceof Less_Tree_Comment ){
+ continue;
+ }
+ $new_value[] = $v;
+ }
+ $this->value = $new_value;
+ }
+ }
+}
+
+
+/**
+ * Extend
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Extend extends Less_Tree{
+
+ public $selector;
+ public $option;
+ public $index;
+ public $selfSelectors = array();
+ public $allowBefore;
+ public $allowAfter;
+ public $firstExtendOnThisSelectorPath;
+ public $type = 'Extend';
+ public $ruleset;
+
+
+ public $object_id;
+ public $parent_ids = array();
+
+ /**
+ * @param integer $index
+ */
+ function __construct($selector, $option, $index){
+ static $i = 0;
+ $this->selector = $selector;
+ $this->option = $option;
+ $this->index = $index;
+
+ switch($option){
+ case "all":
+ $this->allowBefore = true;
+ $this->allowAfter = true;
+ break;
+ default:
+ $this->allowBefore = false;
+ $this->allowAfter = false;
+ break;
+ }
+
+ $this->object_id = $i++;
+ $this->parent_ids = array($this->object_id);
+ }
+
+ function accept( $visitor ){
+ $this->selector = $visitor->visitObj( $this->selector );
+ }
+
+ function compile( $env ){
+ Less_Parser::$has_extends = true;
+ $this->selector = $this->selector->compile($env);
+ return $this;
+ //return new Less_Tree_Extend( $this->selector->compile($env), $this->option, $this->index);
+ }
+
+ function findSelfSelectors( $selectors ){
+ $selfElements = array();
+
+
+ for( $i = 0, $selectors_len = count($selectors); $i < $selectors_len; $i++ ){
+ $selectorElements = $selectors[$i]->elements;
+ // duplicate the logic in genCSS function inside the selector node.
+ // future TODO - move both logics into the selector joiner visitor
+ if( $i && $selectorElements && $selectorElements[0]->combinator === "") {
+ $selectorElements[0]->combinator = ' ';
+ }
+ $selfElements = array_merge( $selfElements, $selectors[$i]->elements );
+ }
+
+ $this->selfSelectors = array(new Less_Tree_Selector($selfElements));
+ }
+
+}
+
+/**
+ * CSS @import node
+ *
+ * The general strategy here is that we don't want to wait
+ * for the parsing to be completed, before we start importing
+ * the file. That's because in the context of a browser,
+ * most of the time will be spent waiting for the server to respond.
+ *
+ * On creation, we push the import path to our import queue, though
+ * `import,push`, we also pass it a callback, which it'll call once
+ * the file has been fetched, and parsed.
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Import extends Less_Tree{
+
+ public $options;
+ public $index;
+ public $path;
+ public $features;
+ public $currentFileInfo;
+ public $css;
+ public $skip;
+ public $root;
+ public $type = 'Import';
+
+ function __construct($path, $features, $options, $index, $currentFileInfo = null ){
+ $this->options = $options;
+ $this->index = $index;
+ $this->path = $path;
+ $this->features = $features;
+ $this->currentFileInfo = $currentFileInfo;
+
+ if( is_array($options) ){
+ $this->options += array('inline'=>false);
+
+ if( isset($this->options['less']) || $this->options['inline'] ){
+ $this->css = !isset($this->options['less']) || !$this->options['less'] || $this->options['inline'];
+ } else {
+ $pathValue = $this->getPath();
+ if( $pathValue && preg_match('/css([\?;].*)?$/',$pathValue) ){
+ $this->css = true;
+ }
+ }
+ }
+ }
+
+//
+// The actual import node doesn't return anything, when converted to CSS.
+// The reason is that it's used at the evaluation stage, so that the rules
+// it imports can be treated like any other rules.
+//
+// In `eval`, we make sure all Import nodes get evaluated, recursively, so
+// we end up with a flat structure, which can easily be imported in the parent
+// ruleset.
+//
+
+ function accept($visitor){
+
+ if( $this->features ){
+ $this->features = $visitor->visitObj($this->features);
+ }
+ $this->path = $visitor->visitObj($this->path);
+
+ if( !$this->options['inline'] && $this->root ){
+ $this->root = $visitor->visit($this->root);
+ }
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ if( $this->css ){
+
+ $output->add( '@import ', $this->currentFileInfo, $this->index );
+
+ $this->path->genCSS( $output );
+ if( $this->features ){
+ $output->add( ' ' );
+ $this->features->genCSS( $output );
+ }
+ $output->add( ';' );
+ }
+ }
+
+ function toCSS(){
+ $features = $this->features ? ' ' . $this->features->toCSS() : '';
+
+ if ($this->css) {
+ return "@import " . $this->path->toCSS() . $features . ";\n";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @return string
+ */
+ function getPath(){
+ if ($this->path instanceof Less_Tree_Quoted) {
+ $path = $this->path->value;
+ return ( isset($this->css) || preg_match('/(\.[a-z]*$)|([\?;].*)$/',$path)) ? $path : $path . '.less';
+ } else if ($this->path instanceof Less_Tree_URL) {
+ return $this->path->value->value;
+ }
+ return null;
+ }
+
+ function compileForImport( $env ){
+ return new Less_Tree_Import( $this->path->compile($env), $this->features, $this->options, $this->index, $this->currentFileInfo);
+ }
+
+ function compilePath($env) {
+ $path = $this->path->compile($env);
+ $rootpath = '';
+ if( $this->currentFileInfo && $this->currentFileInfo['rootpath'] ){
+ $rootpath = $this->currentFileInfo['rootpath'];
+ }
+
+
+ if( !($path instanceof Less_Tree_URL) ){
+ if( $rootpath ){
+ $pathValue = $path->value;
+ // Add the base path if the import is relative
+ if( $pathValue && Less_Environment::isPathRelative($pathValue) ){
+ $path->value = $this->currentFileInfo['uri_root'].$pathValue;
+ }
+ }
+ $path->value = Less_Environment::normalizePath($path->value);
+ }
+
+
+
+ return $path;
+ }
+
+ function compile( $env ){
+
+ $evald = $this->compileForImport($env);
+
+ //get path & uri
+ $path_and_uri = null;
+ if( is_callable(Less_Parser::$options['import_callback']) ){
+ $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$evald);
+ }
+
+ if( !$path_and_uri ){
+ $path_and_uri = $evald->PathAndUri();
+ }
+
+ if( $path_and_uri ){
+ list($full_path, $uri) = $path_and_uri;
+ }else{
+ $full_path = $uri = $evald->getPath();
+ }
+
+
+ //import once
+ if( $evald->skip( $full_path, $env) ){
+ return array();
+ }
+
+ if( $this->options['inline'] ){
+ //todo needs to reference css file not import
+ //$contents = new Less_Tree_Anonymous($this->root, 0, array('filename'=>$this->importedFilename), true );
+
+ Less_Parser::AddParsedFile($full_path);
+ $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
+
+ if( $this->features ){
+ return new Less_Tree_Media( array($contents), $this->features->value );
+ }
+
+ return array( $contents );
+ }
+
+
+ // css ?
+ if( $evald->css ){
+ $features = ( $evald->features ? $evald->features->compile($env) : null );
+ return new Less_Tree_Import( $this->compilePath( $env), $features, $this->options, $this->index);
+ }
+
+
+ return $this->ParseImport( $full_path, $uri, $env );
+ }
+
+
+ /**
+ * Using the import directories, get the full absolute path and uri of the import
+ *
+ * @param Less_Tree_Import $evald
+ */
+ function PathAndUri(){
+
+ $evald_path = $this->getPath();
+
+ if( $evald_path ){
+
+ $import_dirs = array();
+
+ if( Less_Environment::isPathRelative($evald_path) ){
+ //if the path is relative, the file should be in the current directory
+ $import_dirs[ $this->currentFileInfo['currentDirectory'] ] = $this->currentFileInfo['uri_root'];
+
+ }else{
+ //otherwise, the file should be relative to the server root
+ $import_dirs[ $this->currentFileInfo['entryPath'] ] = $this->currentFileInfo['entryUri'];
+
+ //if the user supplied entryPath isn't the actual root
+ $import_dirs[ $_SERVER['DOCUMENT_ROOT'] ] = '';
+
+ }
+
+ // always look in user supplied import directories
+ $import_dirs = array_merge( $import_dirs, Less_Parser::$options['import_dirs'] );
+
+
+ foreach( $import_dirs as $rootpath => $rooturi){
+ if( is_callable($rooturi) ){
+ list($path, $uri) = call_user_func($rooturi, $evald_path);
+ if( is_string($path) ){
+ $full_path = $path;
+ return array( $full_path, $uri );
+ }
+ }else{
+ $path = rtrim($rootpath,'/\\').'/'.ltrim($evald_path,'/\\');
+
+ if( file_exists($path) ){
+ $full_path = Less_Environment::normalizePath($path);
+ $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path));
+ return array( $full_path, $uri );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Parse the import url and return the rules
+ *
+ * @return Less_Tree_Media|array
+ */
+ function ParseImport( $full_path, $uri, $env ){
+
+ $import_env = clone $env;
+ if( (isset($this->options['reference']) && $this->options['reference']) || isset($this->currentFileInfo['reference']) ){
+ $import_env->currentFileInfo['reference'] = true;
+ }
+
+ if( (isset($this->options['multiple']) && $this->options['multiple']) ){
+ $import_env->importMultiple = true;
+ }
+
+ $parser = new Less_Parser($import_env);
+ $root = $parser->parseFile($full_path, $uri, true);
+
+
+ $ruleset = new Less_Tree_Ruleset(array(), $root->rules );
+ $ruleset->evalImports($import_env);
+
+ return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules;
+ }
+
+
+ /**
+ * Should the import be skipped?
+ *
+ * @return boolean|null
+ */
+ private function Skip($path, $env){
+
+ $path = realpath($path);
+
+ if( $path && Less_Parser::FileParsed($path) ){
+
+ if( isset($this->currentFileInfo['reference']) ){
+ return true;
+ }
+
+ return !isset($this->options['multiple']) && !$env->importMultiple;
+ }
+
+ }
+}
+
+
+
+/**
+ * Javascript
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Javascript extends Less_Tree{
+
+ public $type = 'Javascript';
+ public $escaped;
+ public $expression;
+ public $index;
+
+ /**
+ * @param boolean $index
+ * @param boolean $escaped
+ */
+ public function __construct($string, $index, $escaped){
+ $this->escaped = $escaped;
+ $this->expression = $string;
+ $this->index = $index;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous('/* Sorry, can not do JavaScript evaluation in PHP... :( */');
+ }
+
+}
+
+
+/**
+ * Keyword
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Keyword extends Less_Tree{
+
+ public $value;
+ public $type = 'Keyword';
+
+ /**
+ * @param string $value
+ */
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( $this->value === '%') {
+ throw new Less_Exception_Compiler("Invalid % without number");
+ }
+
+ $output->add( $this->value );
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Keyword) {
+ return $other->value === $this->value ? 0 : 1;
+ } else {
+ return -1;
+ }
+ }
+}
+
+
+/**
+ * Media
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Media extends Less_Tree{
+
+ public $features;
+ public $rules;
+ public $index;
+ public $currentFileInfo;
+ public $isReferenced;
+ public $type = 'Media';
+
+ public function __construct($value = array(), $features = array(), $index = null, $currentFileInfo = null ){
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+
+ $selectors = $this->emptySelectors();
+
+ $this->features = new Less_Tree_Value($features);
+
+ $this->rules = array(new Less_Tree_Ruleset($selectors, $value));
+ $this->rules[0]->allowImports = true;
+ }
+
+ function accept( $visitor ){
+ $this->features = $visitor->visitObj($this->features);
+ $this->rules = $visitor->visitArray($this->rules);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+
+ $output->add( '@media ', $this->currentFileInfo, $this->index );
+ $this->features->genCSS( $output );
+ Less_Tree::outputRuleset( $output, $this->rules);
+
+ }
+
+ public function compile($env) {
+
+ $media = new Less_Tree_Media(array(), array(), $this->index, $this->currentFileInfo );
+
+ $strictMathBypass = false;
+ if( Less_Parser::$options['strictMath'] === false) {
+ $strictMathBypass = true;
+ Less_Parser::$options['strictMath'] = true;
+ }
+
+ $media->features = $this->features->compile($env);
+
+ if( $strictMathBypass ){
+ Less_Parser::$options['strictMath'] = false;
+ }
+
+ $env->mediaPath[] = $media;
+ $env->mediaBlocks[] = $media;
+
+ array_unshift($env->frames, $this->rules[0]);
+ $media->rules = array($this->rules[0]->compile($env));
+ array_shift($env->frames);
+
+ array_pop($env->mediaPath);
+
+ return !$env->mediaPath ? $media->compileTop($env) : $media->compileNested($env);
+ }
+
+ public function variable($name) {
+ return $this->rules[0]->variable($name);
+ }
+
+ public function find($selector) {
+ return $this->rules[0]->find($selector, $this);
+ }
+
+ public function emptySelectors(){
+ $el = new Less_Tree_Element('','&', $this->index, $this->currentFileInfo );
+ $sels = array( new Less_Tree_Selector(array($el), array(), null, $this->index, $this->currentFileInfo) );
+ $sels[0]->mediaEmpty = true;
+ return $sels;
+ }
+
+ public function markReferenced(){
+ $this->rules[0]->markReferenced();
+ $this->isReferenced = true;
+ Less_Tree::ReferencedArray($this->rules[0]->rules);
+ }
+
+ // evaltop
+ public function compileTop($env) {
+ $result = $this;
+
+ if (count($env->mediaBlocks) > 1) {
+ $selectors = $this->emptySelectors();
+ $result = new Less_Tree_Ruleset($selectors, $env->mediaBlocks);
+ $result->multiMedia = true;
+ }
+
+ $env->mediaBlocks = array();
+ $env->mediaPath = array();
+
+ return $result;
+ }
+
+ public function compileNested($env) {
+ $path = array_merge($env->mediaPath, array($this));
+
+ // Extract the media-query conditions separated with `,` (OR).
+ foreach ($path as $key => $p) {
+ $value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features;
+ $path[$key] = is_array($value) ? $value : array($value);
+ }
+
+ // Trace all permutations to generate the resulting media-query.
+ //
+ // (a, b and c) with nested (d, e) ->
+ // a and d
+ // a and e
+ // b and c and d
+ // b and c and e
+
+ $permuted = $this->permute($path);
+ $expressions = array();
+ foreach($permuted as $path){
+
+ for( $i=0, $len=count($path); $i < $len; $i++){
+ $path[$i] = Less_Parser::is_method($path[$i], 'toCSS') ? $path[$i] : new Less_Tree_Anonymous($path[$i]);
+ }
+
+ for( $i = count($path) - 1; $i > 0; $i-- ){
+ array_splice($path, $i, 0, array(new Less_Tree_Anonymous('and')));
+ }
+
+ $expressions[] = new Less_Tree_Expression($path);
+ }
+ $this->features = new Less_Tree_Value($expressions);
+
+
+
+ // Fake a tree-node that doesn't output anything.
+ return new Less_Tree_Ruleset(array(), array());
+ }
+
+ public function permute($arr) {
+ if (!$arr)
+ return array();
+
+ if (count($arr) == 1)
+ return $arr[0];
+
+ $result = array();
+ $rest = $this->permute(array_slice($arr, 1));
+ foreach ($rest as $r) {
+ foreach ($arr[0] as $a) {
+ $result[] = array_merge(
+ is_array($a) ? $a : array($a),
+ is_array($r) ? $r : array($r)
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ function bubbleSelectors($selectors) {
+
+ if( !$selectors) return;
+
+ $this->rules = array(new Less_Tree_Ruleset( $selectors, array($this->rules[0])));
+ }
+
+}
+
+
+/**
+ * A simple css name-value pair
+ * ex: width:100px;
+ *
+ * In bootstrap, there are about 600-1,000 simple name-value pairs (depending on how forgiving the match is) -vs- 6,020 dynamic rules (Less_Tree_Rule)
+ * Using the name-value object can speed up bootstrap compilation slightly, but it breaks color keyword interpretation: color:red -> color:#FF0000;
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_NameValue extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $index;
+ public $currentFileInfo;
+ public $type = 'NameValue';
+
+ public function __construct($name, $value = null, $index = null, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ function genCSS( $output ){
+
+ $output->add(
+ $this->name
+ . Less_Environment::$_outputMap[': ']
+ . $this->value
+ . (((Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";")
+ , $this->currentFileInfo, $this->index);
+ }
+
+ public function compile ($env){
+ return $this;
+ }
+}
+
+
+/**
+ * Negative
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Negative extends Less_Tree{
+
+ public $value;
+ public $type = 'Negative';
+
+ function __construct($node){
+ $this->value = $node;
+ }
+
+ //function accept($visitor) {
+ // $this->value = $visitor->visit($this->value);
+ //}
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $output->add( '-' );
+ $this->value->genCSS( $output );
+ }
+
+ function compile($env) {
+ if( Less_Environment::isMathOn() ){
+ $ret = new Less_Tree_Operation('*', array( new Less_Tree_Dimension(-1), $this->value ) );
+ return $ret->compile($env);
+ }
+ return new Less_Tree_Negative( $this->value->compile($env) );
+ }
+}
+
+/**
+ * Operation
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Operation extends Less_Tree{
+
+ public $op;
+ public $operands;
+ public $isSpaced;
+ public $type = 'Operation';
+
+ /**
+ * @param string $op
+ */
+ public function __construct($op, $operands, $isSpaced = false){
+ $this->op = trim($op);
+ $this->operands = $operands;
+ $this->isSpaced = $isSpaced;
+ }
+
+ function accept($visitor) {
+ $this->operands = $visitor->visitArray($this->operands);
+ }
+
+ public function compile($env){
+ $a = $this->operands[0]->compile($env);
+ $b = $this->operands[1]->compile($env);
+
+
+ if( Less_Environment::isMathOn() ){
+
+ if( $a instanceof Less_Tree_Dimension && $b instanceof Less_Tree_Color ){
+ $a = $a->toColor();
+
+ }elseif( $b instanceof Less_Tree_Dimension && $a instanceof Less_Tree_Color ){
+ $b = $b->toColor();
+
+ }
+
+ if( !method_exists($a,'operate') ){
+ throw new Less_Exception_Compiler("Operation on an invalid type");
+ }
+
+ return $a->operate( $this->op, $b);
+ }
+
+ return new Less_Tree_Operation($this->op, array($a, $b), $this->isSpaced );
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $this->operands[0]->genCSS( $output );
+ if( $this->isSpaced ){
+ $output->add( " " );
+ }
+ $output->add( $this->op );
+ if( $this->isSpaced ){
+ $output->add( ' ' );
+ }
+ $this->operands[1]->genCSS( $output );
+ }
+
+}
+
+
+/**
+ * Paren
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Paren extends Less_Tree{
+
+ public $value;
+ public $type = 'Paren';
+
+ public function __construct($value) {
+ $this->value = $value;
+ }
+
+ function accept($visitor){
+ $this->value = $visitor->visitObj($this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $output->add( '(' );
+ $this->value->genCSS( $output );
+ $output->add( ')' );
+ }
+
+ public function compile($env) {
+ return new Less_Tree_Paren($this->value->compile($env));
+ }
+
+}
+
+
+/**
+ * Quoted
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Quoted extends Less_Tree{
+ public $escaped;
+ public $value;
+ public $quote;
+ public $index;
+ public $currentFileInfo;
+ public $type = 'Quoted';
+
+ /**
+ * @param string $str
+ */
+ public function __construct($str, $content = '', $escaped = false, $index = false, $currentFileInfo = null ){
+ $this->escaped = $escaped;
+ $this->value = $content;
+ if( $str ){
+ $this->quote = $str[0];
+ }
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ if( !$this->escaped ){
+ $output->add( $this->quote, $this->currentFileInfo, $this->index );
+ }
+ $output->add( $this->value );
+ if( !$this->escaped ){
+ $output->add( $this->quote );
+ }
+ }
+
+ public function compile($env){
+
+ $value = $this->value;
+ if( preg_match_all('/`([^`]+)`/', $this->value, $matches) ){
+ foreach($matches as $i => $match){
+ $js = new Less_Tree_JavaScript($matches[1], $this->index, true);
+ $js = $js->compile()->value;
+ $value = str_replace($matches[0][$i], $js, $value);
+ }
+ }
+
+ if( preg_match_all('/@\{([\w-]+)\}/',$value,$matches) ){
+ foreach($matches[1] as $i => $match){
+ $v = new Less_Tree_Variable('@' . $match, $this->index, $this->currentFileInfo );
+ $v = $v->compile($env);
+ $v = ($v instanceof Less_Tree_Quoted) ? $v->value : $v->toCSS();
+ $value = str_replace($matches[0][$i], $v, $value);
+ }
+ }
+
+ return new Less_Tree_Quoted($this->quote . $value . $this->quote, $value, $this->escaped, $this->index, $this->currentFileInfo);
+ }
+
+ function compare($x) {
+
+ if( !Less_Parser::is_method($x, 'toCSS') ){
+ return -1;
+ }
+
+ $left = $this->toCSS();
+ $right = $x->toCSS();
+
+ if ($left === $right) {
+ return 0;
+ }
+
+ return $left < $right ? -1 : 1;
+ }
+}
+
+
+/**
+ * Rule
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Rule extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $important;
+ public $merge;
+ public $index;
+ public $inline;
+ public $variable;
+ public $currentFileInfo;
+ public $type = 'Rule';
+
+ /**
+ * @param string $important
+ */
+ public function __construct($name, $value = null, $important = null, $merge = null, $index = null, $currentFileInfo = null, $inline = false){
+ $this->name = $name;
+ $this->value = ($value instanceof Less_Tree_Value || $value instanceof Less_Tree_Ruleset) ? $value : new Less_Tree_Value(array($value));
+ $this->important = $important ? ' ' . trim($important) : '';
+ $this->merge = $merge;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->inline = $inline;
+ $this->variable = ( is_string($name) && $name[0] === '@');
+ }
+
+ function accept($visitor) {
+ $this->value = $visitor->visitObj( $this->value );
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+
+ $output->add( $this->name . Less_Environment::$_outputMap[': '], $this->currentFileInfo, $this->index);
+ try{
+ $this->value->genCSS( $output);
+
+ }catch( Less_Exception_Parser $e ){
+ $e->index = $this->index;
+ $e->currentFile = $this->currentFileInfo;
+ throw $e;
+ }
+ $output->add( $this->important . (($this->inline || (Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";"), $this->currentFileInfo, $this->index);
+ }
+
+ public function compile ($env){
+
+ $name = $this->name;
+ if( is_array($name) ){
+ // expand 'primitive' name directly to get
+ // things faster (~10% for benchmark.less):
+ if( count($name) === 1 && $name[0] instanceof Less_Tree_Keyword ){
+ $name = $name[0]->value;
+ }else{
+ $name = $this->CompileName($env,$name);
+ }
+ }
+
+ $strictMathBypass = Less_Parser::$options['strictMath'];
+ if( $name === "font" && !Less_Parser::$options['strictMath'] ){
+ Less_Parser::$options['strictMath'] = true;
+ }
+
+ try {
+ $evaldValue = $this->value->compile($env);
+
+ if( !$this->variable && $evaldValue->type === "DetachedRuleset") {
+ throw new Less_Exception_Compiler("Rulesets cannot be evaluated on a property.", null, $this->index, $this->currentFileInfo);
+ }
+
+ if( Less_Environment::$mixin_stack ){
+ $return = new Less_Tree_Rule($name, $evaldValue, $this->important, $this->merge, $this->index, $this->currentFileInfo, $this->inline);
+ }else{
+ $this->name = $name;
+ $this->value = $evaldValue;
+ $return = $this;
+ }
+
+ }catch( Less_Exception_Parser $e ){
+ if( !is_numeric($e->index) ){
+ $e->index = $this->index;
+ $e->currentFile = $this->currentFileInfo;
+ }
+ throw $e;
+ }
+
+ Less_Parser::$options['strictMath'] = $strictMathBypass;
+
+ return $return;
+ }
+
+
+ function CompileName( $env, $name ){
+ $output = new Less_Output();
+ foreach($name as $n){
+ $n->compile($env)->genCSS($output);
+ }
+ return $output->toString();
+ }
+
+ function makeImportant(){
+ return new Less_Tree_Rule($this->name, $this->value, '!important', $this->merge, $this->index, $this->currentFileInfo, $this->inline);
+ }
+
+}
+
+
+/**
+ * Ruleset
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Ruleset extends Less_Tree{
+
+ protected $lookups;
+ public $_variables;
+ public $_rulesets;
+
+ public $strictImports;
+
+ public $selectors;
+ public $rules;
+ public $root;
+ public $allowImports;
+ public $paths;
+ public $firstRoot;
+ public $type = 'Ruleset';
+ public $multiMedia;
+ public $allExtends;
+
+ var $ruleset_id;
+ var $originalRuleset;
+
+ var $first_oelements;
+
+ public function SetRulesetIndex(){
+ $this->ruleset_id = Less_Parser::$next_id++;
+ $this->originalRuleset = $this->ruleset_id;
+
+ if( $this->selectors ){
+ foreach($this->selectors as $sel){
+ if( $sel->_oelements ){
+ $this->first_oelements[$sel->_oelements[0]] = true;
+ }
+ }
+ }
+ }
+
+ public function __construct($selectors, $rules, $strictImports = null){
+ $this->selectors = $selectors;
+ $this->rules = $rules;
+ $this->lookups = array();
+ $this->strictImports = $strictImports;
+ $this->SetRulesetIndex();
+ }
+
+ function accept( $visitor ){
+ if( $this->paths ){
+ $paths_len = count($this->paths);
+ for($i = 0,$paths_len; $i < $paths_len; $i++ ){
+ $this->paths[$i] = $visitor->visitArray($this->paths[$i]);
+ }
+ }elseif( $this->selectors ){
+ $this->selectors = $visitor->visitArray($this->selectors);
+ }
+
+ if( $this->rules ){
+ $this->rules = $visitor->visitArray($this->rules);
+ }
+ }
+
+ public function compile($env){
+
+ $ruleset = $this->PrepareRuleset($env);
+
+
+ // Store the frames around mixin definitions,
+ // so they can be evaluated like closures when the time comes.
+ $rsRuleCnt = count($ruleset->rules);
+ for( $i = 0; $i < $rsRuleCnt; $i++ ){
+ if( $ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset ){
+ $ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
+ }
+ }
+
+ $mediaBlockCount = 0;
+ if( $env instanceof Less_Environment ){
+ $mediaBlockCount = count($env->mediaBlocks);
+ }
+
+ // Evaluate mixin calls.
+ $this->EvalMixinCalls( $ruleset, $env, $rsRuleCnt );
+
+
+ // Evaluate everything else
+ for( $i=0; $i<$rsRuleCnt; $i++ ){
+ if(! ($ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset) ){
+ $ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
+ }
+ }
+
+ // Evaluate everything else
+ for( $i=0; $i<$rsRuleCnt; $i++ ){
+ $rule = $ruleset->rules[$i];
+
+ // for rulesets, check if it is a css guard and can be removed
+ if( $rule instanceof Less_Tree_Ruleset && $rule->selectors && count($rule->selectors) === 1 ){
+
+ // check if it can be folded in (e.g. & where)
+ if( $rule->selectors[0]->isJustParentSelector() ){
+ array_splice($ruleset->rules,$i--,1);
+ $rsRuleCnt--;
+
+ for($j = 0; $j < count($rule->rules); $j++ ){
+ $subRule = $rule->rules[$j];
+ if( !($subRule instanceof Less_Tree_Rule) || !$subRule->variable ){
+ array_splice($ruleset->rules, ++$i, 0, array($subRule));
+ $rsRuleCnt++;
+ }
+ }
+
+ }
+ }
+ }
+
+
+ // Pop the stack
+ $env->shiftFrame();
+
+ if ($mediaBlockCount) {
+ $len = count($env->mediaBlocks);
+ for($i = $mediaBlockCount; $i < $len; $i++ ){
+ $env->mediaBlocks[$i]->bubbleSelectors($ruleset->selectors);
+ }
+ }
+
+ return $ruleset;
+ }
+
+ /**
+ * Compile Less_Tree_Mixin_Call objects
+ *
+ * @param Less_Tree_Ruleset $ruleset
+ * @param integer $rsRuleCnt
+ */
+ private function EvalMixinCalls( $ruleset, $env, &$rsRuleCnt ){
+ for($i=0; $i < $rsRuleCnt; $i++){
+ $rule = $ruleset->rules[$i];
+
+ if( $rule instanceof Less_Tree_Mixin_Call ){
+ $rule = $rule->compile($env);
+
+ $temp = array();
+ foreach($rule as $r){
+ if( ($r instanceof Less_Tree_Rule) && $r->variable ){
+ // do not pollute the scope if the variable is
+ // already there. consider returning false here
+ // but we need a way to "return" variable from mixins
+ if( !$ruleset->variable($r->name) ){
+ $temp[] = $r;
+ }
+ }else{
+ $temp[] = $r;
+ }
+ }
+ $temp_count = count($temp)-1;
+ array_splice($ruleset->rules, $i, 1, $temp);
+ $rsRuleCnt += $temp_count;
+ $i += $temp_count;
+ $ruleset->resetCache();
+
+ }elseif( $rule instanceof Less_Tree_RulesetCall ){
+
+ $rule = $rule->compile($env);
+ $rules = array();
+ foreach($rule->rules as $r){
+ if( ($r instanceof Less_Tree_Rule) && $r->variable ){
+ continue;
+ }
+ $rules[] = $r;
+ }
+
+ array_splice($ruleset->rules, $i, 1, $rules);
+ $temp_count = count($rules);
+ $rsRuleCnt += $temp_count - 1;
+ $i += $temp_count-1;
+ $ruleset->resetCache();
+ }
+
+ }
+ }
+
+
+ /**
+ * Compile the selectors and create a new ruleset object for the compile() method
+ *
+ */
+ private function PrepareRuleset($env){
+
+ $hasOnePassingSelector = false;
+ $selectors = array();
+ if( $this->selectors ){
+ Less_Tree_DefaultFunc::error("it is currently only allowed in parametric mixin guards,");
+
+ foreach($this->selectors as $s){
+ $selector = $s->compile($env);
+ $selectors[] = $selector;
+ if( $selector->evaldCondition ){
+ $hasOnePassingSelector = true;
+ }
+ }
+
+ Less_Tree_DefaultFunc::reset();
+ } else {
+ $hasOnePassingSelector = true;
+ }
+
+ if( $this->rules && $hasOnePassingSelector ){
+ $rules = $this->rules;
+ }else{
+ $rules = array();
+ }
+
+ $ruleset = new Less_Tree_Ruleset($selectors, $rules, $this->strictImports);
+
+ $ruleset->originalRuleset = $this->ruleset_id;
+
+ $ruleset->root = $this->root;
+ $ruleset->firstRoot = $this->firstRoot;
+ $ruleset->allowImports = $this->allowImports;
+
+
+ // push the current ruleset to the frames stack
+ $env->unshiftFrame($ruleset);
+
+
+ // Evaluate imports
+ if( $ruleset->root || $ruleset->allowImports || !$ruleset->strictImports ){
+ $ruleset->evalImports($env);
+ }
+
+ return $ruleset;
+ }
+
+ function evalImports($env) {
+
+ $rules_len = count($this->rules);
+ for($i=0; $i < $rules_len; $i++){
+ $rule = $this->rules[$i];
+
+ if( $rule instanceof Less_Tree_Import ){
+ $rules = $rule->compile($env);
+ if( is_array($rules) ){
+ array_splice($this->rules, $i, 1, $rules);
+ $temp_count = count($rules)-1;
+ $i += $temp_count;
+ $rules_len += $temp_count;
+ }else{
+ array_splice($this->rules, $i, 1, array($rules));
+ }
+
+ $this->resetCache();
+ }
+ }
+ }
+
+ function makeImportant(){
+
+ $important_rules = array();
+ foreach($this->rules as $rule){
+ if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_Ruleset ){
+ $important_rules[] = $rule->makeImportant();
+ }else{
+ $important_rules[] = $rule;
+ }
+ }
+
+ return new Less_Tree_Ruleset($this->selectors, $important_rules, $this->strictImports );
+ }
+
+ public function matchArgs($args){
+ return !$args;
+ }
+
+ // lets you call a css selector with a guard
+ public function matchCondition( $args, $env ){
+ $lastSelector = end($this->selectors);
+
+ if( !$lastSelector->evaldCondition ){
+ return false;
+ }
+ if( $lastSelector->condition && !$lastSelector->condition->compile( $env->copyEvalEnv( $env->frames ) ) ){
+ return false;
+ }
+ return true;
+ }
+
+ function resetCache(){
+ $this->_rulesets = null;
+ $this->_variables = null;
+ $this->lookups = array();
+ }
+
+ public function variables(){
+ $this->_variables = array();
+ foreach( $this->rules as $r){
+ if ($r instanceof Less_Tree_Rule && $r->variable === true) {
+ $this->_variables[$r->name] = $r;
+ }
+ }
+ }
+
+ public function variable($name){
+
+ if( is_null($this->_variables) ){
+ $this->variables();
+ }
+ return isset($this->_variables[$name]) ? $this->_variables[$name] : null;
+ }
+
+ public function find( $selector, $self = null ){
+
+ $key = implode(' ',$selector->_oelements);
+
+ if( !isset($this->lookups[$key]) ){
+
+ if( !$self ){
+ $self = $this->ruleset_id;
+ }
+
+ $this->lookups[$key] = array();
+
+ $first_oelement = $selector->_oelements[0];
+
+ foreach($this->rules as $rule){
+ if( $rule instanceof Less_Tree_Ruleset && $rule->ruleset_id != $self ){
+
+ if( isset($rule->first_oelements[$first_oelement]) ){
+
+ foreach( $rule->selectors as $ruleSelector ){
+ $match = $selector->match($ruleSelector);
+ if( $match ){
+ if( $selector->elements_len > $match ){
+ $this->lookups[$key] = array_merge($this->lookups[$key], $rule->find( new Less_Tree_Selector(array_slice($selector->elements, $match)), $self));
+ } else {
+ $this->lookups[$key][] = $rule;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $this->lookups[$key];
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( !$this->root ){
+ Less_Environment::$tabLevel++;
+ }
+
+ $tabRuleStr = $tabSetStr = '';
+ if( !Less_Parser::$options['compress'] ){
+ if( Less_Environment::$tabLevel ){
+ $tabRuleStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel );
+ $tabSetStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel-1 );
+ }else{
+ $tabSetStr = $tabRuleStr = "\n";
+ }
+ }
+
+
+ $ruleNodes = array();
+ $rulesetNodes = array();
+ foreach($this->rules as $rule){
+
+ $class = get_class($rule);
+ if( ($class === 'Less_Tree_Media') || ($class === 'Less_Tree_Directive') || ($this->root && $class === 'Less_Tree_Comment') || ($class === 'Less_Tree_Ruleset' && $rule->rules) ){
+ $rulesetNodes[] = $rule;
+ }else{
+ $ruleNodes[] = $rule;
+ }
+ }
+
+ // If this is the root node, we don't render
+ // a selector, or {}.
+ if( !$this->root ){
+
+ /*
+ debugInfo = tree.debugInfo(env, this, tabSetStr);
+
+ if (debugInfo) {
+ output.add(debugInfo);
+ output.add(tabSetStr);
+ }
+ */
+
+ $paths_len = count($this->paths);
+ for( $i = 0; $i < $paths_len; $i++ ){
+ $path = $this->paths[$i];
+ $firstSelector = true;
+
+ foreach($path as $p){
+ $p->genCSS( $output, $firstSelector );
+ $firstSelector = false;
+ }
+
+ if( $i + 1 < $paths_len ){
+ $output->add( ',' . $tabSetStr );
+ }
+ }
+
+ $output->add( (Less_Parser::$options['compress'] ? '{' : " {") . $tabRuleStr );
+ }
+
+ // Compile rules and rulesets
+ $ruleNodes_len = count($ruleNodes);
+ $rulesetNodes_len = count($rulesetNodes);
+ for( $i = 0; $i < $ruleNodes_len; $i++ ){
+ $rule = $ruleNodes[$i];
+
+ // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
+ // In this instance we do not know whether it is the last property
+ if( $i + 1 === $ruleNodes_len && (!$this->root || $rulesetNodes_len === 0 || $this->firstRoot ) ){
+ Less_Environment::$lastRule = true;
+ }
+
+ $rule->genCSS( $output );
+
+ if( !Less_Environment::$lastRule ){
+ $output->add( $tabRuleStr );
+ }else{
+ Less_Environment::$lastRule = false;
+ }
+ }
+
+ if( !$this->root ){
+ $output->add( $tabSetStr . '}' );
+ Less_Environment::$tabLevel--;
+ }
+
+ $firstRuleset = true;
+ $space = ($this->root ? $tabRuleStr : $tabSetStr);
+ for( $i = 0; $i < $rulesetNodes_len; $i++ ){
+
+ if( $ruleNodes_len && $firstRuleset ){
+ $output->add( $space );
+ }elseif( !$firstRuleset ){
+ $output->add( $space );
+ }
+ $firstRuleset = false;
+ $rulesetNodes[$i]->genCSS( $output);
+ }
+
+ if( !Less_Parser::$options['compress'] && $this->firstRoot ){
+ $output->add( "\n" );
+ }
+
+ }
+
+
+ function markReferenced(){
+ if( !$this->selectors ){
+ return;
+ }
+ foreach($this->selectors as $selector){
+ $selector->markReferenced();
+ }
+ }
+
+ public function joinSelectors( $context, $selectors ){
+ $paths = array();
+ if( is_array($selectors) ){
+ foreach($selectors as $selector) {
+ $this->joinSelector( $paths, $context, $selector);
+ }
+ }
+ return $paths;
+ }
+
+ public function joinSelector( &$paths, $context, $selector){
+
+ $hasParentSelector = false;
+
+ foreach($selector->elements as $el) {
+ if( $el->value === '&') {
+ $hasParentSelector = true;
+ }
+ }
+
+ if( !$hasParentSelector ){
+ if( $context ){
+ foreach($context as $context_el){
+ $paths[] = array_merge($context_el, array($selector) );
+ }
+ }else {
+ $paths[] = array($selector);
+ }
+ return;
+ }
+
+
+ // The paths are [[Selector]]
+ // The first list is a list of comma seperated selectors
+ // The inner list is a list of inheritance seperated selectors
+ // e.g.
+ // .a, .b {
+ // .c {
+ // }
+ // }
+ // == [[.a] [.c]] [[.b] [.c]]
+ //
+
+ // the elements from the current selector so far
+ $currentElements = array();
+ // the current list of new selectors to add to the path.
+ // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
+ // by the parents
+ $newSelectors = array(array());
+
+
+ foreach( $selector->elements as $el){
+
+ // non parent reference elements just get added
+ if( $el->value !== '&' ){
+ $currentElements[] = $el;
+ } else {
+ // the new list of selectors to add
+ $selectorsMultiplied = array();
+
+ // merge the current list of non parent selector elements
+ // on to the current list of selectors to add
+ if( $currentElements ){
+ $this->mergeElementsOnToSelectors( $currentElements, $newSelectors);
+ }
+
+ // loop through our current selectors
+ foreach($newSelectors as $sel){
+
+ // if we don't have any parent paths, the & might be in a mixin so that it can be used
+ // whether there are parents or not
+ if( !$context ){
+ // the combinator used on el should now be applied to the next element instead so that
+ // it is not lost
+ if( $sel ){
+ $sel[0]->elements = array_slice($sel[0]->elements,0);
+ $sel[0]->elements[] = new Less_Tree_Element($el->combinator, '', $el->index, $el->currentFileInfo );
+ }
+ $selectorsMultiplied[] = $sel;
+ }else {
+
+ // and the parent selectors
+ foreach($context as $parentSel){
+ // We need to put the current selectors
+ // then join the last selector's elements on to the parents selectors
+
+ // our new selector path
+ $newSelectorPath = array();
+ // selectors from the parent after the join
+ $afterParentJoin = array();
+ $newJoinedSelectorEmpty = true;
+
+ //construct the joined selector - if & is the first thing this will be empty,
+ // if not newJoinedSelector will be the last set of elements in the selector
+ if( $sel ){
+ $newSelectorPath = $sel;
+ $lastSelector = array_pop($newSelectorPath);
+ $newJoinedSelector = $selector->createDerived( array_slice($lastSelector->elements,0) );
+ $newJoinedSelectorEmpty = false;
+ }
+ else {
+ $newJoinedSelector = $selector->createDerived(array());
+ }
+
+ //put together the parent selectors after the join
+ if ( count($parentSel) > 1) {
+ $afterParentJoin = array_merge($afterParentJoin, array_slice($parentSel,1) );
+ }
+
+ if ( $parentSel ){
+ $newJoinedSelectorEmpty = false;
+
+ // join the elements so far with the first part of the parent
+ $newJoinedSelector->elements[] = new Less_Tree_Element( $el->combinator, $parentSel[0]->elements[0]->value, $el->index, $el->currentFileInfo);
+
+ $newJoinedSelector->elements = array_merge( $newJoinedSelector->elements, array_slice($parentSel[0]->elements, 1) );
+ }
+
+ if (!$newJoinedSelectorEmpty) {
+ // now add the joined selector
+ $newSelectorPath[] = $newJoinedSelector;
+ }
+
+ // and the rest of the parent
+ $newSelectorPath = array_merge($newSelectorPath, $afterParentJoin);
+
+ // add that to our new set of selectors
+ $selectorsMultiplied[] = $newSelectorPath;
+ }
+ }
+ }
+
+ // our new selectors has been multiplied, so reset the state
+ $newSelectors = $selectorsMultiplied;
+ $currentElements = array();
+ }
+ }
+
+ // if we have any elements left over (e.g. .a& .b == .b)
+ // add them on to all the current selectors
+ if( $currentElements ){
+ $this->mergeElementsOnToSelectors($currentElements, $newSelectors);
+ }
+ foreach( $newSelectors as $new_sel){
+ if( $new_sel ){
+ $paths[] = $new_sel;
+ }
+ }
+ }
+
+ function mergeElementsOnToSelectors( $elements, &$selectors){
+
+ if( !$selectors ){
+ $selectors[] = array( new Less_Tree_Selector($elements) );
+ return;
+ }
+
+
+ foreach( $selectors as &$sel){
+
+ // if the previous thing in sel is a parent this needs to join on to it
+ if( $sel ){
+ $last = count($sel)-1;
+ $sel[$last] = $sel[$last]->createDerived( array_merge($sel[$last]->elements, $elements) );
+ }else{
+ $sel[] = new Less_Tree_Selector( $elements );
+ }
+ }
+ }
+}
+
+
+/**
+ * RulesetCall
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_RulesetCall extends Less_Tree{
+
+ public $variable;
+ public $type = "RulesetCall";
+
+ function __construct($variable){
+ $this->variable = $variable;
+ }
+
+ function accept($visitor) {}
+
+ function compile( $env ){
+ $variable = new Less_Tree_Variable($this->variable);
+ $detachedRuleset = $variable->compile($env);
+ return $detachedRuleset->callEval($env);
+ }
+}
+
+
+
+/**
+ * Selector
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Selector extends Less_Tree{
+
+ public $elements;
+ public $condition;
+ public $extendList = array();
+ public $_css;
+ public $index;
+ public $evaldCondition = false;
+ public $type = 'Selector';
+ public $currentFileInfo = array();
+ public $isReferenced;
+ public $mediaEmpty;
+
+ public $elements_len = 0;
+
+ public $_oelements;
+ public $_oelements_len;
+ public $cacheable = true;
+
+ /**
+ * @param boolean $isReferenced
+ */
+ public function __construct( $elements, $extendList = array() , $condition = null, $index=null, $currentFileInfo=null, $isReferenced=null ){
+
+ $this->elements = $elements;
+ $this->elements_len = count($elements);
+ $this->extendList = $extendList;
+ $this->condition = $condition;
+ if( $currentFileInfo ){
+ $this->currentFileInfo = $currentFileInfo;
+ }
+ $this->isReferenced = $isReferenced;
+ if( !$condition ){
+ $this->evaldCondition = true;
+ }
+
+ $this->CacheElements();
+ }
+
+ function accept($visitor) {
+ $this->elements = $visitor->visitArray($this->elements);
+ $this->extendList = $visitor->visitArray($this->extendList);
+ if( $this->condition ){
+ $this->condition = $visitor->visitObj($this->condition);
+ }
+
+ if( $visitor instanceof Less_Visitor_extendFinder ){
+ $this->CacheElements();
+ }
+ }
+
+ function createDerived( $elements, $extendList = null, $evaldCondition = null ){
+ $newSelector = new Less_Tree_Selector( $elements, ($extendList ? $extendList : $this->extendList), null, $this->index, $this->currentFileInfo, $this->isReferenced);
+ $newSelector->evaldCondition = $evaldCondition ? $evaldCondition : $this->evaldCondition;
+ return $newSelector;
+ }
+
+
+ public function match( $other ){
+
+ if( !$other->_oelements || ($this->elements_len < $other->_oelements_len) ){
+ return 0;
+ }
+
+ for( $i = 0; $i < $other->_oelements_len; $i++ ){
+ if( $this->elements[$i]->value !== $other->_oelements[$i]) {
+ return 0;
+ }
+ }
+
+ return $other->_oelements_len; // return number of matched elements
+ }
+
+
+ public function CacheElements(){
+
+ $this->_oelements = array();
+ $css = '';
+
+ foreach($this->elements as $v){
+
+ $css .= $v->combinator;
+ if( !$v->value_is_object ){
+ $css .= $v->value;
+ continue;
+ }
+
+ if( !property_exists($v->value,'value') || !is_string($v->value->value) ){
+ $this->cacheable = false;
+ return;
+ }
+ $css .= $v->value->value;
+ }
+
+ $this->_oelements_len = preg_match_all('/[,\.\w-](?:[\w-]|(?:\\\\.))*/', $css, $matches);
+ if( $this->_oelements_len ){
+ $this->_oelements = $matches[0];
+
+ if( $this->_oelements[0] === '&' ){
+ array_shift($this->_oelements);
+ $this->_oelements_len--;
+ }
+ }
+ }
+
+ public function isJustParentSelector(){
+ return !$this->mediaEmpty &&
+ count($this->elements) === 1 &&
+ $this->elements[0]->value === '&' &&
+ ($this->elements[0]->combinator === ' ' || $this->elements[0]->combinator === '');
+ }
+
+ public function compile($env) {
+
+ $elements = array();
+ foreach($this->elements as $el){
+ $elements[] = $el->compile($env);
+ }
+
+ $extendList = array();
+ foreach($this->extendList as $el){
+ $extendList[] = $el->compile($el);
+ }
+
+ $evaldCondition = false;
+ if( $this->condition ){
+ $evaldCondition = $this->condition->compile($env);
+ }
+
+ return $this->createDerived( $elements, $extendList, $evaldCondition );
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output, $firstSelector = true ){
+
+ if( !$firstSelector && $this->elements[0]->combinator === "" ){
+ $output->add(' ', $this->currentFileInfo, $this->index);
+ }
+
+ foreach($this->elements as $element){
+ $element->genCSS( $output );
+ }
+ }
+
+ function markReferenced(){
+ $this->isReferenced = true;
+ }
+
+ function getIsReferenced(){
+ return !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] || $this->isReferenced;
+ }
+
+ function getIsOutput(){
+ return $this->evaldCondition;
+ }
+
+}
+
+
+/**
+ * UnicodeDescriptor
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_UnicodeDescriptor extends Less_Tree{
+
+ public $value;
+ public $type = 'UnicodeDescriptor';
+
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->value );
+ }
+
+ public function compile(){
+ return $this;
+ }
+}
+
+
+
+/**
+ * Unit
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Unit extends Less_Tree{
+
+ var $numerator = array();
+ var $denominator = array();
+ public $backupUnit;
+ public $type = 'Unit';
+
+ function __construct($numerator = array(), $denominator = array(), $backupUnit = null ){
+ $this->numerator = $numerator;
+ $this->denominator = $denominator;
+ $this->backupUnit = $backupUnit;
+ }
+
+ function __clone(){
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+
+ if( $this->numerator ){
+ $output->add( $this->numerator[0] );
+ }elseif( $this->denominator ){
+ $output->add( $this->denominator[0] );
+ }elseif( !Less_Parser::$options['strictUnits'] && $this->backupUnit ){
+ $output->add( $this->backupUnit );
+ return ;
+ }
+ }
+
+ function toString(){
+ $returnStr = implode('*',$this->numerator);
+ foreach($this->denominator as $d){
+ $returnStr .= '/'.$d;
+ }
+ return $returnStr;
+ }
+
+ function __toString(){
+ return $this->toString();
+ }
+
+
+ /**
+ * @param Less_Tree_Unit $other
+ */
+ function compare($other) {
+ return $this->is( $other->toString() ) ? 0 : -1;
+ }
+
+ function is($unitString){
+ return $this->toString() === $unitString;
+ }
+
+ function isLength(){
+ $css = $this->toCSS();
+ return !!preg_match('/px|em|%|in|cm|mm|pc|pt|ex/',$css);
+ }
+
+ function isAngle() {
+ return isset( Less_Tree_UnitConversions::$angle[$this->toCSS()] );
+ }
+
+ function isEmpty(){
+ return !$this->numerator && !$this->denominator;
+ }
+
+ function isSingular() {
+ return count($this->numerator) <= 1 && !$this->denominator;
+ }
+
+
+ function usedUnits(){
+ $result = array();
+
+ foreach(Less_Tree_UnitConversions::$groups as $groupName){
+ $group = Less_Tree_UnitConversions::${$groupName};
+
+ foreach($this->numerator as $atomicUnit){
+ if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
+ $result[$groupName] = $atomicUnit;
+ }
+ }
+
+ foreach($this->denominator as $atomicUnit){
+ if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
+ $result[$groupName] = $atomicUnit;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ function cancel(){
+ $counter = array();
+ $backup = null;
+
+ foreach($this->numerator as $atomicUnit){
+ if( !$backup ){
+ $backup = $atomicUnit;
+ }
+ $counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) + 1;
+ }
+
+ foreach($this->denominator as $atomicUnit){
+ if( !$backup ){
+ $backup = $atomicUnit;
+ }
+ $counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) - 1;
+ }
+
+ $this->numerator = array();
+ $this->denominator = array();
+
+ foreach($counter as $atomicUnit => $count){
+ if( $count > 0 ){
+ for( $i = 0; $i < $count; $i++ ){
+ $this->numerator[] = $atomicUnit;
+ }
+ }elseif( $count < 0 ){
+ for( $i = 0; $i < -$count; $i++ ){
+ $this->denominator[] = $atomicUnit;
+ }
+ }
+ }
+
+ if( !$this->numerator && !$this->denominator && $backup ){
+ $this->backupUnit = $backup;
+ }
+
+ sort($this->numerator);
+ sort($this->denominator);
+ }
+
+
+}
+
+
+
+/**
+ * UnitConversions
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_UnitConversions{
+
+ public static $groups = array('length','duration','angle');
+
+ public static $length = array(
+ 'm'=> 1,
+ 'cm'=> 0.01,
+ 'mm'=> 0.001,
+ 'in'=> 0.0254,
+ 'px'=> 0.000264583, // 0.0254 / 96,
+ 'pt'=> 0.000352778, // 0.0254 / 72,
+ 'pc'=> 0.004233333, // 0.0254 / 72 * 12
+ );
+
+ public static $duration = array(
+ 's'=> 1,
+ 'ms'=> 0.001
+ );
+
+ public static $angle = array(
+ 'rad' => 0.1591549430919, // 1/(2*M_PI),
+ 'deg' => 0.002777778, // 1/360,
+ 'grad'=> 0.0025, // 1/400,
+ 'turn'=> 1
+ );
+
+}
+
+/**
+ * Url
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Url extends Less_Tree{
+
+ public $attrs;
+ public $value;
+ public $currentFileInfo;
+ public $isEvald;
+ public $type = 'Url';
+
+ public function __construct($value, $currentFileInfo = null, $isEvald = null){
+ $this->value = $value;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->isEvald = $isEvald;
+ }
+
+ function accept( $visitor ){
+ $this->value = $visitor->visitObj($this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $output->add( 'url(' );
+ $this->value->genCSS( $output );
+ $output->add( ')' );
+ }
+
+ /**
+ * @param Less_Functions $ctx
+ */
+ public function compile($ctx){
+ $val = $this->value->compile($ctx);
+
+ if( !$this->isEvald ){
+ // Add the base path if the URL is relative
+ if( Less_Parser::$options['relativeUrls']
+ && $this->currentFileInfo
+ && is_string($val->value)
+ && Less_Environment::isPathRelative($val->value)
+ ){
+ $rootpath = $this->currentFileInfo['uri_root'];
+ if ( !$val->quote ){
+ $rootpath = preg_replace('/[\(\)\'"\s]/', '\\$1', $rootpath );
+ }
+ $val->value = $rootpath . $val->value;
+ }
+
+ $val->value = Less_Environment::normalizePath( $val->value);
+ }
+
+ // Add cache buster if enabled
+ if( Less_Parser::$options['urlArgs'] ){
+ if( !preg_match('/^\s*data:/',$val->value) ){
+ $delimiter = strpos($val->value,'?') === false ? '?' : '&';
+ $urlArgs = $delimiter . Less_Parser::$options['urlArgs'];
+ $hash_pos = strpos($val->value,'#');
+ if( $hash_pos !== false ){
+ $val->value = substr_replace($val->value,$urlArgs, $hash_pos, 0);
+ } else {
+ $val->value .= $urlArgs;
+ }
+ }
+ }
+
+ return new Less_Tree_URL($val, $this->currentFileInfo, true);
+ }
+
+}
+
+
+/**
+ * Value
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Value extends Less_Tree{
+
+ public $type = 'Value';
+ public $value;
+
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ function accept($visitor) {
+ $this->value = $visitor->visitArray($this->value);
+ }
+
+ public function compile($env){
+
+ $ret = array();
+ $i = 0;
+ foreach($this->value as $i => $v){
+ $ret[] = $v->compile($env);
+ }
+ if( $i > 0 ){
+ return new Less_Tree_Value($ret);
+ }
+ return $ret[0];
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $len = count($this->value);
+ for($i = 0; $i < $len; $i++ ){
+ $this->value[$i]->genCSS( $output );
+ if( $i+1 < $len ){
+ $output->add( Less_Environment::$_outputMap[','] );
+ }
+ }
+ }
+
+}
+
+
+/**
+ * Variable
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Variable extends Less_Tree{
+
+ public $name;
+ public $index;
+ public $currentFileInfo;
+ public $evaluating = false;
+ public $type = 'Variable';
+
+ /**
+ * @param string $name
+ */
+ public function __construct($name, $index = null, $currentFileInfo = null) {
+ $this->name = $name;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function compile($env) {
+
+ if( $this->name[1] === '@' ){
+ $v = new Less_Tree_Variable(substr($this->name, 1), $this->index + 1);
+ $name = '@' . $v->compile($env)->value;
+ }else{
+ $name = $this->name;
+ }
+
+ if ($this->evaluating) {
+ throw new Less_Exception_Compiler("Recursive variable definition for " . $name, null, $this->index, $this->currentFileInfo);
+ }
+
+ $this->evaluating = true;
+
+ foreach($env->frames as $frame){
+ if( $v = $frame->variable($name) ){
+ $this->evaluating = false;
+ return $v->value->compile($env);
+ }
+ }
+
+ throw new Less_Exception_Compiler("variable " . $name . " is undefined", null, $this->index );
+ }
+
+}
+
+
+
+class Less_Tree_Mixin_Call extends Less_Tree{
+
+ public $selector;
+ public $arguments;
+ public $index;
+ public $currentFileInfo;
+
+ public $important;
+ public $type = 'MixinCall';
+
+ /**
+ * less.js: tree.mixin.Call
+ *
+ */
+ public function __construct($elements, $args, $index, $currentFileInfo, $important = false){
+ $this->selector = new Less_Tree_Selector($elements);
+ $this->arguments = $args;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->important = $important;
+ }
+
+ //function accept($visitor){
+ // $this->selector = $visitor->visit($this->selector);
+ // $this->arguments = $visitor->visit($this->arguments);
+ //}
+
+
+ public function compile($env){
+
+ $rules = array();
+ $match = false;
+ $isOneFound = false;
+ $candidates = array();
+ $defaultUsed = false;
+ $conditionResult = array();
+
+ $args = array();
+ foreach($this->arguments as $a){
+ $args[] = array('name'=> $a['name'], 'value' => $a['value']->compile($env) );
+ }
+
+ foreach($env->frames as $frame){
+
+ $mixins = $frame->find($this->selector);
+
+ if( !$mixins ){
+ continue;
+ }
+
+ $isOneFound = true;
+ $defNone = 0;
+ $defTrue = 1;
+ $defFalse = 2;
+
+ // To make `default()` function independent of definition order we have two "subpasses" here.
+ // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
+ // and build candidate list with corresponding flags. Then, when we know all possible matches,
+ // we make a final decision.
+
+ $mixins_len = count($mixins);
+ for( $m = 0; $m < $mixins_len; $m++ ){
+ $mixin = $mixins[$m];
+
+ if( $this->IsRecursive( $env, $mixin ) ){
+ continue;
+ }
+
+ if( $mixin->matchArgs($args, $env) ){
+
+ $candidate = array('mixin' => $mixin, 'group' => $defNone);
+
+ if( $mixin instanceof Less_Tree_Ruleset ){
+
+ for( $f = 0; $f < 2; $f++ ){
+ Less_Tree_DefaultFunc::value($f);
+ $conditionResult[$f] = $mixin->matchCondition( $args, $env);
+ }
+ if( $conditionResult[0] || $conditionResult[1] ){
+ if( $conditionResult[0] != $conditionResult[1] ){
+ $candidate['group'] = $conditionResult[1] ? $defTrue : $defFalse;
+ }
+
+ $candidates[] = $candidate;
+ }
+ }else{
+ $candidates[] = $candidate;
+ }
+
+ $match = true;
+ }
+ }
+
+ Less_Tree_DefaultFunc::reset();
+
+
+ $count = array(0, 0, 0);
+ for( $m = 0; $m < count($candidates); $m++ ){
+ $count[ $candidates[$m]['group'] ]++;
+ }
+
+ if( $count[$defNone] > 0 ){
+ $defaultResult = $defFalse;
+ } else {
+ $defaultResult = $defTrue;
+ if( ($count[$defTrue] + $count[$defFalse]) > 1 ){
+ throw Exception( 'Ambiguous use of `default()` found when matching for `'. $this->format($args) + '`' );
+ }
+ }
+
+
+ $candidates_length = count($candidates);
+ $length_1 = ($candidates_length == 1);
+
+ for( $m = 0; $m < $candidates_length; $m++){
+ $candidate = $candidates[$m]['group'];
+ if( ($candidate === $defNone) || ($candidate === $defaultResult) ){
+ try{
+ $mixin = $candidates[$m]['mixin'];
+ if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
+ $mixin = new Less_Tree_Mixin_Definition('', array(), $mixin->rules, null, false);
+ $mixin->originalRuleset = $mixins[$m]->originalRuleset;
+ }
+ $rules = array_merge($rules, $mixin->evalCall($env, $args, $this->important)->rules);
+ } catch (Exception $e) {
+ //throw new Less_Exception_Compiler($e->getMessage(), $e->index, null, $this->currentFileInfo['filename']);
+ throw new Less_Exception_Compiler($e->getMessage(), null, null, $this->currentFileInfo);
+ }
+ }
+ }
+
+ if( $match ){
+ if( !$this->currentFileInfo || !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] ){
+ Less_Tree::ReferencedArray($rules);
+ }
+
+ return $rules;
+ }
+ }
+
+ if( $isOneFound ){
+ throw new Less_Exception_Compiler('No matching definition was found for `'.$this->Format( $args ).'`', null, $this->index, $this->currentFileInfo);
+
+ }else{
+ throw new Less_Exception_Compiler(trim($this->selector->toCSS()) . " is undefined", null, $this->index);
+ }
+
+ }
+
+ /**
+ * Format the args for use in exception messages
+ *
+ */
+ private function Format($args){
+ $message = array();
+ if( $args ){
+ foreach($args as $a){
+ $argValue = '';
+ if( $a['name'] ){
+ $argValue += $a['name']+':';
+ }
+ if( is_object($a['value']) ){
+ $argValue += $a['value']->toCSS();
+ }else{
+ $argValue += '???';
+ }
+ $message[] = $argValue;
+ }
+ }
+ return implode(', ',$message);
+ }
+
+
+ /**
+ * Are we in a recursive mixin call?
+ *
+ * @return bool
+ */
+ private function IsRecursive( $env, $mixin ){
+
+ foreach($env->frames as $recur_frame){
+ if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
+
+ if( $mixin === $recur_frame ){
+ return true;
+ }
+
+ if( isset($recur_frame->originalRuleset) && $mixin->ruleset_id === $recur_frame->originalRuleset ){
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
+
+
+
+
+class Less_Tree_Mixin_Definition extends Less_Tree_Ruleset{
+ public $name;
+ public $selectors;
+ public $params;
+ public $arity = 0;
+ public $rules;
+ public $lookups = array();
+ public $required = 0;
+ public $frames = array();
+ public $condition;
+ public $variadic;
+ public $type = 'MixinDefinition';
+
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition
+ public function __construct($name, $params, $rules, $condition, $variadic = false, $frames = null ){
+ $this->name = $name;
+ $this->selectors = array(new Less_Tree_Selector(array( new Less_Tree_Element(null, $name))));
+
+ $this->params = $params;
+ $this->condition = $condition;
+ $this->variadic = $variadic;
+ $this->rules = $rules;
+
+ if( $params ){
+ $this->arity = count($params);
+ foreach( $params as $p ){
+ if (! isset($p['name']) || ($p['name'] && !isset($p['value']))) {
+ $this->required++;
+ }
+ }
+ }
+
+ $this->frames = $frames;
+ $this->SetRulesetIndex();
+ }
+
+
+
+ //function accept( $visitor ){
+ // $this->params = $visitor->visit($this->params);
+ // $this->rules = $visitor->visit($this->rules);
+ // $this->condition = $visitor->visit($this->condition);
+ //}
+
+
+ public function toCSS(){
+ return '';
+ }
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition.evalParams
+ public function compileParams($env, $mixinFrames, $args = array() , &$evaldArguments = array() ){
+ $frame = new Less_Tree_Ruleset(null, array());
+ $params = $this->params;
+ $mixinEnv = null;
+ $argsLength = 0;
+
+ if( $args ){
+ $argsLength = count($args);
+ for($i = 0; $i < $argsLength; $i++ ){
+ $arg = $args[$i];
+
+ if( $arg && $arg['name'] ){
+ $isNamedFound = false;
+
+ foreach($params as $j => $param){
+ if( !isset($evaldArguments[$j]) && $arg['name'] === $params[$j]['name']) {
+ $evaldArguments[$j] = $arg['value']->compile($env);
+ array_unshift($frame->rules, new Less_Tree_Rule( $arg['name'], $arg['value']->compile($env) ) );
+ $isNamedFound = true;
+ break;
+ }
+ }
+ if ($isNamedFound) {
+ array_splice($args, $i, 1);
+ $i--;
+ $argsLength--;
+ continue;
+ } else {
+ throw new Less_Exception_Compiler("Named argument for " . $this->name .' '.$args[$i]['name'] . ' not found');
+ }
+ }
+ }
+ }
+
+ $argIndex = 0;
+ foreach($params as $i => $param){
+
+ if ( isset($evaldArguments[$i]) ){ continue; }
+
+ $arg = null;
+ if( isset($args[$argIndex]) ){
+ $arg = $args[$argIndex];
+ }
+
+ if (isset($param['name']) && $param['name']) {
+
+ if( isset($param['variadic']) ){
+ $varargs = array();
+ for ($j = $argIndex; $j < $argsLength; $j++) {
+ $varargs[] = $args[$j]['value']->compile($env);
+ }
+ $expression = new Less_Tree_Expression($varargs);
+ array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $expression->compile($env)));
+ }else{
+ $val = ($arg && $arg['value']) ? $arg['value'] : false;
+
+ if ($val) {
+ $val = $val->compile($env);
+ } else if ( isset($param['value']) ) {
+
+ if( !$mixinEnv ){
+ $mixinEnv = new Less_Environment();
+ $mixinEnv->frames = array_merge( array($frame), $mixinFrames);
+ }
+
+ $val = $param['value']->compile($mixinEnv);
+ $frame->resetCache();
+ } else {
+ throw new Less_Exception_Compiler("Wrong number of arguments for " . $this->name . " (" . $argsLength . ' for ' . $this->arity . ")");
+ }
+
+ array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $val));
+ $evaldArguments[$i] = $val;
+ }
+ }
+
+ if ( isset($param['variadic']) && $args) {
+ for ($j = $argIndex; $j < $argsLength; $j++) {
+ $evaldArguments[$j] = $args[$j]['value']->compile($env);
+ }
+ }
+ $argIndex++;
+ }
+
+ ksort($evaldArguments);
+ $evaldArguments = array_values($evaldArguments);
+
+ return $frame;
+ }
+
+ public function compile($env) {
+ if( $this->frames ){
+ return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $this->frames );
+ }
+ return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $env->frames );
+ }
+
+ public function evalCall($env, $args = NULL, $important = NULL) {
+
+ Less_Environment::$mixin_stack++;
+
+ $_arguments = array();
+
+ if( $this->frames ){
+ $mixinFrames = array_merge($this->frames, $env->frames);
+ }else{
+ $mixinFrames = $env->frames;
+ }
+
+ $frame = $this->compileParams($env, $mixinFrames, $args, $_arguments);
+
+ $ex = new Less_Tree_Expression($_arguments);
+ array_unshift($frame->rules, new Less_Tree_Rule('@arguments', $ex->compile($env)));
+
+
+ $ruleset = new Less_Tree_Ruleset(null, $this->rules);
+ $ruleset->originalRuleset = $this->ruleset_id;
+
+
+ $ruleSetEnv = new Less_Environment();
+ $ruleSetEnv->frames = array_merge( array($this, $frame), $mixinFrames );
+ $ruleset = $ruleset->compile( $ruleSetEnv );
+
+ if( $important ){
+ $ruleset = $ruleset->makeImportant();
+ }
+
+ Less_Environment::$mixin_stack--;
+
+ return $ruleset;
+ }
+
+
+ public function matchCondition($args, $env) {
+
+ if( !$this->condition ){
+ return true;
+ }
+
+ $frame = $this->compileParams($env, array_merge($this->frames,$env->frames), $args );
+
+ $compile_env = new Less_Environment();
+ $compile_env->frames = array_merge(
+ array($frame) // the parameter variables
+ , $this->frames // the parent namespace/mixin frames
+ , $env->frames // the current environment frames
+ );
+
+ return (bool)$this->condition->compile($compile_env);
+ }
+
+ public function matchArgs($args, $env = NULL){
+ $argsLength = count($args);
+
+ if( !$this->variadic ){
+ if( $argsLength < $this->required ){
+ return false;
+ }
+ if( $argsLength > count($this->params) ){
+ return false;
+ }
+ }else{
+ if( $argsLength < ($this->required - 1)){
+ return false;
+ }
+ }
+
+ $len = min($argsLength, $this->arity);
+
+ for( $i = 0; $i < $len; $i++ ){
+ if( !isset($this->params[$i]['name']) && !isset($this->params[$i]['variadic']) ){
+ if( $args[$i]['value']->compile($env)->toCSS() != $this->params[$i]['value']->compile($env)->toCSS() ){
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+}
+
+
+/**
+ * Extend Finder Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_extendFinder extends Less_Visitor{
+
+ public $contexts = array();
+ public $allExtendsStack;
+ public $foundExtends;
+
+ function __construct(){
+ $this->contexts = array();
+ $this->allExtendsStack = array(array());
+ parent::__construct();
+ }
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ function run($root){
+ $root = $this->visitObj($root);
+ $root->allExtends =& $this->allExtendsStack[0];
+ return $root;
+ }
+
+ function visitRule($ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ function visitRuleset($rulesetNode){
+
+ if( $rulesetNode->root ){
+ return;
+ }
+
+ $allSelectorsExtendList = array();
+
+ // get &:extend(.a); rules which apply to all selectors in this ruleset
+ if( $rulesetNode->rules ){
+ foreach($rulesetNode->rules as $rule){
+ if( $rule instanceof Less_Tree_Extend ){
+ $allSelectorsExtendList[] = $rule;
+ $rulesetNode->extendOnEveryPath = true;
+ }
+ }
+ }
+
+
+ // now find every selector and apply the extends that apply to all extends
+ // and the ones which apply to an individual extend
+ foreach($rulesetNode->paths as $selectorPath){
+ $selector = end($selectorPath); //$selectorPath[ count($selectorPath)-1];
+
+ $j = 0;
+ foreach($selector->extendList as $extend){
+ $this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
+ }
+ foreach($allSelectorsExtendList as $extend){
+ $this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
+ }
+ }
+
+ $this->contexts[] = $rulesetNode->selectors;
+ }
+
+ function allExtendsStackPush($rulesetNode, $selectorPath, $extend, &$j){
+ $this->foundExtends = true;
+ $extend = clone $extend;
+ $extend->findSelfSelectors( $selectorPath );
+ $extend->ruleset = $rulesetNode;
+ if( $j === 0 ){
+ $extend->firstExtendOnThisSelectorPath = true;
+ }
+
+ $end_key = count($this->allExtendsStack)-1;
+ $this->allExtendsStack[$end_key][] = $extend;
+ $j++;
+ }
+
+
+ function visitRulesetOut( $rulesetNode ){
+ if( !is_object($rulesetNode) || !$rulesetNode->root ){
+ array_pop($this->contexts);
+ }
+ }
+
+ function visitMedia( $mediaNode ){
+ $mediaNode->allExtends = array();
+ $this->allExtendsStack[] =& $mediaNode->allExtends;
+ }
+
+ function visitMediaOut(){
+ array_pop($this->allExtendsStack);
+ }
+
+ function visitDirective( $directiveNode ){
+ $directiveNode->allExtends = array();
+ $this->allExtendsStack[] =& $directiveNode->allExtends;
+ }
+
+ function visitDirectiveOut(){
+ array_pop($this->allExtendsStack);
+ }
+}
+
+
+
+
+/*
+class Less_Visitor_import extends Less_VisitorReplacing{
+
+ public $_visitor;
+ public $_importer;
+ public $importCount;
+
+ function __construct( $evalEnv ){
+ $this->env = $evalEnv;
+ $this->importCount = 0;
+ parent::__construct();
+ }
+
+
+ function run( $root ){
+ $root = $this->visitObj($root);
+ $this->isFinished = true;
+
+ //if( $this->importCount === 0) {
+ // $this->_finish();
+ //}
+ }
+
+ function visitImport($importNode, &$visitDeeper ){
+ $importVisitor = $this;
+ $inlineCSS = $importNode->options['inline'];
+
+ if( !$importNode->css || $inlineCSS ){
+ $evaldImportNode = $importNode->compileForImport($this->env);
+
+ if( $evaldImportNode && (!$evaldImportNode->css || $inlineCSS) ){
+ $importNode = $evaldImportNode;
+ $this->importCount++;
+ $env = clone $this->env;
+
+ if( (isset($importNode->options['multiple']) && $importNode->options['multiple']) ){
+ $env->importMultiple = true;
+ }
+
+ //get path & uri
+ $path_and_uri = null;
+ if( is_callable(Less_Parser::$options['import_callback']) ){
+ $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$importNode);
+ }
+
+ if( !$path_and_uri ){
+ $path_and_uri = $importNode->PathAndUri();
+ }
+
+ if( $path_and_uri ){
+ list($full_path, $uri) = $path_and_uri;
+ }else{
+ $full_path = $uri = $importNode->getPath();
+ }
+
+
+ //import once
+ if( $importNode->skip( $full_path, $env) ){
+ return array();
+ }
+
+ if( $importNode->options['inline'] ){
+ //todo needs to reference css file not import
+ //$contents = new Less_Tree_Anonymous($importNode->root, 0, array('filename'=>$importNode->importedFilename), true );
+
+ Less_Parser::AddParsedFile($full_path);
+ $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
+
+ if( $importNode->features ){
+ return new Less_Tree_Media( array($contents), $importNode->features->value );
+ }
+
+ return array( $contents );
+ }
+
+
+ // css ?
+ if( $importNode->css ){
+ $features = ( $importNode->features ? $importNode->features->compile($env) : null );
+ return new Less_Tree_Import( $importNode->compilePath( $env), $features, $importNode->options, $this->index);
+ }
+
+ return $importNode->ParseImport( $full_path, $uri, $env );
+ }
+
+ }
+
+ $visitDeeper = false;
+ return $importNode;
+ }
+
+
+ function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ return $ruleNode;
+ }
+
+ function visitDirective($directiveNode, $visitArgs){
+ array_unshift($this->env->frames,$directiveNode);
+ return $directiveNode;
+ }
+
+ function visitDirectiveOut($directiveNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitMixinDefinition($mixinDefinitionNode, $visitArgs) {
+ array_unshift($this->env->frames,$mixinDefinitionNode);
+ return $mixinDefinitionNode;
+ }
+
+ function visitMixinDefinitionOut($mixinDefinitionNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitRuleset($rulesetNode, $visitArgs) {
+ array_unshift($this->env->frames,$rulesetNode);
+ return $rulesetNode;
+ }
+
+ function visitRulesetOut($rulesetNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitMedia($mediaNode, $visitArgs) {
+ array_unshift($this->env->frames, $mediaNode->ruleset);
+ return $mediaNode;
+ }
+
+ function visitMediaOut($mediaNode) {
+ array_shift($this->env->frames);
+ }
+
+}
+*/
+
+
+
+
+/**
+ * Join Selector Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_joinSelector extends Less_Visitor{
+
+ public $contexts = array( array() );
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ function run( $root ){
+ return $this->visitObj($root);
+ }
+
+ function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ function visitRuleset( $rulesetNode ){
+
+ $paths = array();
+
+ if( !$rulesetNode->root ){
+ $selectors = array();
+
+ if( $rulesetNode->selectors && $rulesetNode->selectors ){
+ foreach($rulesetNode->selectors as $selector){
+ if( $selector->getIsOutput() ){
+ $selectors[] = $selector;
+ }
+ }
+ }
+
+ if( !$selectors ){
+ $rulesetNode->selectors = null;
+ $rulesetNode->rules = null;
+ }else{
+ $context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
+ $paths = $rulesetNode->joinSelectors( $context, $selectors);
+ }
+
+ $rulesetNode->paths = $paths;
+ }
+
+ $this->contexts[] = $paths; //different from less.js. Placed after joinSelectors() so that $this->contexts will get correct $paths
+ }
+
+ function visitRulesetOut(){
+ array_pop($this->contexts);
+ }
+
+ function visitMedia($mediaNode) {
+ $context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
+
+ if( !count($context) || (is_object($context[0]) && $context[0]->multiMedia) ){
+ $mediaNode->rules[0]->root = true;
+ }
+ }
+
+}
+
+
+
+/**
+ * Process Extends Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_processExtends extends Less_Visitor{
+
+ public $allExtendsStack;
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ public function run( $root ){
+ $extendFinder = new Less_Visitor_extendFinder();
+ $extendFinder->run( $root );
+ if( !$extendFinder->foundExtends){
+ return $root;
+ }
+
+ $root->allExtends = $this->doExtendChaining( $root->allExtends, $root->allExtends);
+
+ $this->allExtendsStack = array();
+ $this->allExtendsStack[] = &$root->allExtends;
+
+ return $this->visitObj( $root );
+ }
+
+ private function doExtendChaining( $extendsList, $extendsListTarget, $iterationCount = 0){
+ //
+ // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
+ // the selector we would do normally, but we are also adding an extend with the same target selector
+ // this means this new extend can then go and alter other extends
+ //
+ // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
+ // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
+ // we look at each selector at a time, as is done in visitRuleset
+
+ $extendsToAdd = array();
+
+
+ //loop through comparing every extend with every target extend.
+ // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
+ // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
+ // and the second is the target.
+ // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
+ // case when processing media queries
+ for( $extendIndex = 0, $extendsList_len = count($extendsList); $extendIndex < $extendsList_len; $extendIndex++ ){
+ for( $targetExtendIndex = 0; $targetExtendIndex < count($extendsListTarget); $targetExtendIndex++ ){
+
+ $extend = $extendsList[$extendIndex];
+ $targetExtend = $extendsListTarget[$targetExtendIndex];
+
+ // look for circular references
+ if( in_array($targetExtend->object_id, $extend->parent_ids,true) ){
+ continue;
+ }
+
+ // find a match in the target extends self selector (the bit before :extend)
+ $selectorPath = array( $targetExtend->selfSelectors[0] );
+ $matches = $this->findMatch( $extend, $selectorPath);
+
+
+ if( $matches ){
+
+ // we found a match, so for each self selector..
+ foreach($extend->selfSelectors as $selfSelector ){
+
+
+ // process the extend as usual
+ $newSelector = $this->extendSelector( $matches, $selectorPath, $selfSelector);
+
+ // but now we create a new extend from it
+ $newExtend = new Less_Tree_Extend( $targetExtend->selector, $targetExtend->option, 0);
+ $newExtend->selfSelectors = $newSelector;
+
+ // add the extend onto the list of extends for that selector
+ end($newSelector)->extendList = array($newExtend);
+ //$newSelector[ count($newSelector)-1]->extendList = array($newExtend);
+
+ // record that we need to add it.
+ $extendsToAdd[] = $newExtend;
+ $newExtend->ruleset = $targetExtend->ruleset;
+
+ //remember its parents for circular references
+ $newExtend->parent_ids = array_merge($newExtend->parent_ids,$targetExtend->parent_ids,$extend->parent_ids);
+
+ // only process the selector once.. if we have :extend(.a,.b) then multiple
+ // extends will look at the same selector path, so when extending
+ // we know that any others will be duplicates in terms of what is added to the css
+ if( $targetExtend->firstExtendOnThisSelectorPath ){
+ $newExtend->firstExtendOnThisSelectorPath = true;
+ $targetExtend->ruleset->paths[] = $newSelector;
+ }
+ }
+ }
+ }
+ }
+
+ if( $extendsToAdd ){
+ // try to detect circular references to stop a stack overflow.
+ // may no longer be needed. $this->extendChainCount++;
+ if( $iterationCount > 100) {
+
+ try{
+ $selectorOne = $extendsToAdd[0]->selfSelectors[0]->toCSS();
+ $selectorTwo = $extendsToAdd[0]->selector->toCSS();
+ }catch(Exception $e){
+ $selectorOne = "{unable to calculate}";
+ $selectorTwo = "{unable to calculate}";
+ }
+
+ throw new Less_Exception_Parser("extend circular reference detected. One of the circular extends is currently:"+$selectorOne+":extend(" + $selectorTwo+")");
+ }
+
+ // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
+ $extendsToAdd = $this->doExtendChaining( $extendsToAdd, $extendsListTarget, $iterationCount+1);
+ }
+
+ return array_merge($extendsList, $extendsToAdd);
+ }
+
+
+ protected function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitSelector( $selectorNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitRuleset($rulesetNode){
+
+
+ if( $rulesetNode->root ){
+ return;
+ }
+
+ $allExtends = end($this->allExtendsStack);
+ $paths_len = count($rulesetNode->paths);
+
+ // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
+ foreach($allExtends as $allExtend){
+ for($pathIndex = 0; $pathIndex < $paths_len; $pathIndex++ ){
+
+ // extending extends happens initially, before the main pass
+ if( isset($rulesetNode->extendOnEveryPath) && $rulesetNode->extendOnEveryPath ){
+ continue;
+ }
+
+ $selectorPath = $rulesetNode->paths[$pathIndex];
+
+ if( end($selectorPath)->extendList ){
+ continue;
+ }
+
+ $this->ExtendMatch( $rulesetNode, $allExtend, $selectorPath);
+
+ }
+ }
+ }
+
+
+ private function ExtendMatch( $rulesetNode, $extend, $selectorPath ){
+ $matches = $this->findMatch($extend, $selectorPath);
+
+ if( $matches ){
+ foreach($extend->selfSelectors as $selfSelector ){
+ $rulesetNode->paths[] = $this->extendSelector($matches, $selectorPath, $selfSelector);
+ }
+ }
+ }
+
+
+
+ private function findMatch($extend, $haystackSelectorPath ){
+
+
+ if( !$this->HasMatches($extend, $haystackSelectorPath) ){
+ return false;
+ }
+
+
+ //
+ // look through the haystack selector path to try and find the needle - extend.selector
+ // returns an array of selector matches that can then be replaced
+ //
+ $needleElements = $extend->selector->elements;
+ $potentialMatches = array();
+ $potentialMatches_len = 0;
+ $potentialMatch = null;
+ $matches = array();
+
+
+
+ // loop through the haystack elements
+ $haystack_path_len = count($haystackSelectorPath);
+ for($haystackSelectorIndex = 0; $haystackSelectorIndex < $haystack_path_len; $haystackSelectorIndex++ ){
+ $hackstackSelector = $haystackSelectorPath[$haystackSelectorIndex];
+
+ $haystack_elements_len = count($hackstackSelector->elements);
+ for($hackstackElementIndex = 0; $hackstackElementIndex < $haystack_elements_len; $hackstackElementIndex++ ){
+
+ $haystackElement = $hackstackSelector->elements[$hackstackElementIndex];
+
+ // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
+ if( $extend->allowBefore || ($haystackSelectorIndex === 0 && $hackstackElementIndex === 0) ){
+ $potentialMatches[] = array('pathIndex'=> $haystackSelectorIndex, 'index'=> $hackstackElementIndex, 'matched'=> 0, 'initialCombinator'=> $haystackElement->combinator);
+ $potentialMatches_len++;
+ }
+
+ for($i = 0; $i < $potentialMatches_len; $i++ ){
+
+ $potentialMatch = &$potentialMatches[$i];
+ $potentialMatch = $this->PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex );
+
+
+ // if we are still valid and have finished, test whether we have elements after and whether these are allowed
+ if( $potentialMatch && $potentialMatch['matched'] === $extend->selector->elements_len ){
+ $potentialMatch['finished'] = true;
+
+ if( !$extend->allowAfter && ($hackstackElementIndex+1 < $haystack_elements_len || $haystackSelectorIndex+1 < $haystack_path_len) ){
+ $potentialMatch = null;
+ }
+ }
+
+ // if null we remove, if not, we are still valid, so either push as a valid match or continue
+ if( $potentialMatch ){
+ if( $potentialMatch['finished'] ){
+ $potentialMatch['length'] = $extend->selector->elements_len;
+ $potentialMatch['endPathIndex'] = $haystackSelectorIndex;
+ $potentialMatch['endPathElementIndex'] = $hackstackElementIndex + 1; // index after end of match
+ $potentialMatches = array(); // we don't allow matches to overlap, so start matching again
+ $potentialMatches_len = 0;
+ $matches[] = $potentialMatch;
+ }
+ continue;
+ }
+
+ array_splice($potentialMatches, $i, 1);
+ $potentialMatches_len--;
+ $i--;
+ }
+ }
+ }
+
+ return $matches;
+ }
+
+
+ // Before going through all the nested loops, lets check to see if a match is possible
+ // Reduces Bootstrap 3.1 compile time from ~6.5s to ~5.6s
+ private function HasMatches($extend, $haystackSelectorPath){
+
+ if( !$extend->selector->cacheable ){
+ return true;
+ }
+
+ $first_el = $extend->selector->_oelements[0];
+
+ foreach($haystackSelectorPath as $hackstackSelector){
+ if( !$hackstackSelector->cacheable ){
+ return true;
+ }
+
+ if( in_array($first_el, $hackstackSelector->_oelements) ){
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param integer $hackstackElementIndex
+ */
+ private function PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex ){
+
+
+ if( $potentialMatch['matched'] > 0 ){
+
+ // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
+ // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
+ // what the resulting combinator will be
+ $targetCombinator = $haystackElement->combinator;
+ if( $targetCombinator === '' && $hackstackElementIndex === 0 ){
+ $targetCombinator = ' ';
+ }
+
+ if( $needleElements[ $potentialMatch['matched'] ]->combinator !== $targetCombinator ){
+ return null;
+ }
+ }
+
+ // if we don't match, null our match to indicate failure
+ if( !$this->isElementValuesEqual( $needleElements[$potentialMatch['matched'] ]->value, $haystackElement->value) ){
+ return null;
+ }
+
+ $potentialMatch['finished'] = false;
+ $potentialMatch['matched']++;
+
+ return $potentialMatch;
+ }
+
+
+ private function isElementValuesEqual( $elementValue1, $elementValue2 ){
+
+ if( $elementValue1 === $elementValue2 ){
+ return true;
+ }
+
+ if( is_string($elementValue1) || is_string($elementValue2) ) {
+ return false;
+ }
+
+ if( $elementValue1 instanceof Less_Tree_Attribute ){
+ return $this->isAttributeValuesEqual( $elementValue1, $elementValue2 );
+ }
+
+ $elementValue1 = $elementValue1->value;
+ if( $elementValue1 instanceof Less_Tree_Selector ){
+ return $this->isSelectorValuesEqual( $elementValue1, $elementValue2 );
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param Less_Tree_Selector $elementValue1
+ */
+ private function isSelectorValuesEqual( $elementValue1, $elementValue2 ){
+
+ $elementValue2 = $elementValue2->value;
+ if( !($elementValue2 instanceof Less_Tree_Selector) || $elementValue1->elements_len !== $elementValue2->elements_len ){
+ return false;
+ }
+
+ for( $i = 0; $i < $elementValue1->elements_len; $i++ ){
+
+ if( $elementValue1->elements[$i]->combinator !== $elementValue2->elements[$i]->combinator ){
+ if( $i !== 0 || ($elementValue1->elements[$i]->combinator || ' ') !== ($elementValue2->elements[$i]->combinator || ' ') ){
+ return false;
+ }
+ }
+
+ if( !$this->isElementValuesEqual($elementValue1->elements[$i]->value, $elementValue2->elements[$i]->value) ){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param Less_Tree_Attribute $elementValue1
+ */
+ private function isAttributeValuesEqual( $elementValue1, $elementValue2 ){
+
+ if( $elementValue1->op !== $elementValue2->op || $elementValue1->key !== $elementValue2->key ){
+ return false;
+ }
+
+ if( !$elementValue1->value || !$elementValue2->value ){
+ if( $elementValue1->value || $elementValue2->value ) {
+ return false;
+ }
+ return true;
+ }
+
+ $elementValue1 = ($elementValue1->value->value ? $elementValue1->value->value : $elementValue1->value );
+ $elementValue2 = ($elementValue2->value->value ? $elementValue2->value->value : $elementValue2->value );
+
+ return $elementValue1 === $elementValue2;
+ }
+
+
+ private function extendSelector($matches, $selectorPath, $replacementSelector){
+
+ //for a set of matches, replace each match with the replacement selector
+
+ $currentSelectorPathIndex = 0;
+ $currentSelectorPathElementIndex = 0;
+ $path = array();
+ $selectorPath_len = count($selectorPath);
+
+ for($matchIndex = 0, $matches_len = count($matches); $matchIndex < $matches_len; $matchIndex++ ){
+
+
+ $match = $matches[$matchIndex];
+ $selector = $selectorPath[ $match['pathIndex'] ];
+
+ $firstElement = new Less_Tree_Element(
+ $match['initialCombinator'],
+ $replacementSelector->elements[0]->value,
+ $replacementSelector->elements[0]->index,
+ $replacementSelector->elements[0]->currentFileInfo
+ );
+
+ if( $match['pathIndex'] > $currentSelectorPathIndex && $currentSelectorPathElementIndex > 0 ){
+ $last_path = end($path);
+ $last_path->elements = array_merge( $last_path->elements, array_slice( $selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
+ $currentSelectorPathElementIndex = 0;
+ $currentSelectorPathIndex++;
+ }
+
+ $newElements = array_merge(
+ array_slice($selector->elements, $currentSelectorPathElementIndex, ($match['index'] - $currentSelectorPathElementIndex) ) // last parameter of array_slice is different than the last parameter of javascript's slice
+ , array($firstElement)
+ , array_slice($replacementSelector->elements,1)
+ );
+
+ if( $currentSelectorPathIndex === $match['pathIndex'] && $matchIndex > 0 ){
+ $last_key = count($path)-1;
+ $path[$last_key]->elements = array_merge($path[$last_key]->elements,$newElements);
+ }else{
+ $path = array_merge( $path, array_slice( $selectorPath, $currentSelectorPathIndex, $match['pathIndex'] ));
+ $path[] = new Less_Tree_Selector( $newElements );
+ }
+
+ $currentSelectorPathIndex = $match['endPathIndex'];
+ $currentSelectorPathElementIndex = $match['endPathElementIndex'];
+ if( $currentSelectorPathElementIndex >= count($selectorPath[$currentSelectorPathIndex]->elements) ){
+ $currentSelectorPathElementIndex = 0;
+ $currentSelectorPathIndex++;
+ }
+ }
+
+ if( $currentSelectorPathIndex < $selectorPath_len && $currentSelectorPathElementIndex > 0 ){
+ $last_path = end($path);
+ $last_path->elements = array_merge( $last_path->elements, array_slice($selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
+ $currentSelectorPathIndex++;
+ }
+
+ $slice_len = $selectorPath_len - $currentSelectorPathIndex;
+ $path = array_merge($path, array_slice($selectorPath, $currentSelectorPathIndex, $slice_len));
+
+ return $path;
+ }
+
+
+ protected function visitMedia( $mediaNode ){
+ $newAllExtends = array_merge( $mediaNode->allExtends, end($this->allExtendsStack) );
+ $this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $mediaNode->allExtends);
+ }
+
+ protected function visitMediaOut(){
+ array_pop( $this->allExtendsStack );
+ }
+
+ protected function visitDirective( $directiveNode ){
+ $newAllExtends = array_merge( $directiveNode->allExtends, end($this->allExtendsStack) );
+ $this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $directiveNode->allExtends);
+ }
+
+ protected function visitDirectiveOut(){
+ array_pop($this->allExtendsStack);
+ }
+
+}
+
+/**
+ * toCSS Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_toCSS extends Less_VisitorReplacing{
+
+ private $charset;
+
+ function __construct(){
+ parent::__construct();
+ }
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ function run( $root ){
+ return $this->visitObj($root);
+ }
+
+ function visitRule( $ruleNode ){
+ if( $ruleNode->variable ){
+ return array();
+ }
+ return $ruleNode;
+ }
+
+ function visitMixinDefinition($mixinNode){
+ // mixin definitions do not get eval'd - this means they keep state
+ // so we have to clear that state here so it isn't used if toCSS is called twice
+ $mixinNode->frames = array();
+ return array();
+ }
+
+ function visitExtend(){
+ return array();
+ }
+
+ function visitComment( $commentNode ){
+ if( $commentNode->isSilent() ){
+ return array();
+ }
+ return $commentNode;
+ }
+
+ function visitMedia( $mediaNode, &$visitDeeper ){
+ $mediaNode->accept($this);
+ $visitDeeper = false;
+
+ if( !$mediaNode->rules ){
+ return array();
+ }
+ return $mediaNode;
+ }
+
+ function visitDirective( $directiveNode ){
+ if( isset($directiveNode->currentFileInfo['reference']) && (!property_exists($directiveNode,'isReferenced') || !$directiveNode->isReferenced) ){
+ return array();
+ }
+ if( $directiveNode->name === '@charset' ){
+ // Only output the debug info together with subsequent @charset definitions
+ // a comment (or @media statement) before the actual @charset directive would
+ // be considered illegal css as it has to be on the first line
+ if( isset($this->charset) && $this->charset ){
+
+ //if( $directiveNode->debugInfo ){
+ // $comment = new Less_Tree_Comment('/* ' . str_replace("\n",'',$directiveNode->toCSS())." */\n");
+ // $comment->debugInfo = $directiveNode->debugInfo;
+ // return $this->visit($comment);
+ //}
+
+
+ return array();
+ }
+ $this->charset = true;
+ }
+ return $directiveNode;
+ }
+
+ function checkPropertiesInRoot( $rulesetNode ){
+
+ if( !$rulesetNode->firstRoot ){
+ return;
+ }
+
+ foreach($rulesetNode->rules as $ruleNode){
+ if( $ruleNode instanceof Less_Tree_Rule && !$ruleNode->variable ){
+ $msg = "properties must be inside selector blocks, they cannot be in the root. Index ".$ruleNode->index.($ruleNode->currentFileInfo ? (' Filename: '.$ruleNode->currentFileInfo['filename']) : null);
+ throw new Less_Exception_Compiler($msg);
+ }
+ }
+ }
+
+
+ function visitRuleset( $rulesetNode, &$visitDeeper ){
+
+ $visitDeeper = false;
+
+ $this->checkPropertiesInRoot( $rulesetNode );
+
+ if( $rulesetNode->root ){
+ return $this->visitRulesetRoot( $rulesetNode );
+ }
+
+ $rulesets = array();
+ $rulesetNode->paths = $this->visitRulesetPaths($rulesetNode);
+
+
+ // Compile rules and rulesets
+ $nodeRuleCnt = count($rulesetNode->rules);
+ for( $i = 0; $i < $nodeRuleCnt; ){
+ $rule = $rulesetNode->rules[$i];
+
+ if( property_exists($rule,'rules') ){
+ // visit because we are moving them out from being a child
+ $rulesets[] = $this->visitObj($rule);
+ array_splice($rulesetNode->rules,$i,1);
+ $nodeRuleCnt--;
+ continue;
+ }
+ $i++;
+ }
+
+
+ // accept the visitor to remove rules and refactor itself
+ // then we can decide now whether we want it or not
+ if( $nodeRuleCnt > 0 ){
+ $rulesetNode->accept($this);
+
+ if( $rulesetNode->rules ){
+
+ if( count($rulesetNode->rules) > 1 ){
+ $this->_mergeRules( $rulesetNode->rules );
+ $this->_removeDuplicateRules( $rulesetNode->rules );
+ }
+
+ // now decide whether we keep the ruleset
+ if( $rulesetNode->paths ){
+ //array_unshift($rulesets, $rulesetNode);
+ array_splice($rulesets,0,0,array($rulesetNode));
+ }
+ }
+
+ }
+
+
+ if( count($rulesets) === 1 ){
+ return $rulesets[0];
+ }
+ return $rulesets;
+ }
+
+
+ /**
+ * Helper function for visitiRuleset
+ *
+ * return array|Less_Tree_Ruleset
+ */
+ private function visitRulesetRoot( $rulesetNode ){
+ $rulesetNode->accept( $this );
+ if( $rulesetNode->firstRoot || $rulesetNode->rules ){
+ return $rulesetNode;
+ }
+ return array();
+ }
+
+
+ /**
+ * Helper function for visitRuleset()
+ *
+ * @return array
+ */
+ private function visitRulesetPaths($rulesetNode){
+
+ $paths = array();
+ foreach($rulesetNode->paths as $p){
+ if( $p[0]->elements[0]->combinator === ' ' ){
+ $p[0]->elements[0]->combinator = '';
+ }
+
+ foreach($p as $pi){
+ if( $pi->getIsReferenced() && $pi->getIsOutput() ){
+ $paths[] = $p;
+ break;
+ }
+ }
+ }
+
+ return $paths;
+ }
+
+ function _removeDuplicateRules( &$rules ){
+ // remove duplicates
+ $ruleCache = array();
+ for( $i = count($rules)-1; $i >= 0 ; $i-- ){
+ $rule = $rules[$i];
+ if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_NameValue ){
+
+ if( !isset($ruleCache[$rule->name]) ){
+ $ruleCache[$rule->name] = $rule;
+ }else{
+ $ruleList =& $ruleCache[$rule->name];
+
+ if( $ruleList instanceof Less_Tree_Rule || $ruleList instanceof Less_Tree_NameValue ){
+ $ruleList = $ruleCache[$rule->name] = array( $ruleCache[$rule->name]->toCSS() );
+ }
+
+ $ruleCSS = $rule->toCSS();
+ if( array_search($ruleCSS,$ruleList) !== false ){
+ array_splice($rules,$i,1);
+ }else{
+ $ruleList[] = $ruleCSS;
+ }
+ }
+ }
+ }
+ }
+
+ function _mergeRules( &$rules ){
+ $groups = array();
+
+ //obj($rules);
+
+ $rules_len = count($rules);
+ for( $i = 0; $i < $rules_len; $i++ ){
+ $rule = $rules[$i];
+
+ if( ($rule instanceof Less_Tree_Rule) && $rule->merge ){
+
+ $key = $rule->name;
+ if( $rule->important ){
+ $key .= ',!';
+ }
+
+ if( !isset($groups[$key]) ){
+ $groups[$key] = array();
+ }else{
+ array_splice($rules, $i--, 1);
+ $rules_len--;
+ }
+
+ $groups[$key][] = $rule;
+ }
+ }
+
+
+ foreach($groups as $parts){
+
+ if( count($parts) > 1 ){
+ $rule = $parts[0];
+ $spacedGroups = array();
+ $lastSpacedGroup = array();
+ $parts_mapped = array();
+ foreach($parts as $p){
+ if( $p->merge === '+' ){
+ if( $lastSpacedGroup ){
+ $spacedGroups[] = self::toExpression($lastSpacedGroup);
+ }
+ $lastSpacedGroup = array();
+ }
+ $lastSpacedGroup[] = $p;
+ }
+
+ $spacedGroups[] = self::toExpression($lastSpacedGroup);
+ $rule->value = self::toValue($spacedGroups);
+ }
+ }
+
+ }
+
+ static function toExpression($values){
+ $mapped = array();
+ foreach($values as $p){
+ $mapped[] = $p->value;
+ }
+ return new Less_Tree_Expression( $mapped );
+ }
+
+ static function toValue($values){
+ //return new Less_Tree_Value($values); ??
+
+ $mapped = array();
+ foreach($values as $p){
+ $mapped[] = $p;
+ }
+ return new Less_Tree_Value($mapped);
+ }
+}
+
+
+
+/**
+ * Parser Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Parser extends Exception{
+
+ /**
+ * The current file
+ *
+ * @var Less_ImportedFile
+ */
+ public $currentFile;
+
+ /**
+ * The current parser index
+ *
+ * @var integer
+ */
+ public $index;
+
+ protected $input;
+
+ protected $details = array();
+
+
+ /**
+ * Constructor
+ *
+ * @param string $message
+ * @param Exception $previous Previous exception
+ * @param integer $index The current parser index
+ * @param Less_FileInfo|string $currentFile The file
+ * @param integer $code The exception code
+ */
+ public function __construct($message = null, Exception $previous = null, $index = null, $currentFile = null, $code = 0){
+
+ if (PHP_VERSION_ID < 50300) {
+ $this->previous = $previous;
+ parent::__construct($message, $code);
+ } else {
+ parent::__construct($message, $code, $previous);
+ }
+
+ $this->currentFile = $currentFile;
+ $this->index = $index;
+
+ $this->genMessage();
+ }
+
+
+ protected function getInput(){
+
+ if( !$this->input && $this->currentFile && $this->currentFile['filename'] ){
+ $this->input = file_get_contents( $this->currentFile['filename'] );
+ }
+ }
+
+
+
+ /**
+ * Converts the exception to string
+ *
+ * @return string
+ */
+ public function genMessage(){
+
+ if( $this->currentFile && $this->currentFile['filename'] ){
+ $this->message .= ' in '.basename($this->currentFile['filename']);
+ }
+
+ if( $this->index !== null ){
+ $this->getInput();
+ if( $this->input ){
+ $line = self::getLineNumber();
+ $this->message .= ' on line '.$line.', column '.self::getColumn();
+
+ $lines = explode("\n",$this->input);
+
+ $count = count($lines);
+ $start_line = max(0, $line-3);
+ $last_line = min($count, $start_line+6);
+ $num_len = strlen($last_line);
+ for( $i = $start_line; $i < $last_line; $i++ ){
+ $this->message .= "\n".str_pad($i+1,$num_len,'0',STR_PAD_LEFT).'| '.$lines[$i];
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Returns the line number the error was encountered
+ *
+ * @return integer
+ */
+ public function getLineNumber(){
+ if( $this->index ){
+ return substr_count($this->input, "\n", 0, $this->index) + 1;
+ }
+ return 1;
+ }
+
+
+ /**
+ * Returns the column the error was encountered
+ *
+ * @return integer
+ */
+ public function getColumn(){
+
+ $part = substr($this->input, 0, $this->index);
+ $pos = strrpos($part,"\n");
+ return $this->index - $pos;
+ }
+
+}
+
+
+/**
+ * Chunk Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Chunk extends Less_Exception_Parser{
+
+
+ protected $parserCurrentIndex = 0;
+
+ protected $emitFrom = 0;
+
+ protected $input_len;
+
+
+ /**
+ * Constructor
+ *
+ * @param string $input
+ * @param Exception $previous Previous exception
+ * @param integer $index The current parser index
+ * @param Less_FileInfo|string $currentFile The file
+ * @param integer $code The exception code
+ */
+ public function __construct($input, Exception $previous = null, $index = null, $currentFile = null, $code = 0){
+
+ $this->message = 'ParseError: Unexpected input'; //default message
+
+ $this->index = $index;
+
+ $this->currentFile = $currentFile;
+
+ $this->input = $input;
+ $this->input_len = strlen($input);
+
+ $this->Chunks();
+ $this->genMessage();
+ }
+
+
+ /**
+ * See less.js chunks()
+ * We don't actually need the chunks
+ *
+ */
+ function Chunks(){
+ $level = 0;
+ $parenLevel = 0;
+ $lastMultiCommentEndBrace = null;
+ $lastOpening = null;
+ $lastMultiComment = null;
+ $lastParen = null;
+
+ for( $this->parserCurrentIndex = 0; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ){
+ $cc = $this->CharCode($this->parserCurrentIndex);
+ if ((($cc >= 97) && ($cc <= 122)) || ($cc < 34)) {
+ // a-z or whitespace
+ continue;
+ }
+
+ switch ($cc) {
+
+ // (
+ case 40:
+ $parenLevel++;
+ $lastParen = $this->parserCurrentIndex;
+ continue;
+
+ // )
+ case 41:
+ $parenLevel--;
+ if( $parenLevel < 0 ){
+ return $this->fail("missing opening `(`");
+ }
+ continue;
+
+ // ;
+ case 59:
+ //if (!$parenLevel) { $this->emitChunk(); }
+ continue;
+
+ // {
+ case 123:
+ $level++;
+ $lastOpening = $this->parserCurrentIndex;
+ continue;
+
+ // }
+ case 125:
+ $level--;
+ if( $level < 0 ){
+ return $this->fail("missing opening `{`");
+
+ }
+ //if (!$level && !$parenLevel) { $this->emitChunk(); }
+ continue;
+ // \
+ case 92:
+ if ($this->parserCurrentIndex < $this->input_len - 1) { $this->parserCurrentIndex++; continue; }
+ return $this->fail("unescaped `\\`");
+
+ // ", ' and `
+ case 34:
+ case 39:
+ case 96:
+ $matched = 0;
+ $currentChunkStartIndex = $this->parserCurrentIndex;
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 1; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if ($cc2 > 96) { continue; }
+ if ($cc2 == $cc) { $matched = 1; break; }
+ if ($cc2 == 92) { // \
+ if ($this->parserCurrentIndex == $this->input_len - 1) {
+ return $this->fail("unescaped `\\`");
+ }
+ $this->parserCurrentIndex++;
+ }
+ }
+ if ($matched) { continue; }
+ return $this->fail("unmatched `" + chr($cc) + "`", $currentChunkStartIndex);
+
+ // /, check for comment
+ case 47:
+ if ($parenLevel || ($this->parserCurrentIndex == $this->input_len - 1)) { continue; }
+ $cc2 = $this->CharCode($this->parserCurrentIndex+1);
+ if ($cc2 == 47) {
+ // //, find lnfeed
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if (($cc2 <= 13) && (($cc2 == 10) || ($cc2 == 13))) { break; }
+ }
+ } else if ($cc2 == 42) {
+ // /*, find */
+ $lastMultiComment = $currentChunkStartIndex = $this->parserCurrentIndex;
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len - 1; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if ($cc2 == 125) { $lastMultiCommentEndBrace = $this->parserCurrentIndex; }
+ if ($cc2 != 42) { continue; }
+ if ($this->CharCode($this->parserCurrentIndex+1) == 47) { break; }
+ }
+ if ($this->parserCurrentIndex == $this->input_len - 1) {
+ return $this->fail("missing closing `*/`", $currentChunkStartIndex);
+ }
+ }
+ continue;
+
+ // *, check for unmatched */
+ case 42:
+ if (($this->parserCurrentIndex < $this->input_len - 1) && ($this->CharCode($this->parserCurrentIndex+1) == 47)) {
+ return $this->fail("unmatched `/*`");
+ }
+ continue;
+ }
+ }
+
+ if( $level !== 0 ){
+ if( ($lastMultiComment > $lastOpening) && ($lastMultiCommentEndBrace > $lastMultiComment) ){
+ return $this->fail("missing closing `}` or `*/`", $lastOpening);
+ } else {
+ return $this->fail("missing closing `}`", $lastOpening);
+ }
+ } else if ( $parenLevel !== 0 ){
+ return $this->fail("missing closing `)`", $lastParen);
+ }
+
+
+ //chunk didn't fail
+
+
+ //$this->emitChunk(true);
+ }
+
+ function CharCode($pos){
+ return ord($this->input[$pos]);
+ }
+
+
+ function fail( $msg, $index = null ){
+
+ if( !$index ){
+ $this->index = $this->parserCurrentIndex;
+ }else{
+ $this->index = $index;
+ }
+ $this->message = 'ParseError: '.$msg;
+ }
+
+
+ /*
+ function emitChunk( $force = false ){
+ $len = $this->parserCurrentIndex - $this->emitFrom;
+ if ((($len < 512) && !$force) || !$len) {
+ return;
+ }
+ $chunks[] = substr($this->input, $this->emitFrom, $this->parserCurrentIndex + 1 - $this->emitFrom );
+ $this->emitFrom = $this->parserCurrentIndex + 1;
+ }
+ */
+
+}
+
+
+/**
+ * Compiler Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Compiler extends Less_Exception_Parser{
+
+}
+
+/**
+ * Parser output with source map
+ *
+ * @package Less
+ * @subpackage Output
+ */
+class Less_Output_Mapped extends Less_Output {
+
+ /**
+ * The source map generator
+ *
+ * @var Less_SourceMap_Generator
+ */
+ protected $generator;
+
+ /**
+ * Current line
+ *
+ * @var integer
+ */
+ protected $lineNumber = 0;
+
+ /**
+ * Current column
+ *
+ * @var integer
+ */
+ protected $column = 0;
+
+ /**
+ * Array of contents map (file and its content)
+ *
+ * @var array
+ */
+ protected $contentsMap = array();
+
+ /**
+ * Constructor
+ *
+ * @param array $contentsMap Array of filename to contents map
+ * @param Less_SourceMap_Generator $generator
+ */
+ public function __construct(array $contentsMap, $generator){
+ $this->contentsMap = $contentsMap;
+ $this->generator = $generator;
+ }
+
+ /**
+ * Adds a chunk to the stack
+ * The $index for less.php may be different from less.js since less.php does not chunkify inputs
+ *
+ * @param string $chunk
+ * @param string $fileInfo
+ * @param integer $index
+ * @param mixed $mapLines
+ */
+ public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
+
+ //ignore adding empty strings
+ if( $chunk === '' ){
+ return;
+ }
+
+
+ $sourceLines = array();
+ $sourceColumns = ' ';
+
+
+ if( $fileInfo ){
+
+ $url = $fileInfo['currentUri'];
+
+ if( isset($this->contentsMap[$url]) ){
+ $inputSource = substr($this->contentsMap[$url], 0, $index);
+ $sourceLines = explode("\n", $inputSource);
+ $sourceColumns = end($sourceLines);
+ }else{
+ throw new Exception('Filename '.$url.' not in contentsMap');
+ }
+
+ }
+
+ $lines = explode("\n", $chunk);
+ $columns = end($lines);
+
+ if($fileInfo){
+
+ if(!$mapLines){
+ $this->generator->addMapping(
+ $this->lineNumber + 1, // generated_line
+ $this->column, // generated_column
+ count($sourceLines), // original_line
+ strlen($sourceColumns), // original_column
+ $fileInfo['currentUri']
+ );
+ }else{
+ for($i = 0, $count = count($lines); $i < $count; $i++){
+ $this->generator->addMapping(
+ $this->lineNumber + $i + 1, // generated_line
+ $i === 0 ? $this->column : 0, // generated_column
+ count($sourceLines) + $i, // original_line
+ $i === 0 ? strlen($sourceColumns) : 0, // original_column
+ $fileInfo['currentUri']
+ );
+ }
+ }
+ }
+
+ if(count($lines) === 1){
+ $this->column += strlen($columns);
+ }else{
+ $this->lineNumber += count($lines) - 1;
+ $this->column = strlen($columns);
+ }
+
+ // add only chunk
+ parent::add($chunk);
+ }
+
+}
+
+/**
+ * Encode / Decode Base64 VLQ.
+ *
+ * @package Less
+ * @subpackage SourceMap
+ */
+class Less_SourceMap_Base64VLQ {
+
+ /**
+ * Shift
+ *
+ * @var integer
+ */
+ private $shift = 5;
+
+ /**
+ * Mask
+ *
+ * @var integer
+ */
+ private $mask = 0x1F; // == (1 << shift) == 0b00011111
+
+ /**
+ * Continuation bit
+ *
+ * @var integer
+ */
+ private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000
+
+ /**
+ * Char to integer map
+ *
+ * @var array
+ */
+ private $charToIntMap = array(
+ 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6,
+ 'H' => 7,'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
+ 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20,
+ 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27,
+ 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34,
+ 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41,
+ 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48,
+ 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, 4 => 56,
+ 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63,
+ );
+
+ /**
+ * Integer to char map
+ *
+ * @var array
+ */
+ private $intToCharMap = array(
+ 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G',
+ 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N',
+ 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U',
+ 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b',
+ 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i',
+ 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p',
+ 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w',
+ 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3',
+ 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+',
+ 63 => '/',
+ );
+
+ /**
+ * Constructor
+ */
+ public function __construct(){
+ // I leave it here for future reference
+ // foreach(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char)
+ // {
+ // $this->charToIntMap[$char] = $i;
+ // $this->intToCharMap[$i] = $char;
+ // }
+ }
+
+ /**
+ * Convert from a two-complement value to a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
+ * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
+ * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297,
+ * even on a 64 bit machine.
+ * @param string $aValue
+ */
+ public function toVLQSigned($aValue){
+ return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0);
+ }
+
+ /**
+ * Convert to a two-complement value from a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
+ * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
+ * We assume that the value was generated with a 32 bit machine in mind.
+ * Hence
+ * 1 becomes -2147483648
+ * even on a 64 bit machine.
+ * @param integer $aValue
+ */
+ public function fromVLQSigned($aValue){
+ return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1);
+ }
+
+ /**
+ * Return the base 64 VLQ encoded value.
+ *
+ * @param string $aValue The value to encode
+ * @return string The encoded value
+ */
+ public function encode($aValue){
+ $encoded = '';
+ $vlq = $this->toVLQSigned($aValue);
+ do
+ {
+ $digit = $vlq & $this->mask;
+ $vlq = $this->zeroFill($vlq, $this->shift);
+ if($vlq > 0){
+ $digit |= $this->continuationBit;
+ }
+ $encoded .= $this->base64Encode($digit);
+ } while($vlq > 0);
+
+ return $encoded;
+ }
+
+ /**
+ * Return the value decoded from base 64 VLQ.
+ *
+ * @param string $encoded The encoded value to decode
+ * @return integer The decoded value
+ */
+ public function decode($encoded){
+ $vlq = 0;
+ $i = 0;
+ do
+ {
+ $digit = $this->base64Decode($encoded[$i]);
+ $vlq |= ($digit & $this->mask) << ($i * $this->shift);
+ $i++;
+ } while($digit & $this->continuationBit);
+
+ return $this->fromVLQSigned($vlq);
+ }
+
+ /**
+ * Right shift with zero fill.
+ *
+ * @param integer $a number to shift
+ * @param integer $b number of bits to shift
+ * @return integer
+ */
+ public function zeroFill($a, $b){
+ return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1));
+ }
+
+ /**
+ * Encode single 6-bit digit as base64.
+ *
+ * @param integer $number
+ * @return string
+ * @throws Exception If the number is invalid
+ */
+ public function base64Encode($number){
+ if($number < 0 || $number > 63){
+ throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number));
+ }
+ return $this->intToCharMap[$number];
+ }
+
+ /**
+ * Decode single 6-bit digit from base64
+ *
+ * @param string $char
+ * @return number
+ * @throws Exception If the number is invalid
+ */
+ public function base64Decode($char){
+ if(!array_key_exists($char, $this->charToIntMap)){
+ throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char));
+ }
+ return $this->charToIntMap[$char];
+ }
+
+}
+
+
+/**
+ * Source map generator
+ *
+ * @package Less
+ * @subpackage Output
+ */
+class Less_SourceMap_Generator extends Less_Configurable {
+
+ /**
+ * What version of source map does the generator generate?
+ */
+ const VERSION = 3;
+
+ /**
+ * Array of default options
+ *
+ * @var array
+ */
+ protected $defaultOptions = array(
+ // an optional source root, useful for relocating source files
+ // on a server or removing repeated values in the 'sources' entry.
+ // This value is prepended to the individual entries in the 'source' field.
+ 'sourceRoot' => '',
+
+ // an optional name of the generated code that this source map is associated with.
+ 'sourceMapFilename' => null,
+
+ // url of the map
+ 'sourceMapURL' => null,
+
+ // absolute path to a file to write the map to
+ 'sourceMapWriteTo' => null,
+
+ // output source contents?
+ 'outputSourceFiles' => false,
+
+ // base path for filename normalization
+ 'sourceMapBasepath' => ''
+ );
+
+ /**
+ * The base64 VLQ encoder
+ *
+ * @var Less_SourceMap_Base64VLQ
+ */
+ protected $encoder;
+
+ /**
+ * Array of mappings
+ *
+ * @var array
+ */
+ protected $mappings = array();
+
+ /**
+ * The root node
+ *
+ * @var Less_Tree_Ruleset
+ */
+ protected $root;
+
+ /**
+ * Array of contents map
+ *
+ * @var array
+ */
+ protected $contentsMap = array();
+
+ /**
+ * File to content map
+ *
+ * @var array
+ */
+ protected $sources = array();
+
+ /**
+ * Constructor
+ *
+ * @param Less_Tree_Ruleset $root The root node
+ * @param array $options Array of options
+ */
+ public function __construct(Less_Tree_Ruleset $root, $contentsMap, $options = array()){
+ $this->root = $root;
+ $this->contentsMap = $contentsMap;
+ $this->encoder = new Less_SourceMap_Base64VLQ();
+
+ $this->SetOptions($options);
+
+
+ // fix windows paths
+ if( isset($this->options['sourceMapBasepath']) ){
+ $this->options['sourceMapBasepath'] = str_replace('\\', '/', $this->options['sourceMapBasepath']);
+ }
+ }
+
+ /**
+ * Generates the CSS
+ *
+ * @return string
+ */
+ public function generateCSS(){
+ $output = new Less_Output_Mapped($this->contentsMap, $this);
+
+ // catch the output
+ $this->root->genCSS($output);
+
+
+ $sourceMapUrl = $this->getOption('sourceMapURL');
+ $sourceMapFilename = $this->getOption('sourceMapFilename');
+ $sourceMapContent = $this->generateJson();
+ $sourceMapWriteTo = $this->getOption('sourceMapWriteTo');
+
+ if( !$sourceMapUrl && $sourceMapFilename ){
+ $sourceMapUrl = $this->normalizeFilename($sourceMapFilename);
+ }
+
+ // write map to a file
+ if( $sourceMapWriteTo ){
+ $this->saveMap($sourceMapWriteTo, $sourceMapContent);
+ }
+
+ // inline the map
+ if( !$sourceMapUrl ){
+ $sourceMapUrl = sprintf('data:application/json,%s', Less_Functions::encodeURIComponent($sourceMapContent));
+ }
+
+ if( $sourceMapUrl ){
+ $output->add( sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl) );
+ }
+
+ return $output->toString();
+ }
+
+ /**
+ * Saves the source map to a file
+ *
+ * @param string $file The absolute path to a file
+ * @param string $content The content to write
+ * @throws Exception If the file could not be saved
+ */
+ protected function saveMap($file, $content){
+ $dir = dirname($file);
+ // directory does not exist
+ if( !is_dir($dir) ){
+ // FIXME: create the dir automatically?
+ throw new Exception(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir));
+ }
+ // FIXME: proper saving, with dir write check!
+ if(file_put_contents($file, $content) === false){
+ throw new Exception(sprintf('Cannot save the source map to "%s"', $file));
+ }
+ return true;
+ }
+
+ /**
+ * Normalizes the filename
+ *
+ * @param string $filename
+ * @return string
+ */
+ protected function normalizeFilename($filename){
+ $filename = str_replace('\\', '/', $filename);
+ $basePath = $this->getOption('sourceMapBasepath');
+
+ if( $basePath && ($pos = strpos($filename, $basePath)) !== false ){
+ $filename = substr($filename, $pos + strlen($basePath));
+ if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0){
+ $filename = substr($filename, 1);
+ }
+ }
+ return sprintf('%s%s', $this->getOption('sourceMapRootpath'), $filename);
+ }
+
+ /**
+ * Adds a mapping
+ *
+ * @param integer $generatedLine The line number in generated file
+ * @param integer $generatedColumn The column number in generated file
+ * @param integer $originalLine The line number in original file
+ * @param integer $originalColumn The column number in original file
+ * @param string $sourceFile The original source file
+ */
+ public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile){
+ $this->mappings[] = array(
+ 'generated_line' => $generatedLine,
+ 'generated_column' => $generatedColumn,
+ 'original_line' => $originalLine,
+ 'original_column' => $originalColumn,
+ 'source_file' => $sourceFile
+ );
+
+
+ $norm_file = $this->normalizeFilename($sourceFile);
+
+ $this->sources[$norm_file] = $sourceFile;
+ }
+
+
+ /**
+ * Generates the JSON source map
+ *
+ * @return string
+ * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#
+ */
+ protected function generateJson(){
+
+ $sourceMap = array();
+ $mappings = $this->generateMappings();
+
+ // File version (always the first entry in the object) and must be a positive integer.
+ $sourceMap['version'] = self::VERSION;
+
+
+ // An optional name of the generated code that this source map is associated with.
+ $file = $this->getOption('sourceMapFilename');
+ if( $file ){
+ $sourceMap['file'] = $file;
+ }
+
+
+ // An optional source root, useful for relocating source files on a server or removing repeated values in the 'sources' entry. This value is prepended to the individual entries in the 'source' field.
+ $root = $this->getOption('sourceRoot');
+ if( $root ){
+ $sourceMap['sourceRoot'] = $root;
+ }
+
+
+ // A list of original sources used by the 'mappings' entry.
+ $sourceMap['sources'] = array_keys($this->sources);
+
+
+
+ // A list of symbol names used by the 'mappings' entry.
+ $sourceMap['names'] = array();
+
+ // A string with the encoded mapping data.
+ $sourceMap['mappings'] = $mappings;
+
+ if( $this->getOption('outputSourceFiles') ){
+ // An optional list of source content, useful when the 'source' can't be hosted.
+ // The contents are listed in the same order as the sources above.
+ // 'null' may be used if some original sources should be retrieved by name.
+ $sourceMap['sourcesContent'] = $this->getSourcesContent();
+ }
+
+ // less.js compat fixes
+ if( count($sourceMap['sources']) && empty($sourceMap['sourceRoot']) ){
+ unset($sourceMap['sourceRoot']);
+ }
+
+ return json_encode($sourceMap);
+ }
+
+ /**
+ * Returns the sources contents
+ *
+ * @return array|null
+ */
+ protected function getSourcesContent(){
+ if(empty($this->sources)){
+ return;
+ }
+ $content = array();
+ foreach($this->sources as $sourceFile){
+ $content[] = file_get_contents($sourceFile);
+ }
+ return $content;
+ }
+
+ /**
+ * Generates the mappings string
+ *
+ * @return string
+ */
+ public function generateMappings(){
+
+ if( !count($this->mappings) ){
+ return '';
+ }
+
+ // group mappings by generated line number.
+ $groupedMap = $groupedMapEncoded = array();
+ foreach($this->mappings as $m){
+ $groupedMap[$m['generated_line']][] = $m;
+ }
+ ksort($groupedMap);
+
+ $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;
+
+ foreach($groupedMap as $lineNumber => $line_map){
+ while(++$lastGeneratedLine < $lineNumber){
+ $groupedMapEncoded[] = ';';
+ }
+
+ $lineMapEncoded = array();
+ $lastGeneratedColumn = 0;
+
+ foreach($line_map as $m){
+ $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
+ $lastGeneratedColumn = $m['generated_column'];
+
+ // find the index
+ if( $m['source_file'] ){
+ $index = $this->findFileIndex($this->normalizeFilename($m['source_file']));
+ if( $index !== false ){
+ $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex);
+ $lastOriginalIndex = $index;
+
+ // lines are stored 0-based in SourceMap spec version 3
+ $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine);
+ $lastOriginalLine = $m['original_line'] - 1;
+
+ $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn);
+ $lastOriginalColumn = $m['original_column'];
+ }
+ }
+
+ $lineMapEncoded[] = $mapEncoded;
+ }
+
+ $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';';
+ }
+
+ return rtrim(implode($groupedMapEncoded), ';');
+ }
+
+ /**
+ * Finds the index for the filename
+ *
+ * @param string $filename
+ * @return integer|false
+ */
+ protected function findFileIndex($filename){
+ return array_search($filename, array_keys($this->sources));
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/lessphp/less/version.php b/plugins/system/t3/includes/lessphp/less/version.php
new file mode 100644
index 0000000..5737a50
--- /dev/null
+++ b/plugins/system/t3/includes/lessphp/less/version.php
@@ -0,0 +1,15 @@
+
+ * Licensed under MIT or GPLv3, see LICENSE
+ */
+
+
+/**
+ * The less compiler and parser.
+ *
+ * Converting LESS to CSS is a three stage process. The incoming file is parsed
+ * by `lessc_parser` into a syntax tree, then it is compiled into another tree
+ * representing the CSS structure by `lessc`. The CSS tree is fed into a
+ * formatter, like `lessc_formatter` which then outputs CSS as a string.
+ *
+ * During the first compile, all values are *reduced*, which means that their
+ * types are brought to the lowest form before being dump as strings. This
+ * handles math equations, variable dereferences, and the like.
+ *
+ * The `parse` function of `lessc` is the entry point.
+ *
+ * In summary:
+ *
+ * The `lessc` class creates an intstance of the parser, feeds it LESS code,
+ * then transforms the resulting tree to a CSS tree. This class also holds the
+ * evaluation context, such as all available mixins and variables at any given
+ * time.
+ *
+ * The `lessc_parser` class is only concerned with parsing its input.
+ *
+ * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
+ * handling things like indentation.
+ */
+class lessc {
+ static public $VERSION = "v0.3.9";
+ static protected $TRUE = array("keyword", "true");
+ static protected $FALSE = array("keyword", "false");
+
+ protected $libFunctions = array();
+ protected $registeredVars = array();
+ protected $preserveComments = false;
+
+ public $vPrefix = '@'; // prefix of abstract properties
+ public $mPrefix = '$'; // prefix of abstract blocks
+ public $parentSelector = '&';
+
+ public $importDisabled = false;
+ public $importDir = '';
+
+ protected $numberPrecision = null;
+
+ // set to the parser that generated the current line when compiling
+ // so we know how to create error messages
+ protected $sourceParser = null;
+ protected $sourceLoc = null;
+
+ static public $defaultValue = array("keyword", "");
+
+ static protected $nextImportId = 0; // uniquely identify imports
+
+ // attempts to find the path of an import url, returns null for css files
+ protected function findImport($url) {
+ foreach ((array)$this->importDir as $dir) {
+ $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
+ if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
+ return $file;
+ }
+ }
+
+ return null;
+ }
+
+ protected function fileExists($name) {
+ return is_file($name);
+ }
+
+ static public function compressList($items, $delim) {
+ if (!isset($items[1]) && isset($items[0])) return $items[0];
+ else return array('list', $delim, $items);
+ }
+
+ static public function preg_quote($what) {
+ return preg_quote($what, '/');
+ }
+
+ protected function tryImport($importPath, $parentBlock, $out) {
+ if ($importPath[0] == "function" && $importPath[1] == "url") {
+ $importPath = $this->flattenList($importPath[2]);
+ }
+
+ $str = $this->coerceString($importPath);
+ if ($str === null) return false;
+
+ $url = $this->compileValue($this->lib_e($str));
+
+ // don't import if it ends in css
+ if (substr_compare($url, '.css', -4, 4) === 0) return false;
+
+ $realPath = $this->findImport($url);
+ if ($realPath === null) return false;
+
+ if ($this->importDisabled) {
+ return array(false, "/* import disabled */");
+ }
+
+ $this->addParsedFile($realPath);
+ $parser = $this->makeParser($realPath);
+ $root = $parser->parse(file_get_contents($realPath));
+
+ // set the parents of all the block props
+ foreach ($root->props as $prop) {
+ if ($prop[0] == "block") {
+ $prop[1]->parent = $parentBlock;
+ }
+ }
+
+ // copy mixins into scope, set their parents
+ // bring blocks from import into current block
+ // TODO: need to mark the source parser these came from this file
+ foreach ($root->children as $childName => $child) {
+ if (isset($parentBlock->children[$childName])) {
+ $parentBlock->children[$childName] = array_merge(
+ $parentBlock->children[$childName],
+ $child);
+ } else {
+ $parentBlock->children[$childName] = $child;
+ }
+ }
+
+ $pi = pathinfo($realPath);
+ $dir = $pi["dirname"];
+
+ list($top, $bottom) = $this->sortProps($root->props, true);
+ $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
+
+ return array(true, $bottom, $parser, $dir);
+ }
+
+ protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
+ $oldSourceParser = $this->sourceParser;
+
+ $oldImport = $this->importDir;
+
+ // TODO: this is because the importDir api is stupid
+ $this->importDir = (array)$this->importDir;
+ array_unshift($this->importDir, $importDir);
+
+ foreach ($props as $prop) {
+ $this->compileProp($prop, $block, $out);
+ }
+
+ $this->importDir = $oldImport;
+ $this->sourceParser = $oldSourceParser;
+ }
+
+ /**
+ * Recursively compiles a block.
+ *
+ * A block is analogous to a CSS block in most cases. A single LESS document
+ * is encapsulated in a block when parsed, but it does not have parent tags
+ * so all of it's children appear on the root level when compiled.
+ *
+ * Blocks are made up of props and children.
+ *
+ * Props are property instructions, array tuples which describe an action
+ * to be taken, eg. write a property, set a variable, mixin a block.
+ *
+ * The children of a block are just all the blocks that are defined within.
+ * This is used to look up mixins when performing a mixin.
+ *
+ * Compiling the block involves pushing a fresh environment on the stack,
+ * and iterating through the props, compiling each one.
+ *
+ * See lessc::compileProp()
+ *
+ */
+ protected function compileBlock($block) {
+ switch ($block->type) {
+ case "root":
+ $this->compileRoot($block);
+ break;
+ case null:
+ $this->compileCSSBlock($block);
+ break;
+ case "media":
+ $this->compileMedia($block);
+ break;
+ case "directive":
+ $name = "@" . $block->name;
+ if (!empty($block->value)) {
+ $name .= " " . $this->compileValue($this->reduce($block->value));
+ }
+
+ $this->compileNestedBlock($block, array($name));
+ break;
+ default:
+ $this->throwError("unknown block type: $block->type\n");
+ }
+ }
+
+ protected function compileCSSBlock($block) {
+ $env = $this->pushEnv();
+
+ $selectors = $this->compileSelectors($block->tags);
+ $env->selectors = $this->multiplySelectors($selectors);
+ $out = $this->makeOutputBlock(null, $env->selectors);
+
+ $this->scope->children[] = $out;
+ $this->compileProps($block, $out);
+
+ $block->scope = $env; // mixins carry scope with them!
+ $this->popEnv();
+ }
+
+ protected function compileMedia($media) {
+ $env = $this->pushEnv($media);
+ $parentScope = $this->mediaParent($this->scope);
+
+ $query = $this->compileMediaQuery($this->multiplyMedia($env));
+
+ $this->scope = $this->makeOutputBlock($media->type, array($query));
+ $parentScope->children[] = $this->scope;
+
+ $this->compileProps($media, $this->scope);
+
+ if (count($this->scope->lines) > 0) {
+ $orphanSelelectors = $this->findClosestSelectors();
+ if (!is_null($orphanSelelectors)) {
+ $orphan = $this->makeOutputBlock(null, $orphanSelelectors);
+ $orphan->lines = $this->scope->lines;
+ array_unshift($this->scope->children, $orphan);
+ $this->scope->lines = array();
+ }
+ }
+
+ $this->scope = $this->scope->parent;
+ $this->popEnv();
+ }
+
+ protected function mediaParent($scope) {
+ while (!empty($scope->parent)) {
+ if (!empty($scope->type) && $scope->type != "media") {
+ break;
+ }
+ $scope = $scope->parent;
+ }
+
+ return $scope;
+ }
+
+ protected function compileNestedBlock($block, $selectors) {
+ $this->pushEnv($block);
+ $this->scope = $this->makeOutputBlock($block->type, $selectors);
+ $this->scope->parent->children[] = $this->scope;
+
+ $this->compileProps($block, $this->scope);
+
+ $this->scope = $this->scope->parent;
+ $this->popEnv();
+ }
+
+ protected function compileRoot($root) {
+ $this->pushEnv();
+ $this->scope = $this->makeOutputBlock($root->type);
+ $this->compileProps($root, $this->scope);
+ $this->popEnv();
+ }
+
+ protected function compileProps($block, $out) {
+ foreach ($this->sortProps($block->props) as $prop) {
+ $this->compileProp($prop, $block, $out);
+ }
+ }
+
+ protected function sortProps($props, $split = false) {
+ $vars = array();
+ $imports = array();
+ $other = array();
+
+ foreach ($props as $prop) {
+ switch ($prop[0]) {
+ case "assign":
+ if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
+ $vars[] = $prop;
+ } else {
+ $other[] = $prop;
+ }
+ break;
+ case "import":
+ $id = self::$nextImportId++;
+ $prop[] = $id;
+ $imports[] = $prop;
+ $other[] = array("import_mixin", $id);
+ break;
+ default:
+ $other[] = $prop;
+ }
+ }
+
+ if ($split) {
+ return array(array_merge($vars, $imports), $other);
+ } else {
+ return array_merge($vars, $imports, $other);
+ }
+ }
+
+ protected function compileMediaQuery($queries) {
+ $compiledQueries = array();
+ foreach ($queries as $query) {
+ $parts = array();
+ foreach ($query as $q) {
+ switch ($q[0]) {
+ case "mediaType":
+ $parts[] = implode(" ", array_slice($q, 1));
+ break;
+ case "mediaExp":
+ if (isset($q[2])) {
+ $parts[] = "($q[1]: " .
+ $this->compileValue($this->reduce($q[2])) . ")";
+ } else {
+ $parts[] = "($q[1])";
+ }
+ break;
+ case "variable":
+ $parts[] = $this->compileValue($this->reduce($q));
+ break;
+ }
+ }
+
+ if (count($parts) > 0) {
+ $compiledQueries[] = implode(" and ", $parts);
+ }
+ }
+
+ $out = "@media";
+ if (!empty($parts)) {
+ $out .= " " .
+ implode($this->formatter->selectorSeparator, $compiledQueries);
+ }
+ return $out;
+ }
+
+ protected function multiplyMedia($env, $childQueries = null) {
+ if (is_null($env) ||
+ !empty($env->block->type) && $env->block->type != "media")
+ {
+ return $childQueries;
+ }
+
+ // plain old block, skip
+ if (empty($env->block->type)) {
+ return $this->multiplyMedia($env->parent, $childQueries);
+ }
+
+ $out = array();
+ $queries = $env->block->queries;
+ if (is_null($childQueries)) {
+ $out = $queries;
+ } else {
+ foreach ($queries as $parent) {
+ foreach ($childQueries as $child) {
+ $out[] = array_merge($parent, $child);
+ }
+ }
+ }
+
+ return $this->multiplyMedia($env->parent, $out);
+ }
+
+ protected function expandParentSelectors(&$tag, $replace) {
+ $parts = explode("$&$", $tag);
+ $count = 0;
+ foreach ($parts as &$part) {
+ $part = str_replace($this->parentSelector, $replace, $part, $c);
+ $count += $c;
+ }
+ $tag = implode($this->parentSelector, $parts);
+ return $count;
+ }
+
+ protected function findClosestSelectors() {
+ $env = $this->env;
+ $selectors = null;
+ while ($env !== null) {
+ if (isset($env->selectors)) {
+ $selectors = $env->selectors;
+ break;
+ }
+ $env = $env->parent;
+ }
+
+ return $selectors;
+ }
+
+
+ // multiply $selectors against the nearest selectors in env
+ protected function multiplySelectors($selectors) {
+ // find parent selectors
+
+ $parentSelectors = $this->findClosestSelectors();
+ if (is_null($parentSelectors)) {
+ // kill parent reference in top level selector
+ foreach ($selectors as &$s) {
+ $this->expandParentSelectors($s, "");
+ }
+
+ return $selectors;
+ }
+
+ $out = array();
+ foreach ($parentSelectors as $parent) {
+ foreach ($selectors as $child) {
+ $count = $this->expandParentSelectors($child, $parent);
+
+ // don't prepend the parent tag if & was used
+ if ($count > 0) {
+ $out[] = trim($child);
+ } else {
+ $out[] = trim($parent . ' ' . $child);
+ }
+ }
+ }
+
+ return $out;
+ }
+
+ // reduces selector expressions
+ protected function compileSelectors($selectors) {
+ $out = array();
+
+ foreach ($selectors as $s) {
+ if (is_array($s)) {
+ list(, $value) = $s;
+ $out[] = trim($this->compileValue($this->reduce($value)));
+ } else {
+ $out[] = $s;
+ }
+ }
+
+ return $out;
+ }
+
+ protected function eq($left, $right) {
+ return $left == $right;
+ }
+
+ protected function patternMatch($block, $callingArgs) {
+ // match the guards if it has them
+ // any one of the groups must have all its guards pass for a match
+ if (!empty($block->guards)) {
+ $groupPassed = false;
+ foreach ($block->guards as $guardGroup) {
+ foreach ($guardGroup as $guard) {
+ $this->pushEnv();
+ $this->zipSetArgs($block->args, $callingArgs);
+
+ $negate = false;
+ if ($guard[0] == "negate") {
+ $guard = $guard[1];
+ $negate = true;
+ }
+
+ $passed = $this->reduce($guard) == self::$TRUE;
+ if ($negate) $passed = !$passed;
+
+ $this->popEnv();
+
+ if ($passed) {
+ $groupPassed = true;
+ } else {
+ $groupPassed = false;
+ break;
+ }
+ }
+
+ if ($groupPassed) break;
+ }
+
+ if (!$groupPassed) {
+ return false;
+ }
+ }
+
+ $numCalling = count($callingArgs);
+
+ if (empty($block->args)) {
+ return $block->isVararg || $numCalling == 0;
+ }
+
+ $i = -1; // no args
+ // try to match by arity or by argument literal
+ foreach ($block->args as $i => $arg) {
+ switch ($arg[0]) {
+ case "lit":
+ if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
+ return false;
+ }
+ break;
+ case "arg":
+ // no arg and no default value
+ if (!isset($callingArgs[$i]) && !isset($arg[2])) {
+ return false;
+ }
+ break;
+ case "rest":
+ $i--; // rest can be empty
+ break 2;
+ }
+ }
+
+ if ($block->isVararg) {
+ return true; // not having enough is handled above
+ } else {
+ $numMatched = $i + 1;
+ // greater than becuase default values always match
+ return $numMatched >= $numCalling;
+ }
+ }
+
+ protected function patternMatchAll($blocks, $callingArgs) {
+ $matches = null;
+ foreach ($blocks as $block) {
+ if ($this->patternMatch($block, $callingArgs)) {
+ $matches[] = $block;
+ }
+ }
+
+ return $matches;
+ }
+
+ // attempt to find blocks matched by path and args
+ protected function findBlocks($searchIn, $path, $args, $seen=array()) {
+ if ($searchIn == null) return null;
+ if (isset($seen[$searchIn->id])) return null;
+ $seen[$searchIn->id] = true;
+
+ $name = $path[0];
+
+ if (isset($searchIn->children[$name])) {
+ $blocks = $searchIn->children[$name];
+ if (count($path) == 1) {
+ $matches = $this->patternMatchAll($blocks, $args);
+ if (!empty($matches)) {
+ // This will return all blocks that match in the closest
+ // scope that has any matching block, like lessjs
+ return $matches;
+ }
+ } else {
+ $matches = array();
+ foreach ($blocks as $subBlock) {
+ $subMatches = $this->findBlocks($subBlock,
+ array_slice($path, 1), $args, $seen);
+
+ if (!is_null($subMatches)) {
+ foreach ($subMatches as $sm) {
+ $matches[] = $sm;
+ }
+ }
+ }
+
+ return count($matches) > 0 ? $matches : null;
+ }
+ }
+
+ if ($searchIn->parent === $searchIn) return null;
+ return $this->findBlocks($searchIn->parent, $path, $args, $seen);
+ }
+
+ // sets all argument names in $args to either the default value
+ // or the one passed in through $values
+ protected function zipSetArgs($args, $values) {
+ $i = 0;
+ $assignedValues = array();
+ foreach ($args as $a) {
+ if ($a[0] == "arg") {
+ if ($i < count($values) && !is_null($values[$i])) {
+ $value = $values[$i];
+ } elseif (isset($a[2])) {
+ $value = $a[2];
+ } else $value = null;
+
+ $value = $this->reduce($value);
+ $this->set($a[1], $value);
+ $assignedValues[] = $value;
+ }
+ $i++;
+ }
+
+ // check for a rest
+ $last = end($args);
+ if ($last[0] == "rest") {
+ $rest = array_slice($values, count($args) - 1);
+ $this->set($last[1], $this->reduce(array("list", " ", $rest)));
+ }
+
+ $this->env->arguments = $assignedValues;
+ }
+
+ // compile a prop and update $lines or $blocks appropriately
+ protected function compileProp($prop, $block, $out) {
+ // set error position context
+ $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
+
+ switch ($prop[0]) {
+ case 'assign':
+ list(, $name, $value) = $prop;
+ if ($name[0] == $this->vPrefix) {
+ $this->set($name, $value);
+ } else {
+ $out->lines[] = $this->formatter->property($name,
+ $this->compileValue($this->reduce($value)));
+ }
+ break;
+ case 'block':
+ list(, $child) = $prop;
+ $this->compileBlock($child);
+ break;
+ case 'mixin':
+ list(, $path, $args, $suffix) = $prop;
+
+ $args = array_map(array($this, "reduce"), (array)$args);
+ $mixins = $this->findBlocks($block, $path, $args);
+
+ if ($mixins === null) {
+ // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
+ break; // throw error here??
+ }
+
+ foreach ($mixins as $mixin) {
+ $haveScope = false;
+ if (isset($mixin->parent->scope)) {
+ $haveScope = true;
+ $mixinParentEnv = $this->pushEnv();
+ $mixinParentEnv->storeParent = $mixin->parent->scope;
+ }
+
+ $haveArgs = false;
+ if (isset($mixin->args)) {
+ $haveArgs = true;
+ $this->pushEnv();
+ $this->zipSetArgs($mixin->args, $args);
+ }
+
+ $oldParent = $mixin->parent;
+ if ($mixin != $block) $mixin->parent = $block;
+
+ foreach ($this->sortProps($mixin->props) as $subProp) {
+ if ($suffix !== null &&
+ $subProp[0] == "assign" &&
+ is_string($subProp[1]) &&
+ $subProp[1]{0} != $this->vPrefix)
+ {
+ $subProp[2] = array(
+ 'list', ' ',
+ array($subProp[2], array('keyword', $suffix))
+ );
+ }
+
+ $this->compileProp($subProp, $mixin, $out);
+ }
+
+ $mixin->parent = $oldParent;
+
+ if ($haveArgs) $this->popEnv();
+ if ($haveScope) $this->popEnv();
+ }
+
+ break;
+ case 'raw':
+ $out->lines[] = $prop[1];
+ break;
+ case "directive":
+ list(, $name, $value) = $prop;
+ $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
+ break;
+ case "comment":
+ $out->lines[] = $prop[1];
+ break;
+ case "import";
+ list(, $importPath, $importId) = $prop;
+ $importPath = $this->reduce($importPath);
+
+ if (!isset($this->env->imports)) {
+ $this->env->imports = array();
+ }
+
+ $result = $this->tryImport($importPath, $block, $out);
+
+ $this->env->imports[$importId] = $result === false ?
+ array(false, "@import " . $this->compileValue($importPath).";") :
+ $result;
+
+ break;
+ case "import_mixin":
+ list(,$importId) = $prop;
+ $import = $this->env->imports[$importId];
+ if ($import[0] === false) {
+ $out->lines[] = $import[1];
+ } else {
+ list(, $bottom, $parser, $importDir) = $import;
+ $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
+ }
+
+ break;
+ default:
+ $this->throwError("unknown op: {$prop[0]}\n");
+ }
+ }
+
+
+ /**
+ * Compiles a primitive value into a CSS property value.
+ *
+ * Values in lessphp are typed by being wrapped in arrays, their format is
+ * typically:
+ *
+ * array(type, contents [, additional_contents]*)
+ *
+ * The input is expected to be reduced. This function will not work on
+ * things like expressions and variables.
+ */
+ protected function compileValue($value) {
+ switch ($value[0]) {
+ case 'list':
+ // [1] - delimiter
+ // [2] - array of values
+ return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
+ case 'raw_color':
+ if (!empty($this->formatter->compressColors)) {
+ return $this->compileValue($this->coerceColor($value));
+ }
+ return $value[1];
+ case 'keyword':
+ // [1] - the keyword
+ return $value[1];
+ case 'number':
+ list(, $num, $unit) = $value;
+ // [1] - the number
+ // [2] - the unit
+ if ($this->numberPrecision !== null) {
+ $num = round($num, $this->numberPrecision);
+ }
+ return $num . $unit;
+ case 'string':
+ // [1] - contents of string (includes quotes)
+ list(, $delim, $content) = $value;
+ foreach ($content as &$part) {
+ if (is_array($part)) {
+ $part = $this->compileValue($part);
+ }
+ }
+ return $delim . implode($content) . $delim;
+ case 'color':
+ // [1] - red component (either number or a %)
+ // [2] - green component
+ // [3] - blue component
+ // [4] - optional alpha component
+ list(, $r, $g, $b) = $value;
+ $r = round($r);
+ $g = round($g);
+ $b = round($b);
+
+ if (count($value) == 5 && $value[4] != 1) { // rgba
+ return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
+ }
+
+ $h = sprintf("#%02x%02x%02x", $r, $g, $b);
+
+ if (!empty($this->formatter->compressColors)) {
+ // Converting hex color to short notation (e.g. #003399 to #039)
+ if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
+ $h = '#' . $h[1] . $h[3] . $h[5];
+ }
+ }
+
+ return $h;
+
+ case 'function':
+ list(, $name, $args) = $value;
+ return $name.'('.$this->compileValue($args).')';
+ default: // assumed to be unit
+ $this->throwError("unknown value type: $value[0]");
+ }
+ }
+
+ protected function lib_isnumber($value) {
+ return $this->toBool($value[0] == "number");
+ }
+
+ protected function lib_isstring($value) {
+ return $this->toBool($value[0] == "string");
+ }
+
+ protected function lib_iscolor($value) {
+ return $this->toBool($this->coerceColor($value));
+ }
+
+ protected function lib_iskeyword($value) {
+ return $this->toBool($value[0] == "keyword");
+ }
+
+ protected function lib_ispixel($value) {
+ return $this->toBool($value[0] == "number" && $value[2] == "px");
+ }
+
+ protected function lib_ispercentage($value) {
+ return $this->toBool($value[0] == "number" && $value[2] == "%");
+ }
+
+ protected function lib_isem($value) {
+ return $this->toBool($value[0] == "number" && $value[2] == "em");
+ }
+
+ protected function lib_isrem($value) {
+ return $this->toBool($value[0] == "number" && $value[2] == "rem");
+ }
+
+ protected function lib_rgbahex($color) {
+ $color = $this->coerceColor($color);
+ if (is_null($color))
+ $this->throwError("color expected for rgbahex");
+
+ return sprintf("#%02x%02x%02x%02x",
+ isset($color[4]) ? $color[4]*255 : 255,
+ $color[1],$color[2], $color[3]);
+ }
+
+ protected function lib_argb($color){
+ return $this->lib_rgbahex($color);
+ }
+
+ // utility func to unquote a string
+ protected function lib_e($arg) {
+ switch ($arg[0]) {
+ case "list":
+ $items = $arg[2];
+ if (isset($items[0])) {
+ return $this->lib_e($items[0]);
+ }
+ return self::$defaultValue;
+ case "string":
+ $arg[1] = "";
+ return $arg;
+ case "keyword":
+ return $arg;
+ default:
+ return array("keyword", $this->compileValue($arg));
+ }
+ }
+
+ protected function lib__sprintf($args) {
+ if ($args[0] != "list") return $args;
+ $values = $args[2];
+ $string = array_shift($values);
+ $template = $this->compileValue($this->lib_e($string));
+
+ $i = 0;
+ if (preg_match_all('/%[dsa]/', $template, $m)) {
+ foreach ($m[0] as $match) {
+ $val = isset($values[$i]) ?
+ $this->reduce($values[$i]) : array('keyword', '');
+
+ // lessjs compat, renders fully expanded color, not raw color
+ if ($color = $this->coerceColor($val)) {
+ $val = $color;
+ }
+
+ $i++;
+ $rep = $this->compileValue($this->lib_e($val));
+ $template = preg_replace('/'.self::preg_quote($match).'/',
+ $rep, $template, 1);
+ }
+ }
+
+ $d = $string[0] == "string" ? $string[1] : '"';
+ return array("string", $d, array($template));
+ }
+
+ protected function lib_floor($arg) {
+ $value = $this->assertNumber($arg);
+ return array("number", floor($value), $arg[2]);
+ }
+
+ protected function lib_ceil($arg) {
+ $value = $this->assertNumber($arg);
+ return array("number", ceil($value), $arg[2]);
+ }
+
+ protected function lib_round($arg) {
+ $value = $this->assertNumber($arg);
+ return array("number", round($value), $arg[2]);
+ }
+
+ protected function lib_unit($arg) {
+ if ($arg[0] == "list") {
+ list($number, $newUnit) = $arg[2];
+ return array("number", $this->assertNumber($number),
+ $this->compileValue($this->lib_e($newUnit)));
+ } else {
+ return array("number", $this->assertNumber($arg), "");
+ }
+ }
+
+ /**
+ * Helper function to get arguments for color manipulation functions.
+ * takes a list that contains a color like thing and a percentage
+ */
+ protected function colorArgs($args) {
+ if ($args[0] != 'list' || count($args[2]) < 2) {
+ return array(array('color', 0, 0, 0), 0);
+ }
+ list($color, $delta) = $args[2];
+ $color = $this->assertColor($color);
+ $delta = floatval($delta[1]);
+
+ return array($color, $delta);
+ }
+
+ protected function lib_darken($args) {
+ list($color, $delta) = $this->colorArgs($args);
+
+ $hsl = $this->toHSL($color);
+ $hsl[3] = $this->clamp($hsl[3] - $delta, 100);
+ return $this->toRGB($hsl);
+ }
+
+ protected function lib_lighten($args) {
+ list($color, $delta) = $this->colorArgs($args);
+
+ $hsl = $this->toHSL($color);
+ $hsl[3] = $this->clamp($hsl[3] + $delta, 100);
+ return $this->toRGB($hsl);
+ }
+
+ protected function lib_saturate($args) {
+ list($color, $delta) = $this->colorArgs($args);
+
+ $hsl = $this->toHSL($color);
+ $hsl[2] = $this->clamp($hsl[2] + $delta, 100);
+ return $this->toRGB($hsl);
+ }
+
+ protected function lib_desaturate($args) {
+ list($color, $delta) = $this->colorArgs($args);
+
+ $hsl = $this->toHSL($color);
+ $hsl[2] = $this->clamp($hsl[2] - $delta, 100);
+ return $this->toRGB($hsl);
+ }
+
+ protected function lib_spin($args) {
+ list($color, $delta) = $this->colorArgs($args);
+
+ $hsl = $this->toHSL($color);
+
+ $hsl[1] = $hsl[1] + $delta % 360;
+ if ($hsl[1] < 0) $hsl[1] += 360;
+
+ return $this->toRGB($hsl);
+ }
+
+ protected function lib_fadeout($args) {
+ list($color, $delta) = $this->colorArgs($args);
+ $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
+ return $color;
+ }
+
+ protected function lib_fadein($args) {
+ list($color, $delta) = $this->colorArgs($args);
+ $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
+ return $color;
+ }
+
+ protected function lib_hue($color) {
+ $hsl = $this->toHSL($this->assertColor($color));
+ return round($hsl[1]);
+ }
+
+ protected function lib_saturation($color) {
+ $hsl = $this->toHSL($this->assertColor($color));
+ return round($hsl[2]);
+ }
+
+ protected function lib_lightness($color) {
+ $hsl = $this->toHSL($this->assertColor($color));
+ return round($hsl[3]);
+ }
+
+ // get the alpha of a color
+ // defaults to 1 for non-colors or colors without an alpha
+ protected function lib_alpha($value) {
+ if (!is_null($color = $this->coerceColor($value))) {
+ return isset($color[4]) ? $color[4] : 1;
+ }
+ }
+
+ // set the alpha of the color
+ protected function lib_fade($args) {
+ list($color, $alpha) = $this->colorArgs($args);
+ $color[4] = $this->clamp($alpha / 100.0);
+ return $color;
+ }
+
+ protected function lib_percentage($arg) {
+ $num = $this->assertNumber($arg);
+ return array("number", $num*100, "%");
+ }
+
+ // mixes two colors by weight
+ // mix(@color1, @color2, @weight);
+ // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
+ protected function lib_mix($args) {
+ if ($args[0] != "list" || count($args[2]) < 3)
+ $this->throwError("mix expects (color1, color2, weight)");
+
+ list($first, $second, $weight) = $args[2];
+ $first = $this->assertColor($first);
+ $second = $this->assertColor($second);
+
+ $first_a = $this->lib_alpha($first);
+ $second_a = $this->lib_alpha($second);
+ $weight = $weight[1] / 100.0;
+
+ $w = $weight * 2 - 1;
+ $a = $first_a - $second_a;
+
+ $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
+ $w2 = 1.0 - $w1;
+
+ $new = array('color',
+ $w1 * $first[1] + $w2 * $second[1],
+ $w1 * $first[2] + $w2 * $second[2],
+ $w1 * $first[3] + $w2 * $second[3],
+ );
+
+ if ($first_a != 1.0 || $second_a != 1.0) {
+ $new[] = $first_a * $weight + $second_a * ($weight - 1);
+ }
+
+ return $this->fixColor($new);
+ }
+
+ protected function lib_contrast($args) {
+ if ($args[0] != 'list' || count($args[2]) < 3) {
+ return array(array('color', 0, 0, 0), 0);
+ }
+
+ list($inputColor, $darkColor, $lightColor) = $args[2];
+
+ $inputColor = $this->assertColor($inputColor);
+ $darkColor = $this->assertColor($darkColor);
+ $lightColor = $this->assertColor($lightColor);
+ $hsl = $this->toHSL($inputColor);
+
+ if ($hsl[3] > 50) {
+ return $darkColor;
+ }
+
+ return $lightColor;
+ }
+
+ protected function assertColor($value, $error = "expected color value") {
+ $color = $this->coerceColor($value);
+ if (is_null($color)) $this->throwError($error);
+ return $color;
+ }
+
+ protected function assertNumber($value, $error = "expecting number") {
+ if ($value[0] == "number") return $value[1];
+ $this->throwError($error);
+ }
+
+ protected function toHSL($color) {
+ if ($color[0] == 'hsl') return $color;
+
+ $r = $color[1] / 255;
+ $g = $color[2] / 255;
+ $b = $color[3] / 255;
+
+ $min = min($r, $g, $b);
+ $max = max($r, $g, $b);
+
+ $L = ($min + $max) / 2;
+ if ($min == $max) {
+ $S = $H = 0;
+ } else {
+ if ($L < 0.5)
+ $S = ($max - $min)/($max + $min);
+ else
+ $S = ($max - $min)/(2.0 - $max - $min);
+
+ if ($r == $max) $H = ($g - $b)/($max - $min);
+ elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
+ elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
+
+ }
+
+ $out = array('hsl',
+ ($H < 0 ? $H + 6 : $H)*60,
+ $S*100,
+ $L*100,
+ );
+
+ if (count($color) > 4) $out[] = $color[4]; // copy alpha
+ return $out;
+ }
+
+ protected function toRGB_helper($comp, $temp1, $temp2) {
+ if ($comp < 0) $comp += 1.0;
+ elseif ($comp > 1) $comp -= 1.0;
+
+ if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
+ if (2 * $comp < 1) return $temp2;
+ if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
+
+ return $temp1;
+ }
+
+ /**
+ * Converts a hsl array into a color value in rgb.
+ * Expects H to be in range of 0 to 360, S and L in 0 to 100
+ */
+ protected function toRGB($color) {
+ if ($color[0] == 'color') return $color;
+
+ $H = $color[1] / 360;
+ $S = $color[2] / 100;
+ $L = $color[3] / 100;
+
+ if ($S == 0) {
+ $r = $g = $b = $L;
+ } else {
+ $temp2 = $L < 0.5 ?
+ $L*(1.0 + $S) :
+ $L + $S - $L * $S;
+
+ $temp1 = 2.0 * $L - $temp2;
+
+ $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
+ $g = $this->toRGB_helper($H, $temp1, $temp2);
+ $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
+ }
+
+ // $out = array('color', round($r*255), round($g*255), round($b*255));
+ $out = array('color', $r*255, $g*255, $b*255);
+ if (count($color) > 4) $out[] = $color[4]; // copy alpha
+ return $out;
+ }
+
+ protected function clamp($v, $max = 1, $min = 0) {
+ return min($max, max($min, $v));
+ }
+
+ /**
+ * Convert the rgb, rgba, hsl color literals of function type
+ * as returned by the parser into values of color type.
+ */
+ protected function funcToColor($func) {
+ $fname = $func[1];
+ if ($func[2][0] != 'list') return false; // need a list of arguments
+ $rawComponents = $func[2][2];
+
+ if ($fname == 'hsl' || $fname == 'hsla') {
+ $hsl = array('hsl');
+ $i = 0;
+ foreach ($rawComponents as $c) {
+ $val = $this->reduce($c);
+ $val = isset($val[1]) ? floatval($val[1]) : 0;
+
+ if ($i == 0) $clamp = 360;
+ elseif ($i < 3) $clamp = 100;
+ else $clamp = 1;
+
+ $hsl[] = $this->clamp($val, $clamp);
+ $i++;
+ }
+
+ while (count($hsl) < 4) $hsl[] = 0;
+ return $this->toRGB($hsl);
+
+ } elseif ($fname == 'rgb' || $fname == 'rgba') {
+ $components = array();
+ $i = 1;
+ foreach ($rawComponents as $c) {
+ $c = $this->reduce($c);
+ if ($i < 4) {
+ if ($c[0] == "number" && $c[2] == "%") {
+ $components[] = 255 * ($c[1] / 100);
+ } else {
+ $components[] = floatval($c[1]);
+ }
+ } elseif ($i == 4) {
+ if ($c[0] == "number" && $c[2] == "%") {
+ $components[] = 1.0 * ($c[1] / 100);
+ } else {
+ $components[] = floatval($c[1]);
+ }
+ } else break;
+
+ $i++;
+ }
+ while (count($components) < 3) $components[] = 0;
+ array_unshift($components, 'color');
+ return $this->fixColor($components);
+ }
+
+ return false;
+ }
+
+ protected function reduce($value, $forExpression = false) {
+ switch ($value[0]) {
+ case "interpolate":
+ $reduced = $this->reduce($value[1]);
+ $var = $this->compileValue($reduced);
+ $res = $this->reduce(array("variable", $this->vPrefix . $var));
+
+ if (empty($value[2])) $res = $this->lib_e($res);
+
+ return $res;
+ case "variable":
+ $key = $value[1];
+ if (is_array($key)) {
+ $key = $this->reduce($key);
+ $key = $this->vPrefix . $this->compileValue($this->lib_e($key));
+ }
+
+ $seen =& $this->env->seenNames;
+
+ if (!empty($seen[$key])) {
+ $this->throwError("infinite loop detected: $key");
+ }
+
+ $seen[$key] = true;
+ $out = $this->reduce($this->get($key, self::$defaultValue));
+ $seen[$key] = false;
+ return $out;
+ case "list":
+ foreach ($value[2] as &$item) {
+ $item = $this->reduce($item, $forExpression);
+ }
+ return $value;
+ case "expression":
+ return $this->evaluate($value);
+ case "string":
+ foreach ($value[2] as &$part) {
+ if (is_array($part)) {
+ $strip = $part[0] == "variable";
+ $part = $this->reduce($part);
+ if ($strip) $part = $this->lib_e($part);
+ }
+ }
+ return $value;
+ case "escape":
+ list(,$inner) = $value;
+ return $this->lib_e($this->reduce($inner));
+ case "function":
+ $color = $this->funcToColor($value);
+ if ($color) return $color;
+
+ list(, $name, $args) = $value;
+ if ($name == "%") $name = "_sprintf";
+ $f = isset($this->libFunctions[$name]) ?
+ $this->libFunctions[$name] : array($this, 'lib_'.$name);
+
+ if (is_callable($f)) {
+ if ($args[0] == 'list')
+ $args = self::compressList($args[2], $args[1]);
+
+ $ret = call_user_func($f, $this->reduce($args, true), $this);
+
+ if (is_null($ret)) {
+ return array("string", "", array(
+ $name, "(", $args, ")"
+ ));
+ }
+
+ // convert to a typed value if the result is a php primitive
+ if (is_numeric($ret)) $ret = array('number', $ret, "");
+ elseif (!is_array($ret)) $ret = array('keyword', $ret);
+
+ return $ret;
+ }
+
+ // plain function, reduce args
+ $value[2] = $this->reduce($value[2]);
+ return $value;
+ case "unary":
+ list(, $op, $exp) = $value;
+ $exp = $this->reduce($exp);
+
+ if ($exp[0] == "number") {
+ switch ($op) {
+ case "+":
+ return $exp;
+ case "-":
+ $exp[1] *= -1;
+ return $exp;
+ }
+ }
+ return array("string", "", array($op, $exp));
+ }
+
+ if ($forExpression) {
+ switch ($value[0]) {
+ case "keyword":
+ if ($color = $this->coerceColor($value)) {
+ return $color;
+ }
+ break;
+ case "raw_color":
+ return $this->coerceColor($value);
+ }
+ }
+
+ return $value;
+ }
+
+
+ // coerce a value for use in color operation
+ protected function coerceColor($value) {
+ switch($value[0]) {
+ case 'color': return $value;
+ case 'raw_color':
+ $c = array("color", 0, 0, 0);
+ $colorStr = substr($value[1], 1);
+ $num = hexdec($colorStr);
+ $width = strlen($colorStr) == 3 ? 16 : 256;
+
+ for ($i = 3; $i > 0; $i--) { // 3 2 1
+ $t = $num % $width;
+ $num /= $width;
+
+ $c[$i] = $t * (256/$width) + $t * floor(16/$width);
+ }
+
+ return $c;
+ case 'keyword':
+ $name = $value[1];
+ if (isset(self::$cssColors[$name])) {
+ $rgba = explode(',', self::$cssColors[$name]);
+
+ if(isset($rgba[3]))
+ return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
+
+ return array('color', $rgba[0], $rgba[1], $rgba[2]);
+ }
+ return null;
+ }
+ }
+
+ // make something string like into a string
+ protected function coerceString($value) {
+ switch ($value[0]) {
+ case "string":
+ return $value;
+ case "keyword":
+ return array("string", "", array($value[1]));
+ }
+ return null;
+ }
+
+ // turn list of length 1 into value type
+ protected function flattenList($value) {
+ if ($value[0] == "list" && count($value[2]) == 1) {
+ return $this->flattenList($value[2][0]);
+ }
+ return $value;
+ }
+
+ protected function toBool($a) {
+ if ($a) return self::$TRUE;
+ else return self::$FALSE;
+ }
+
+ // evaluate an expression
+ protected function evaluate($exp) {
+ list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
+
+ $left = $this->reduce($left, true);
+ $right = $this->reduce($right, true);
+
+ if ($leftColor = $this->coerceColor($left)) {
+ $left = $leftColor;
+ }
+
+ if ($rightColor = $this->coerceColor($right)) {
+ $right = $rightColor;
+ }
+
+ $ltype = $left[0];
+ $rtype = $right[0];
+
+ // operators that work on all types
+ if ($op == "and") {
+ return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
+ }
+
+ if ($op == "=") {
+ return $this->toBool($this->eq($left, $right) );
+ }
+
+ if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
+ return $str;
+ }
+
+ // type based operators
+ $fname = "op_${ltype}_${rtype}";
+ if (is_callable(array($this, $fname))) {
+ $out = $this->$fname($op, $left, $right);
+ if (!is_null($out)) return $out;
+ }
+
+ // make the expression look it did before being parsed
+ $paddedOp = $op;
+ if ($whiteBefore) $paddedOp = " " . $paddedOp;
+ if ($whiteAfter) $paddedOp .= " ";
+
+ return array("string", "", array($left, $paddedOp, $right));
+ }
+
+ protected function stringConcatenate($left, $right) {
+ if ($strLeft = $this->coerceString($left)) {
+ if ($right[0] == "string") {
+ $right[1] = "";
+ }
+ $strLeft[2][] = $right;
+ return $strLeft;
+ }
+
+ if ($strRight = $this->coerceString($right)) {
+ array_unshift($strRight[2], $left);
+ return $strRight;
+ }
+ }
+
+
+ // make sure a color's components don't go out of bounds
+ protected function fixColor($c) {
+ foreach (range(1, 3) as $i) {
+ if ($c[$i] < 0) $c[$i] = 0;
+ if ($c[$i] > 255) $c[$i] = 255;
+ }
+
+ return $c;
+ }
+
+ protected function op_number_color($op, $lft, $rgt) {
+ if ($op == '+' || $op == '*') {
+ return $this->op_color_number($op, $rgt, $lft);
+ }
+ }
+
+ protected function op_color_number($op, $lft, $rgt) {
+ if ($rgt[0] == '%') $rgt[1] /= 100;
+
+ return $this->op_color_color($op, $lft,
+ array_fill(1, count($lft) - 1, $rgt[1]));
+ }
+
+ protected function op_color_color($op, $left, $right) {
+ $out = array('color');
+ $max = count($left) > count($right) ? count($left) : count($right);
+ foreach (range(1, $max - 1) as $i) {
+ $lval = isset($left[$i]) ? $left[$i] : 0;
+ $rval = isset($right[$i]) ? $right[$i] : 0;
+ switch ($op) {
+ case '+':
+ $out[] = $lval + $rval;
+ break;
+ case '-':
+ $out[] = $lval - $rval;
+ break;
+ case '*':
+ $out[] = $lval * $rval;
+ break;
+ case '%':
+ $out[] = $lval % $rval;
+ break;
+ case '/':
+ if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
+ $out[] = $lval / $rval;
+ break;
+ default:
+ $this->throwError('evaluate error: color op number failed on op '.$op);
+ }
+ }
+ return $this->fixColor($out);
+ }
+
+ function lib_red($color){
+ $color = $this->coerceColor($color);
+ if (is_null($color)) {
+ $this->throwError('color expected for red()');
+ }
+
+ return $color[1];
+ }
+
+ function lib_green($color){
+ $color = $this->coerceColor($color);
+ if (is_null($color)) {
+ $this->throwError('color expected for green()');
+ }
+
+ return $color[2];
+ }
+
+ function lib_blue($color){
+ $color = $this->coerceColor($color);
+ if (is_null($color)) {
+ $this->throwError('color expected for blue()');
+ }
+
+ return $color[3];
+ }
+
+
+ // operator on two numbers
+ protected function op_number_number($op, $left, $right) {
+ $unit = empty($left[2]) ? $right[2] : $left[2];
+
+ $value = 0;
+ switch ($op) {
+ case '+':
+ $value = $left[1] + $right[1];
+ break;
+ case '*':
+ $value = $left[1] * $right[1];
+ break;
+ case '-':
+ $value = $left[1] - $right[1];
+ break;
+ case '%':
+ $value = $left[1] % $right[1];
+ break;
+ case '/':
+ if ($right[1] == 0) $this->throwError('parse error: divide by zero');
+ $value = $left[1] / $right[1];
+ break;
+ case '<':
+ return $this->toBool($left[1] < $right[1]);
+ case '>':
+ return $this->toBool($left[1] > $right[1]);
+ case '>=':
+ return $this->toBool($left[1] >= $right[1]);
+ case '=<':
+ return $this->toBool($left[1] <= $right[1]);
+ default:
+ $this->throwError('parse error: unknown number operator: '.$op);
+ }
+
+ return array("number", $value, $unit);
+ }
+
+
+ /* environment functions */
+
+ protected function makeOutputBlock($type, $selectors = null) {
+ $b = new stdclass;
+ $b->lines = array();
+ $b->children = array();
+ $b->selectors = $selectors;
+ $b->type = $type;
+ $b->parent = $this->scope;
+ return $b;
+ }
+
+ // the state of execution
+ protected function pushEnv($block = null) {
+ $e = new stdclass;
+ $e->parent = $this->env;
+ $e->store = array();
+ $e->block = $block;
+
+ $this->env = $e;
+ return $e;
+ }
+
+ // pop something off the stack
+ protected function popEnv() {
+ $old = $this->env;
+ $this->env = $this->env->parent;
+ return $old;
+ }
+
+ // set something in the current env
+ protected function set($name, $value) {
+ $this->env->store[$name] = $value;
+ }
+
+
+ // get the highest occurrence entry for a name
+ protected function get($name, $default=null) {
+ $current = $this->env;
+
+ $isArguments = $name == $this->vPrefix . 'arguments';
+ while ($current) {
+ if ($isArguments && isset($current->arguments)) {
+ return array('list', ' ', $current->arguments);
+ }
+
+ if (isset($current->store[$name]))
+ return $current->store[$name];
+ else {
+ $current = isset($current->storeParent) ?
+ $current->storeParent : $current->parent;
+ }
+ }
+
+ return $default;
+ }
+
+ // inject array of unparsed strings into environment as variables
+ protected function injectVariables($args) {
+ $this->pushEnv();
+ $parser = new lessc_parser($this, __METHOD__);
+ foreach ($args as $name => $strValue) {
+ if ($name{0} != '@') $name = '@'.$name;
+ $parser->count = 0;
+ $parser->buffer = (string)$strValue;
+ if (!$parser->propertyValue($value)) {
+ throw new Exception("failed to parse passed in variable $name: $strValue");
+ }
+
+ $this->set($name, $value);
+ }
+ }
+
+ /**
+ * Initialize any static state, can initialize parser for a file
+ * $opts isn't used yet
+ */
+ public function __construct($fname = null) {
+ if ($fname !== null) {
+ // used for deprecated parse method
+ $this->_parseFile = $fname;
+ }
+ }
+
+ public function compile($string, $name = null) {
+ $locale = setlocale(LC_NUMERIC, 0);
+ setlocale(LC_NUMERIC, "C");
+
+ $this->parser = $this->makeParser($name);
+ $root = $this->parser->parse($string);
+
+ $this->env = null;
+ $this->scope = null;
+
+ $this->formatter = $this->newFormatter();
+
+ if (!empty($this->registeredVars)) {
+ $this->injectVariables($this->registeredVars);
+ }
+
+ $this->sourceParser = $this->parser; // used for error messages
+ $this->compileBlock($root);
+
+ ob_start();
+ $this->formatter->block($this->scope);
+ $out = ob_get_clean();
+ setlocale(LC_NUMERIC, $locale);
+ return $out;
+ }
+
+ public function compileFile($fname, $outFname = null) {
+ if (!is_readable($fname)) {
+ throw new Exception('load error: failed to find '.$fname);
+ }
+
+ $pi = pathinfo($fname);
+
+ $oldImport = $this->importDir;
+
+ $this->importDir = (array)$this->importDir;
+ $this->importDir[] = $pi['dirname'].'/';
+
+ $this->allParsedFiles = array();
+ $this->addParsedFile($fname);
+
+ $out = $this->compile(file_get_contents($fname), $fname);
+
+ $this->importDir = $oldImport;
+
+ if ($outFname !== null) {
+ return file_put_contents($outFname, $out);
+ }
+
+ return $out;
+ }
+
+ // compile only if changed input has changed or output doesn't exist
+ public function checkedCompile($in, $out) {
+ if (!is_file($out) || filemtime($in) > filemtime($out)) {
+ $this->compileFile($in, $out);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Execute lessphp on a .less file or a lessphp cache structure
+ *
+ * The lessphp cache structure contains information about a specific
+ * less file having been parsed. It can be used as a hint for future
+ * calls to determine whether or not a rebuild is required.
+ *
+ * The cache structure contains two important keys that may be used
+ * externally:
+ *
+ * compiled: The final compiled CSS
+ * updated: The time (in seconds) the CSS was last compiled
+ *
+ * The cache structure is a plain-ol' PHP associative array and can
+ * be serialized and unserialized without a hitch.
+ *
+ * @param mixed $in Input
+ * @param bool $force Force rebuild?
+ * @return array lessphp cache structure
+ */
+ public function cachedCompile($in, $force = false) {
+ // assume no root
+ $root = null;
+
+ if (is_string($in)) {
+ $root = $in;
+ } elseif (is_array($in) and isset($in['root'])) {
+ if ($force or ! isset($in['files'])) {
+ // If we are forcing a recompile or if for some reason the
+ // structure does not contain any file information we should
+ // specify the root to trigger a rebuild.
+ $root = $in['root'];
+ } elseif (isset($in['files']) and is_array($in['files'])) {
+ foreach ($in['files'] as $fname => $ftime ) {
+ if (!file_exists($fname) or filemtime($fname) > $ftime) {
+ // One of the files we knew about previously has changed
+ // so we should look at our incoming root again.
+ $root = $in['root'];
+ break;
+ }
+ }
+ }
+ } else {
+ // TODO: Throw an exception? We got neither a string nor something
+ // that looks like a compatible lessphp cache structure.
+ return null;
+ }
+
+ if ($root !== null) {
+ // If we have a root value which means we should rebuild.
+ $out = array();
+ $out['root'] = $root;
+ $out['compiled'] = $this->compileFile($root);
+ $out['files'] = $this->allParsedFiles();
+ $out['updated'] = time();
+ return $out;
+ } else {
+ // No changes, pass back the structure
+ // we were given initially.
+ return $in;
+ }
+
+ }
+
+ // parse and compile buffer
+ // This is deprecated
+ public function parse($str = null, $initialVariables = null) {
+ if (is_array($str)) {
+ $initialVariables = $str;
+ $str = null;
+ }
+
+ $oldVars = $this->registeredVars;
+ if ($initialVariables !== null) {
+ $this->setVariables($initialVariables);
+ }
+
+ if ($str == null) {
+ if (empty($this->_parseFile)) {
+ throw new exception("nothing to parse");
+ }
+
+ $out = $this->compileFile($this->_parseFile);
+ } else {
+ $out = $this->compile($str);
+ }
+
+ $this->registeredVars = $oldVars;
+ return $out;
+ }
+
+ protected function makeParser($name) {
+ $parser = new lessc_parser($this, $name);
+ $parser->writeComments = $this->preserveComments;
+
+ return $parser;
+ }
+
+ public function setFormatter($name) {
+ $this->formatterName = $name;
+ }
+
+ protected function newFormatter() {
+ $className = "lessc_formatter_lessjs";
+ if (!empty($this->formatterName)) {
+ if (!is_string($this->formatterName))
+ return $this->formatterName;
+ $className = "lessc_formatter_$this->formatterName";
+ }
+
+ return new $className;
+ }
+
+ public function setPreserveComments($preserve) {
+ $this->preserveComments = $preserve;
+ }
+
+ public function registerFunction($name, $func) {
+ $this->libFunctions[$name] = $func;
+ }
+
+ public function unregisterFunction($name) {
+ unset($this->libFunctions[$name]);
+ }
+
+ public function setVariables($variables) {
+ $this->registeredVars = array_merge($this->registeredVars, $variables);
+ }
+
+ public function unsetVariable($name) {
+ unset($this->registeredVars[$name]);
+ }
+
+ public function setImportDir($dirs) {
+ $this->importDir = (array)$dirs;
+ }
+
+ public function addImportDir($dir) {
+ $this->importDir = (array)$this->importDir;
+ $this->importDir[] = $dir;
+ }
+
+ public function allParsedFiles() {
+ return $this->allParsedFiles;
+ }
+
+ protected function addParsedFile($file) {
+ $this->allParsedFiles[realpath($file)] = filemtime($file);
+ }
+
+ /**
+ * Uses the current value of $this->count to show line and line number
+ */
+ protected function throwError($msg = null) {
+ if ($this->sourceLoc >= 0) {
+ $this->sourceParser->throwError($msg, $this->sourceLoc);
+ }
+ throw new exception($msg);
+ }
+
+ // compile file $in to file $out if $in is newer than $out
+ // returns true when it compiles, false otherwise
+ public static function ccompile($in, $out, $less = null) {
+ if ($less === null) {
+ $less = new self;
+ }
+ return $less->checkedCompile($in, $out);
+ }
+
+ public static function cexecute($in, $force = false, $less = null) {
+ if ($less === null) {
+ $less = new self;
+ }
+ return $less->cachedCompile($in, $force);
+ }
+
+ static protected $cssColors = array(
+ 'aliceblue' => '240,248,255',
+ 'antiquewhite' => '250,235,215',
+ 'aqua' => '0,255,255',
+ 'aquamarine' => '127,255,212',
+ 'azure' => '240,255,255',
+ 'beige' => '245,245,220',
+ 'bisque' => '255,228,196',
+ 'black' => '0,0,0',
+ 'blanchedalmond' => '255,235,205',
+ 'blue' => '0,0,255',
+ 'blueviolet' => '138,43,226',
+ 'brown' => '165,42,42',
+ 'burlywood' => '222,184,135',
+ 'cadetblue' => '95,158,160',
+ 'chartreuse' => '127,255,0',
+ 'chocolate' => '210,105,30',
+ 'coral' => '255,127,80',
+ 'cornflowerblue' => '100,149,237',
+ 'cornsilk' => '255,248,220',
+ 'crimson' => '220,20,60',
+ 'cyan' => '0,255,255',
+ 'darkblue' => '0,0,139',
+ 'darkcyan' => '0,139,139',
+ 'darkgoldenrod' => '184,134,11',
+ 'darkgray' => '169,169,169',
+ 'darkgreen' => '0,100,0',
+ 'darkgrey' => '169,169,169',
+ 'darkkhaki' => '189,183,107',
+ 'darkmagenta' => '139,0,139',
+ 'darkolivegreen' => '85,107,47',
+ 'darkorange' => '255,140,0',
+ 'darkorchid' => '153,50,204',
+ 'darkred' => '139,0,0',
+ 'darksalmon' => '233,150,122',
+ 'darkseagreen' => '143,188,143',
+ 'darkslateblue' => '72,61,139',
+ 'darkslategray' => '47,79,79',
+ 'darkslategrey' => '47,79,79',
+ 'darkturquoise' => '0,206,209',
+ 'darkviolet' => '148,0,211',
+ 'deeppink' => '255,20,147',
+ 'deepskyblue' => '0,191,255',
+ 'dimgray' => '105,105,105',
+ 'dimgrey' => '105,105,105',
+ 'dodgerblue' => '30,144,255',
+ 'firebrick' => '178,34,34',
+ 'floralwhite' => '255,250,240',
+ 'forestgreen' => '34,139,34',
+ 'fuchsia' => '255,0,255',
+ 'gainsboro' => '220,220,220',
+ 'ghostwhite' => '248,248,255',
+ 'gold' => '255,215,0',
+ 'goldenrod' => '218,165,32',
+ 'gray' => '128,128,128',
+ 'green' => '0,128,0',
+ 'greenyellow' => '173,255,47',
+ 'grey' => '128,128,128',
+ 'honeydew' => '240,255,240',
+ 'hotpink' => '255,105,180',
+ 'indianred' => '205,92,92',
+ 'indigo' => '75,0,130',
+ 'ivory' => '255,255,240',
+ 'khaki' => '240,230,140',
+ 'lavender' => '230,230,250',
+ 'lavenderblush' => '255,240,245',
+ 'lawngreen' => '124,252,0',
+ 'lemonchiffon' => '255,250,205',
+ 'lightblue' => '173,216,230',
+ 'lightcoral' => '240,128,128',
+ 'lightcyan' => '224,255,255',
+ 'lightgoldenrodyellow' => '250,250,210',
+ 'lightgray' => '211,211,211',
+ 'lightgreen' => '144,238,144',
+ 'lightgrey' => '211,211,211',
+ 'lightpink' => '255,182,193',
+ 'lightsalmon' => '255,160,122',
+ 'lightseagreen' => '32,178,170',
+ 'lightskyblue' => '135,206,250',
+ 'lightslategray' => '119,136,153',
+ 'lightslategrey' => '119,136,153',
+ 'lightsteelblue' => '176,196,222',
+ 'lightyellow' => '255,255,224',
+ 'lime' => '0,255,0',
+ 'limegreen' => '50,205,50',
+ 'linen' => '250,240,230',
+ 'magenta' => '255,0,255',
+ 'maroon' => '128,0,0',
+ 'mediumaquamarine' => '102,205,170',
+ 'mediumblue' => '0,0,205',
+ 'mediumorchid' => '186,85,211',
+ 'mediumpurple' => '147,112,219',
+ 'mediumseagreen' => '60,179,113',
+ 'mediumslateblue' => '123,104,238',
+ 'mediumspringgreen' => '0,250,154',
+ 'mediumturquoise' => '72,209,204',
+ 'mediumvioletred' => '199,21,133',
+ 'midnightblue' => '25,25,112',
+ 'mintcream' => '245,255,250',
+ 'mistyrose' => '255,228,225',
+ 'moccasin' => '255,228,181',
+ 'navajowhite' => '255,222,173',
+ 'navy' => '0,0,128',
+ 'oldlace' => '253,245,230',
+ 'olive' => '128,128,0',
+ 'olivedrab' => '107,142,35',
+ 'orange' => '255,165,0',
+ 'orangered' => '255,69,0',
+ 'orchid' => '218,112,214',
+ 'palegoldenrod' => '238,232,170',
+ 'palegreen' => '152,251,152',
+ 'paleturquoise' => '175,238,238',
+ 'palevioletred' => '219,112,147',
+ 'papayawhip' => '255,239,213',
+ 'peachpuff' => '255,218,185',
+ 'peru' => '205,133,63',
+ 'pink' => '255,192,203',
+ 'plum' => '221,160,221',
+ 'powderblue' => '176,224,230',
+ 'purple' => '128,0,128',
+ 'red' => '255,0,0',
+ 'rosybrown' => '188,143,143',
+ 'royalblue' => '65,105,225',
+ 'saddlebrown' => '139,69,19',
+ 'salmon' => '250,128,114',
+ 'sandybrown' => '244,164,96',
+ 'seagreen' => '46,139,87',
+ 'seashell' => '255,245,238',
+ 'sienna' => '160,82,45',
+ 'silver' => '192,192,192',
+ 'skyblue' => '135,206,235',
+ 'slateblue' => '106,90,205',
+ 'slategray' => '112,128,144',
+ 'slategrey' => '112,128,144',
+ 'snow' => '255,250,250',
+ 'springgreen' => '0,255,127',
+ 'steelblue' => '70,130,180',
+ 'tan' => '210,180,140',
+ 'teal' => '0,128,128',
+ 'thistle' => '216,191,216',
+ 'tomato' => '255,99,71',
+ 'transparent' => '0,0,0,0',
+ 'turquoise' => '64,224,208',
+ 'violet' => '238,130,238',
+ 'wheat' => '245,222,179',
+ 'white' => '255,255,255',
+ 'whitesmoke' => '245,245,245',
+ 'yellow' => '255,255,0',
+ 'yellowgreen' => '154,205,50'
+ );
+}
+
+// responsible for taking a string of LESS code and converting it into a
+// syntax tree
+class lessc_parser {
+ static protected $nextBlockId = 0; // used to uniquely identify blocks
+
+ static protected $precedence = array(
+ '=<' => 0,
+ '>=' => 0,
+ '=' => 0,
+ '<' => 0,
+ '>' => 0,
+
+ '+' => 1,
+ '-' => 1,
+ '*' => 2,
+ '/' => 2,
+ '%' => 2,
+ );
+
+ static protected $whitePattern;
+ static protected $commentMulti;
+
+ static protected $commentSingle = "//";
+ static protected $commentMultiLeft = "/*";
+ static protected $commentMultiRight = "*/";
+
+ // regex string to match any of the operators
+ static protected $operatorString;
+
+ // these properties will supress division unless it's inside parenthases
+ static protected $supressDivisionProps =
+ array('/border-radius$/i', '/^font$/i');
+
+ protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
+ protected $lineDirectives = array("charset");
+
+ /**
+ * if we are in parens we can be more liberal with whitespace around
+ * operators because it must evaluate to a single value and thus is less
+ * ambiguous.
+ *
+ * Consider:
+ * property1: 10 -5; // is two numbers, 10 and -5
+ * property2: (10 -5); // should evaluate to 5
+ */
+ protected $inParens = false;
+
+ // caches preg escaped literals
+ static protected $literalCache = array();
+
+ public function __construct($lessc, $sourceName = null) {
+ $this->eatWhiteDefault = true;
+ // reference to less needed for vPrefix, mPrefix, and parentSelector
+ $this->lessc = $lessc;
+
+ $this->sourceName = $sourceName; // name used for error messages
+
+ $this->writeComments = false;
+
+ if (!self::$operatorString) {
+ self::$operatorString =
+ '('.implode('|', array_map(array('lessc', 'preg_quote'),
+ array_keys(self::$precedence))).')';
+
+ $commentSingle = lessc::preg_quote(self::$commentSingle);
+ $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft);
+ $commentMultiRight = lessc::preg_quote(self::$commentMultiRight);
+
+ self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
+ self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
+ }
+ }
+
+ public function parse($buffer) {
+ $this->count = 0;
+ $this->line = 1;
+
+ $this->env = null; // block stack
+ $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
+ $this->pushSpecialBlock("root");
+ $this->eatWhiteDefault = true;
+ $this->seenComments = array();
+
+ // trim whitespace on head
+ // if (preg_match('/^\s+/', $this->buffer, $m)) {
+ // $this->line += substr_count($m[0], "\n");
+ // $this->buffer = ltrim($this->buffer);
+ // }
+ $this->whitespace();
+
+ // parse the entire file
+ $lastCount = $this->count;
+ while (false !== $this->parseChunk());
+
+ if ($this->count != strlen($this->buffer))
+ $this->throwError();
+
+ // TODO report where the block was opened
+ if (!is_null($this->env->parent))
+ throw new exception('parse error: unclosed block');
+
+ return $this->env;
+ }
+
+ /**
+ * Parse a single chunk off the head of the buffer and append it to the
+ * current parse environment.
+ * Returns false when the buffer is empty, or when there is an error.
+ *
+ * This function is called repeatedly until the entire document is
+ * parsed.
+ *
+ * This parser is most similar to a recursive descent parser. Single
+ * functions represent discrete grammatical rules for the language, and
+ * they are able to capture the text that represents those rules.
+ *
+ * Consider the function lessc::keyword(). (all parse functions are
+ * structured the same)
+ *
+ * The function takes a single reference argument. When calling the
+ * function it will attempt to match a keyword on the head of the buffer.
+ * If it is successful, it will place the keyword in the referenced
+ * argument, advance the position in the buffer, and return true. If it
+ * fails then it won't advance the buffer and it will return false.
+ *
+ * All of these parse functions are powered by lessc::match(), which behaves
+ * the same way, but takes a literal regular expression. Sometimes it is
+ * more convenient to use match instead of creating a new function.
+ *
+ * Because of the format of the functions, to parse an entire string of
+ * grammatical rules, you can chain them together using &&.
+ *
+ * But, if some of the rules in the chain succeed before one fails, then
+ * the buffer position will be left at an invalid state. In order to
+ * avoid this, lessc::seek() is used to remember and set buffer positions.
+ *
+ * Before parsing a chain, use $s = $this->seek() to remember the current
+ * position into $s. Then if a chain fails, use $this->seek($s) to
+ * go back where we started.
+ */
+ protected function parseChunk() {
+ if (empty($this->buffer)) return false;
+ $s = $this->seek();
+
+ // setting a property
+ if ($this->keyword($key) && $this->assign() &&
+ $this->propertyValue($value, $key) && $this->end())
+ {
+ $this->append(array('assign', $key, $value), $s);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+
+ // look for special css blocks
+ if ($this->literal('@', false)) {
+ $this->count--;
+
+ // media
+ if ($this->literal('@media')) {
+ if (($this->mediaQueryList($mediaQueries) || true)
+ && $this->literal('{'))
+ {
+ $media = $this->pushSpecialBlock("media");
+ $media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
+ return true;
+ } else {
+ $this->seek($s);
+ return false;
+ }
+ }
+
+ if ($this->literal("@", false) && $this->keyword($dirName)) {
+ if ($this->isDirective($dirName, $this->blockDirectives)) {
+ if (($this->openString("{", $dirValue, null, array(";")) || true) &&
+ $this->literal("{"))
+ {
+ $dir = $this->pushSpecialBlock("directive");
+ $dir->name = $dirName;
+ if (isset($dirValue)) $dir->value = $dirValue;
+ return true;
+ }
+ } elseif ($this->isDirective($dirName, $this->lineDirectives)) {
+ if ($this->propertyValue($dirValue) && $this->end()) {
+ $this->append(array("directive", $dirName, $dirValue));
+ return true;
+ }
+ }
+ }
+
+ $this->seek($s);
+ }
+
+ // setting a variable
+ if ($this->variable($var) && $this->assign() &&
+ $this->propertyValue($value) && $this->end())
+ {
+ $this->append(array('assign', $var, $value), $s);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ if ($this->import($importValue)) {
+ $this->append($importValue, $s);
+ return true;
+ }
+
+ // opening parametric mixin
+ if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
+ ($this->guards($guards) || true) &&
+ $this->literal('{'))
+ {
+ $block = $this->pushBlock($this->fixTags(array($tag)));
+ $block->args = $args;
+ $block->isVararg = $isVararg;
+ if (!empty($guards)) $block->guards = $guards;
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ // opening a simple block
+ if ($this->tags($tags) && $this->literal('{')) {
+ $tags = $this->fixTags($tags);
+ $this->pushBlock($tags);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ // closing a block
+ if ($this->literal('}', false)) {
+ try {
+ $block = $this->pop();
+ } catch (exception $e) {
+ $this->seek($s);
+ $this->throwError($e->getMessage());
+ }
+
+ $hidden = false;
+ if (is_null($block->type)) {
+ $hidden = true;
+ if (!isset($block->args)) {
+ foreach ($block->tags as $tag) {
+ if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
+ $hidden = false;
+ break;
+ }
+ }
+ }
+
+ foreach ($block->tags as $tag) {
+ if (is_string($tag)) {
+ $this->env->children[$tag][] = $block;
+ }
+ }
+ }
+
+ if (!$hidden) {
+ $this->append(array('block', $block), $s);
+ }
+
+ // this is done here so comments aren't bundled into he block that
+ // was just closed
+ $this->whitespace();
+ return true;
+ }
+
+ // mixin
+ if ($this->mixinTags($tags) &&
+ ($this->argumentValues($argv) || true) &&
+ ($this->keyword($suffix) || true) && $this->end())
+ {
+ $tags = $this->fixTags($tags);
+ $this->append(array('mixin', $tags, $argv, $suffix), $s);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ // spare ;
+ if ($this->literal(';')) return true;
+
+ return false; // got nothing, throw error
+ }
+
+ protected function isDirective($dirname, $directives) {
+ // TODO: cache pattern in parser
+ $pattern = implode("|",
+ array_map(array("lessc", "preg_quote"), $directives));
+ $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
+
+ return preg_match($pattern, $dirname);
+ }
+
+ protected function fixTags($tags) {
+ // move @ tags out of variable namespace
+ foreach ($tags as &$tag) {
+ if ($tag{0} == $this->lessc->vPrefix)
+ $tag[0] = $this->lessc->mPrefix;
+ }
+ return $tags;
+ }
+
+ // a list of expressions
+ protected function expressionList(&$exps) {
+ $values = array();
+
+ while ($this->expression($exp)) {
+ $values[] = $exp;
+ }
+
+ if (count($values) == 0) return false;
+
+ $exps = lessc::compressList($values, ' ');
+ return true;
+ }
+
+ /**
+ * Attempt to consume an expression.
+ * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
+ */
+ protected function expression(&$out) {
+ if ($this->value($lhs)) {
+ $out = $this->expHelper($lhs, 0);
+
+ // look for / shorthand
+ if (!empty($this->env->supressedDivision)) {
+ unset($this->env->supressedDivision);
+ $s = $this->seek();
+ if ($this->literal("/") && $this->value($rhs)) {
+ $out = array("list", "",
+ array($out, array("keyword", "/"), $rhs));
+ } else {
+ $this->seek($s);
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * recursively parse infix equation with $lhs at precedence $minP
+ */
+ protected function expHelper($lhs, $minP) {
+ $this->inExp = true;
+ $ss = $this->seek();
+
+ while (true) {
+ $whiteBefore = isset($this->buffer[$this->count - 1]) &&
+ ctype_space($this->buffer[$this->count - 1]);
+
+ // If there is whitespace before the operator, then we require
+ // whitespace after the operator for it to be an expression
+ $needWhite = $whiteBefore && !$this->inParens;
+
+ if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
+ if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
+ foreach (self::$supressDivisionProps as $pattern) {
+ if (preg_match($pattern, $this->env->currentProperty)) {
+ $this->env->supressedDivision = true;
+ break 2;
+ }
+ }
+ }
+
+
+ $whiteAfter = isset($this->buffer[$this->count - 1]) &&
+ ctype_space($this->buffer[$this->count - 1]);
+
+ if (!$this->value($rhs)) break;
+
+ // peek for next operator to see what to do with rhs
+ if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
+ $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
+ }
+
+ $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
+ $ss = $this->seek();
+
+ continue;
+ }
+
+ break;
+ }
+
+ $this->seek($ss);
+
+ return $lhs;
+ }
+
+ // consume a list of values for a property
+ public function propertyValue(&$value, $keyName = null) {
+ $values = array();
+
+ if ($keyName !== null) $this->env->currentProperty = $keyName;
+
+ $s = null;
+ while ($this->expressionList($v)) {
+ $values[] = $v;
+ $s = $this->seek();
+ if (!$this->literal(',')) break;
+ }
+
+ if ($s) $this->seek($s);
+
+ if ($keyName !== null) unset($this->env->currentProperty);
+
+ if (count($values) == 0) return false;
+
+ $value = lessc::compressList($values, ', ');
+ return true;
+ }
+
+ protected function parenValue(&$out) {
+ $s = $this->seek();
+
+ // speed shortcut
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
+ return false;
+ }
+
+ $inParens = $this->inParens;
+ if ($this->literal("(") &&
+ ($this->inParens = true) && $this->expression($exp) &&
+ $this->literal(")"))
+ {
+ $out = $exp;
+ $this->inParens = $inParens;
+ return true;
+ } else {
+ $this->inParens = $inParens;
+ $this->seek($s);
+ }
+
+ return false;
+ }
+
+ // a single value
+ protected function value(&$value) {
+ $s = $this->seek();
+
+ // speed shortcut
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
+ // negation
+ if ($this->literal("-", false) &&
+ (($this->variable($inner) && $inner = array("variable", $inner)) ||
+ $this->unit($inner) ||
+ $this->parenValue($inner)))
+ {
+ $value = array("unary", "-", $inner);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+ }
+
+ if ($this->parenValue($value)) return true;
+ if ($this->unit($value)) return true;
+ if ($this->color($value)) return true;
+ if ($this->func($value)) return true;
+ if ($this->string($value)) return true;
+
+ if ($this->keyword($word)) {
+ $value = array('keyword', $word);
+ return true;
+ }
+
+ // try a variable
+ if ($this->variable($var)) {
+ $value = array('variable', $var);
+ return true;
+ }
+
+ // unquote string (should this work on any type?
+ if ($this->literal("~") && $this->string($str)) {
+ $value = array("escape", $str);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ // css hack: \0
+ if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
+ $value = array('keyword', '\\'.$m[1]);
+ return true;
+ } else {
+ $this->seek($s);
+ }
+
+ return false;
+ }
+
+ // an import statement
+ protected function import(&$out) {
+ $s = $this->seek();
+ if (!$this->literal('@import')) return false;
+
+ // @import "something.css" media;
+ // @import url("something.css") media;
+ // @import url(something.css) media;
+
+ if ($this->propertyValue($value)) {
+ $out = array("import", $value);
+ return true;
+ }
+ }
+
+ protected function mediaQueryList(&$out) {
+ if ($this->genericList($list, "mediaQuery", ",", false)) {
+ $out = $list[2];
+ return true;
+ }
+ return false;
+ }
+
+ protected function mediaQuery(&$out) {
+ $s = $this->seek();
+
+ $expressions = null;
+ $parts = array();
+
+ if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
+ $prop = array("mediaType");
+ if (isset($only)) $prop[] = "only";
+ if (isset($not)) $prop[] = "not";
+ $prop[] = $mediaType;
+ $parts[] = $prop;
+ } else {
+ $this->seek($s);
+ }
+
+
+ if (!empty($mediaType) && !$this->literal("and")) {
+ // ~
+ } else {
+ $this->genericList($expressions, "mediaExpression", "and", false);
+ if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
+ }
+
+ if (count($parts) == 0) {
+ $this->seek($s);
+ return false;
+ }
+
+ $out = $parts;
+ return true;
+ }
+
+ protected function mediaExpression(&$out) {
+ $s = $this->seek();
+ $value = null;
+ if ($this->literal("(") &&
+ $this->keyword($feature) &&
+ ($this->literal(":") && $this->expression($value) || true) &&
+ $this->literal(")"))
+ {
+ $out = array("mediaExp", $feature);
+ if ($value) $out[] = $value;
+ return true;
+ } elseif ($this->variable($variable)) {
+ $out = array('variable', $variable);
+ return true;
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ // an unbounded string stopped by $end
+ protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
+ $oldWhite = $this->eatWhiteDefault;
+ $this->eatWhiteDefault = false;
+
+ $stop = array("'", '"', "@{", $end);
+ $stop = array_map(array("lessc", "preg_quote"), $stop);
+ // $stop[] = self::$commentMulti;
+
+ if (!is_null($rejectStrs)) {
+ $stop = array_merge($stop, $rejectStrs);
+ }
+
+ $patt = '(.*?)('.implode("|", $stop).')';
+
+ $nestingLevel = 0;
+
+ $content = array();
+ while ($this->match($patt, $m, false)) {
+ if (!empty($m[1])) {
+ $content[] = $m[1];
+ if ($nestingOpen) {
+ $nestingLevel += substr_count($m[1], $nestingOpen);
+ }
+ }
+
+ $tok = $m[2];
+
+ $this->count-= strlen($tok);
+ if ($tok == $end) {
+ if ($nestingLevel == 0) {
+ break;
+ } else {
+ $nestingLevel--;
+ }
+ }
+
+ if (($tok == "'" || $tok == '"') && $this->string($str)) {
+ $content[] = $str;
+ continue;
+ }
+
+ if ($tok == "@{" && $this->interpolation($inter)) {
+ $content[] = $inter;
+ continue;
+ }
+
+ if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
+ $ount = null;
+ break;
+ }
+
+ $content[] = $tok;
+ $this->count+= strlen($tok);
+ }
+
+ $this->eatWhiteDefault = $oldWhite;
+
+ if (count($content) == 0) return false;
+
+ // trim the end
+ if (is_string(end($content))) {
+ $content[count($content) - 1] = rtrim(end($content));
+ }
+
+ $out = array("string", "", $content);
+ return true;
+ }
+
+ protected function string(&$out) {
+ $s = $this->seek();
+ if ($this->literal('"', false)) {
+ $delim = '"';
+ } elseif ($this->literal("'", false)) {
+ $delim = "'";
+ } else {
+ return false;
+ }
+
+ $content = array();
+
+ // look for either ending delim , escape, or string interpolation
+ $patt = '([^\n]*?)(@\{|\\\\|' .
+ lessc::preg_quote($delim).')';
+
+ $oldWhite = $this->eatWhiteDefault;
+ $this->eatWhiteDefault = false;
+
+ while ($this->match($patt, $m, false)) {
+ $content[] = $m[1];
+ if ($m[2] == "@{") {
+ $this->count -= strlen($m[2]);
+ if ($this->interpolation($inter, false)) {
+ $content[] = $inter;
+ } else {
+ $this->count += strlen($m[2]);
+ $content[] = "@{"; // ignore it
+ }
+ } elseif ($m[2] == '\\') {
+ $content[] = $m[2];
+ if ($this->literal($delim, false)) {
+ $content[] = $delim;
+ }
+ } else {
+ $this->count -= strlen($delim);
+ break; // delim
+ }
+ }
+
+ $this->eatWhiteDefault = $oldWhite;
+
+ if ($this->literal($delim)) {
+ $out = array("string", $delim, $content);
+ return true;
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ protected function interpolation(&$out) {
+ $oldWhite = $this->eatWhiteDefault;
+ $this->eatWhiteDefault = true;
+
+ $s = $this->seek();
+ if ($this->literal("@{") &&
+ $this->openString("}", $interp, null, array("'", '"', ";")) &&
+ $this->literal("}", false))
+ {
+ $out = array("interpolate", $interp);
+ $this->eatWhiteDefault = $oldWhite;
+ if ($this->eatWhiteDefault) $this->whitespace();
+ return true;
+ }
+
+ $this->eatWhiteDefault = $oldWhite;
+ $this->seek($s);
+ return false;
+ }
+
+ protected function unit(&$unit) {
+ // speed shortcut
+ if (isset($this->buffer[$this->count])) {
+ $char = $this->buffer[$this->count];
+ if (!ctype_digit($char) && $char != ".") return false;
+ }
+
+ if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
+ $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
+ return true;
+ }
+ return false;
+ }
+
+ // a # color
+ protected function color(&$out) {
+ if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
+ if (strlen($m[1]) > 7) {
+ $out = array("string", "", array($m[1]));
+ } else {
+ $out = array("raw_color", $m[1]);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ // consume a list of property values delimited by ; and wrapped in ()
+ protected function argumentValues(&$args, $delim = ',') {
+ $s = $this->seek();
+ if (!$this->literal('(')) return false;
+
+ $values = array();
+ while (true) {
+ if ($this->expressionList($value)) $values[] = $value;
+ if (!$this->literal($delim)) break;
+ else {
+ if ($value == null) $values[] = null;
+ $value = null;
+ }
+ }
+
+ if (!$this->literal(')')) {
+ $this->seek($s);
+ return false;
+ }
+
+ $args = $values;
+ return true;
+ }
+
+ // consume an argument definition list surrounded by ()
+ // each argument is a variable name with optional value
+ // or at the end a ... or a variable named followed by ...
+ protected function argumentDef(&$args, &$isVararg, $delim = ',') {
+ $s = $this->seek();
+ if (!$this->literal('(')) return false;
+
+ $values = array();
+
+ $isVararg = false;
+ while (true) {
+ if ($this->literal("...")) {
+ $isVararg = true;
+ break;
+ }
+
+ if ($this->variable($vname)) {
+ $arg = array("arg", $vname);
+ $ss = $this->seek();
+ if ($this->assign() && $this->expressionList($value)) {
+ $arg[] = $value;
+ } else {
+ $this->seek($ss);
+ if ($this->literal("...")) {
+ $arg[0] = "rest";
+ $isVararg = true;
+ }
+ }
+ $values[] = $arg;
+ if ($isVararg) break;
+ continue;
+ }
+
+ if ($this->value($literal)) {
+ $values[] = array("lit", $literal);
+ }
+
+ if (!$this->literal($delim)) break;
+ }
+
+ if (!$this->literal(')')) {
+ $this->seek($s);
+ return false;
+ }
+
+ $args = $values;
+
+ return true;
+ }
+
+ // consume a list of tags
+ // this accepts a hanging delimiter
+ protected function tags(&$tags, $simple = false, $delim = ',') {
+ $tags = array();
+ while ($this->tag($tt, $simple)) {
+ $tags[] = $tt;
+ if (!$this->literal($delim)) break;
+ }
+ if (count($tags) == 0) return false;
+
+ return true;
+ }
+
+ // list of tags of specifying mixin path
+ // optionally separated by > (lazy, accepts extra >)
+ protected function mixinTags(&$tags) {
+ $s = $this->seek();
+ $tags = array();
+ while ($this->tag($tt, true)) {
+ $tags[] = $tt;
+ $this->literal(">");
+ }
+
+ if (count($tags) == 0) return false;
+
+ return true;
+ }
+
+ // a bracketed value (contained within in a tag definition)
+ protected function tagBracket(&$value) {
+ // speed shortcut
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
+ return false;
+ }
+
+ $s = $this->seek();
+ if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
+ $value = '['.$c.']';
+ // whitespace?
+ if ($this->whitespace()) $value .= " ";
+
+ // escape parent selector, (yuck)
+ $value = str_replace($this->lessc->parentSelector, "$&$", $value);
+ return true;
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ protected function tagExpression(&$value) {
+ $s = $this->seek();
+ if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
+ $value = array('exp', $exp);
+ return true;
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ // a space separated list of selectors
+ protected function tag(&$tag, $simple = false) {
+ if ($simple)
+ $chars = '^@,:;{}\][>\(\) "\'';
+ else
+ $chars = '^@,;{}["\'';
+
+ $s = $this->seek();
+
+ if (!$simple && $this->tagExpression($tag)) {
+ return true;
+ }
+
+ $hasExpression = false;
+ $parts = array();
+ while ($this->tagBracket($first)) $parts[] = $first;
+
+ $oldWhite = $this->eatWhiteDefault;
+ $this->eatWhiteDefault = false;
+
+ while (true) {
+ if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
+ $parts[] = $m[1];
+ if ($simple) break;
+
+ while ($this->tagBracket($brack)) {
+ $parts[] = $brack;
+ }
+ continue;
+ }
+
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
+ if ($this->interpolation($interp)) {
+ $hasExpression = true;
+ $interp[2] = true; // don't unescape
+ $parts[] = $interp;
+ continue;
+ }
+
+ if ($this->literal("@")) {
+ $parts[] = "@";
+ continue;
+ }
+ }
+
+ if ($this->unit($unit)) { // for keyframes
+ $parts[] = $unit[1];
+ $parts[] = $unit[2];
+ continue;
+ }
+
+ break;
+ }
+
+ $this->eatWhiteDefault = $oldWhite;
+ if (!$parts) {
+ $this->seek($s);
+ return false;
+ }
+
+ if ($hasExpression) {
+ $tag = array("exp", array("string", "", $parts));
+ } else {
+ $tag = trim(implode($parts));
+ }
+
+ $this->whitespace();
+ return true;
+ }
+
+ // a css function
+ protected function func(&$func) {
+ $s = $this->seek();
+
+ if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
+ $fname = $m[1];
+
+ $sPreArgs = $this->seek();
+
+ $args = array();
+ while (true) {
+ $ss = $this->seek();
+ // this ugly nonsense is for ie filter properties
+ if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
+ $args[] = array("string", "", array($name, "=", $value));
+ } else {
+ $this->seek($ss);
+ if ($this->expressionList($value)) {
+ $args[] = $value;
+ }
+ }
+
+ if (!$this->literal(',')) break;
+ }
+ $args = array('list', ',', $args);
+
+ if ($this->literal(')')) {
+ $func = array('function', $fname, $args);
+ return true;
+ } elseif ($fname == 'url') {
+ // couldn't parse and in url? treat as string
+ $this->seek($sPreArgs);
+ if ($this->openString(")", $string) && $this->literal(")")) {
+ $func = array('function', $fname, $string);
+ return true;
+ }
+ }
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ // consume a less variable
+ protected function variable(&$name) {
+ $s = $this->seek();
+ if ($this->literal($this->lessc->vPrefix, false) &&
+ ($this->variable($sub) || $this->keyword($name)))
+ {
+ if (!empty($sub)) {
+ $name = array('variable', $sub);
+ } else {
+ $name = $this->lessc->vPrefix.$name;
+ }
+ return true;
+ }
+
+ $name = null;
+ $this->seek($s);
+ return false;
+ }
+
+ /**
+ * Consume an assignment operator
+ * Can optionally take a name that will be set to the current property name
+ */
+ protected function assign($name = null) {
+ if ($name) $this->currentProperty = $name;
+ return $this->literal(':') || $this->literal('=');
+ }
+
+ // consume a keyword
+ protected function keyword(&$word) {
+ if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
+ $word = $m[1];
+ return true;
+ }
+ return false;
+ }
+
+ // consume an end of statement delimiter
+ protected function end() {
+ if ($this->literal(';')) {
+ return true;
+ } elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
+ // if there is end of file or a closing block next then we don't need a ;
+ return true;
+ }
+ return false;
+ }
+
+ protected function guards(&$guards) {
+ $s = $this->seek();
+
+ if (!$this->literal("when")) {
+ $this->seek($s);
+ return false;
+ }
+
+ $guards = array();
+
+ while ($this->guardGroup($g)) {
+ $guards[] = $g;
+ if (!$this->literal(",")) break;
+ }
+
+ if (count($guards) == 0) {
+ $guards = null;
+ $this->seek($s);
+ return false;
+ }
+
+ return true;
+ }
+
+ // a bunch of guards that are and'd together
+ // TODO rename to guardGroup
+ protected function guardGroup(&$guardGroup) {
+ $s = $this->seek();
+ $guardGroup = array();
+ while ($this->guard($guard)) {
+ $guardGroup[] = $guard;
+ if (!$this->literal("and")) break;
+ }
+
+ if (count($guardGroup) == 0) {
+ $guardGroup = null;
+ $this->seek($s);
+ return false;
+ }
+
+ return true;
+ }
+
+ protected function guard(&$guard) {
+ $s = $this->seek();
+ $negate = $this->literal("not");
+
+ if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
+ $guard = $exp;
+ if ($negate) $guard = array("negate", $guard);
+ return true;
+ }
+
+ $this->seek($s);
+ return false;
+ }
+
+ /* raw parsing functions */
+
+ protected function literal($what, $eatWhitespace = null) {
+ if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
+
+ // shortcut on single letter
+ if (!isset($what[1]) && isset($this->buffer[$this->count])) {
+ if ($this->buffer[$this->count] == $what) {
+ if (!$eatWhitespace) {
+ $this->count++;
+ return true;
+ }
+ // goes below...
+ } else {
+ return false;
+ }
+ }
+
+ if (!isset(self::$literalCache[$what])) {
+ self::$literalCache[$what] = lessc::preg_quote($what);
+ }
+
+ return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
+ }
+
+ protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
+ $s = $this->seek();
+ $items = array();
+ while ($this->$parseItem($value)) {
+ $items[] = $value;
+ if ($delim) {
+ if (!$this->literal($delim)) break;
+ }
+ }
+
+ if (count($items) == 0) {
+ $this->seek($s);
+ return false;
+ }
+
+ if ($flatten && count($items) == 1) {
+ $out = $items[0];
+ } else {
+ $out = array("list", $delim, $items);
+ }
+
+ return true;
+ }
+
+
+ // advance counter to next occurrence of $what
+ // $until - don't include $what in advance
+ // $allowNewline, if string, will be used as valid char set
+ protected function to($what, &$out, $until = false, $allowNewline = false) {
+ if (is_string($allowNewline)) {
+ $validChars = $allowNewline;
+ } else {
+ $validChars = $allowNewline ? "." : "[^\n]";
+ }
+ if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false;
+ if ($until) $this->count -= strlen($what); // give back $what
+ $out = $m[1];
+ return true;
+ }
+
+ // try to match something on head of buffer
+ protected function match($regex, &$out, $eatWhitespace = null) {
+ if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
+
+ $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
+ if (preg_match($r, $this->buffer, $out, null, $this->count)) {
+ $this->count += strlen($out[0]);
+ if ($eatWhitespace && $this->writeComments) $this->whitespace();
+ return true;
+ }
+ return false;
+ }
+
+ // match some whitespace
+ protected function whitespace() {
+ if ($this->writeComments) {
+ $gotWhite = false;
+ while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
+ if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
+ $this->append(array("comment", $m[1]));
+ $this->commentsSeen[$this->count] = true;
+ }
+ $this->count += strlen($m[0]);
+ $gotWhite = true;
+ }
+ return $gotWhite;
+ } else {
+ $this->match("", $m);
+ return strlen($m[0]) > 0;
+ }
+ }
+
+ // match something without consuming it
+ protected function peek($regex, &$out = null, $from=null) {
+ if (is_null($from)) $from = $this->count;
+ $r = '/'.$regex.'/Ais';
+ $result = preg_match($r, $this->buffer, $out, null, $from);
+
+ return $result;
+ }
+
+ // seek to a spot in the buffer or return where we are on no argument
+ protected function seek($where = null) {
+ if ($where === null) return $this->count;
+ else $this->count = $where;
+ return true;
+ }
+
+ /* misc functions */
+
+ public function throwError($msg = "parse error", $count = null) {
+ $count = is_null($count) ? $this->count : $count;
+
+ $line = $this->line +
+ substr_count(substr($this->buffer, 0, $count), "\n");
+
+ if (!empty($this->sourceName)) {
+ $loc = "$this->sourceName on line $line";
+ } else {
+ $loc = "line: $line";
+ }
+
+ // TODO this depends on $this->count
+ if ($this->peek("(.*?)(\n|$)", $m, $count)) {
+ throw new exception("$msg: failed at `$m[1]` $loc");
+ } else {
+ throw new exception("$msg: $loc");
+ }
+ }
+
+ protected function pushBlock($selectors=null, $type=null) {
+ $b = new stdclass;
+ $b->parent = $this->env;
+
+ $b->type = $type;
+ $b->id = self::$nextBlockId++;
+
+ $b->isVararg = false; // TODO: kill me from here
+ $b->tags = $selectors;
+
+ $b->props = array();
+ $b->children = array();
+
+ $this->env = $b;
+ return $b;
+ }
+
+ // push a block that doesn't multiply tags
+ protected function pushSpecialBlock($type) {
+ return $this->pushBlock(null, $type);
+ }
+
+ // append a property to the current block
+ protected function append($prop, $pos = null) {
+ if ($pos !== null) $prop[-1] = $pos;
+ $this->env->props[] = $prop;
+ }
+
+ // pop something off the stack
+ protected function pop() {
+ $old = $this->env;
+ $this->env = $this->env->parent;
+ return $old;
+ }
+
+ // remove comments from $text
+ // todo: make it work for all functions, not just url
+ protected function removeComments($text) {
+ $look = array(
+ 'url(', '//', '/*', '"', "'"
+ );
+
+ $out = '';
+ $min = null;
+ while (true) {
+ // find the next item
+ foreach ($look as $token) {
+ $pos = strpos($text, $token);
+ if ($pos !== false) {
+ if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
+ }
+ }
+
+ if (is_null($min)) break;
+
+ $count = $min[1];
+ $skip = 0;
+ $newlines = 0;
+ switch ($min[0]) {
+ case 'url(':
+ if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
+ $count += strlen($m[0]) - strlen($min[0]);
+ break;
+ case '"':
+ case "'":
+ if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count))
+ $count += strlen($m[0]) - 1;
+ break;
+ case '//':
+ $skip = strpos($text, "\n", $count);
+ if ($skip === false) $skip = strlen($text) - $count;
+ else $skip -= $count;
+ break;
+ case '/*':
+ if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
+ $skip = strlen($m[0]);
+ $newlines = substr_count($m[0], "\n");
+ }
+ break;
+ }
+
+ if ($skip == 0) $count += strlen($min[0]);
+
+ $out .= substr($text, 0, $count).str_repeat("\n", $newlines);
+ $text = substr($text, $count + $skip);
+
+ $min = null;
+ }
+
+ return $out.$text;
+ }
+
+}
+
+class lessc_formatter_classic {
+ public $indentChar = " ";
+
+ public $break = "\n";
+ public $open = " {";
+ public $close = "}";
+ public $selectorSeparator = ", ";
+ public $assignSeparator = ":";
+
+ public $openSingle = " { ";
+ public $closeSingle = " }";
+
+ public $disableSingle = false;
+ public $breakSelectors = false;
+
+ public $compressColors = false;
+
+ public function __construct() {
+ $this->indentLevel = 0;
+ }
+
+ public function indentStr($n = 0) {
+ return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
+ }
+
+ public function property($name, $value) {
+ return $name . $this->assignSeparator . $value . ";";
+ }
+
+ protected function isEmpty($block) {
+ if (empty($block->lines)) {
+ foreach ($block->children as $child) {
+ if (!$this->isEmpty($child)) return false;
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ public function block($block) {
+ if ($this->isEmpty($block)) return;
+
+ $inner = $pre = $this->indentStr();
+
+ $isSingle = !$this->disableSingle &&
+ is_null($block->type) && count($block->lines) == 1;
+
+ if (!empty($block->selectors)) {
+ $this->indentLevel++;
+
+ if ($this->breakSelectors) {
+ $selectorSeparator = $this->selectorSeparator . $this->break . $pre;
+ } else {
+ $selectorSeparator = $this->selectorSeparator;
+ }
+
+ echo $pre .
+ implode($selectorSeparator, $block->selectors);
+ if ($isSingle) {
+ echo $this->openSingle;
+ $inner = "";
+ } else {
+ echo $this->open . $this->break;
+ $inner = $this->indentStr();
+ }
+
+ }
+
+ if (!empty($block->lines)) {
+ $glue = $this->break.$inner;
+ echo $inner . implode($glue, $block->lines);
+ if (!$isSingle && !empty($block->children)) {
+ echo $this->break;
+ }
+ }
+
+ foreach ($block->children as $child) {
+ $this->block($child);
+ }
+
+ if (!empty($block->selectors)) {
+ if (!$isSingle && empty($block->children)) echo $this->break;
+
+ if ($isSingle) {
+ echo $this->closeSingle . $this->break;
+ } else {
+ echo $pre . $this->close . $this->break;
+ }
+
+ $this->indentLevel--;
+ }
+ }
+}
+
+class lessc_formatter_compressed extends lessc_formatter_classic {
+ public $disableSingle = true;
+ public $open = "{";
+ public $selectorSeparator = ",";
+ public $assignSeparator = ":";
+ public $break = "";
+ public $compressColors = true;
+
+ public function indentStr($n = 0) {
+ return "";
+ }
+}
+
+class lessc_formatter_lessjs extends lessc_formatter_classic {
+ public $disableSingle = true;
+ public $breakSelectors = true;
+ public $assignSeparator = ": ";
+ public $selectorSeparator = ",";
+}
+
+
diff --git a/plugins/system/t3/includes/menu/megamenu.php b/plugins/system/t3/includes/menu/megamenu.php
new file mode 100644
index 0000000..396bb06
--- /dev/null
+++ b/plugins/system/t3/includes/menu/megamenu.php
@@ -0,0 +1,356 @@
+getMenu('site');
+
+ $attributes = array('menutype');
+ $values = array($menutype);
+
+ if(isset($settings['access'])){
+ $attributes[] = 'access';
+ $values[] = $settings['access'];
+ } else {
+ $settings['access'] = array(1);
+ }
+
+ if(isset($settings['language'])){
+ $attributes[] = 'language';
+ $values[] = $settings['language'];
+ }
+
+ $items = $menu->getItems($attributes, $values);
+
+ $active = ($menu->getActive()) ? $menu->getActive() : $menu->getDefault();
+ $this->active_id = $active ? $active->id : 0;
+ $this->active_tree = $active->tree;
+
+ $this->settings = $settings;
+ $this->params = $params;
+ $this->editmode = isset($settings['editmode']);
+ foreach ($items as &$item) {
+ //remove all non-parent item (the parent has access higher access level)
+ if($item->level >= 2 && !isset($this->_items[$item->parent_id])){
+ continue;
+ }
+
+ $parent = isset($this->children[$item->parent_id]) ? $this->children[$item->parent_id] : array();
+ $parent[] = $item;
+ $this->children[$item->parent_id] = $parent;
+ $this->_items[$item->id] = $item;
+ }
+
+ foreach ($items as &$item) {
+ // bind setting for this item
+ $key = 'item-' . $item->id;
+ $setting = isset($this->settings[$key]) ? $this->settings[$key] : array();
+
+ // decode html tag
+ if (isset($setting['caption']) && $setting['caption'])
+ $setting['caption'] = str_replace(array('[lt]', '[gt]'), array('<', '>'), $setting['caption']);
+ if ($item->level == 1 && isset($setting['caption']) && $setting['caption'])
+ $this->top_level_caption = true;
+
+ // active - current
+ $class = '';
+ if ($item->id == $this->active_id) {
+ $class .= ' current';
+ }
+ if (in_array($item->id, $this->active_tree)) {
+ $class .= ' active';
+ } elseif ($item->type == 'alias') {
+ $aliasToId = $item->params->get('aliasoptions');
+ if (count($this->active_tree) > 0 && $aliasToId == $this->active_tree[count($this->active_tree) - 1]) {
+ $class .= ' active';
+ } elseif (in_array($aliasToId, $this->active_tree)) {
+ $class .= ' alias-parent-active';
+ }
+ }
+
+ $item->class = $class;
+ $item->mega = 0;
+ $item->group = 0;
+ $item->dropdown = 0;
+ if (isset($setting['group']) && $item->level > 1) {
+ $item->group = 1;
+ } else {
+ if ((isset($this->children[$item->id]) && ($this->editmode || !isset($setting['hidesub']))) || isset($setting['sub'])) {
+ $item->dropdown = 1;
+ }
+ }
+ $item->mega = $item->group || $item->dropdown;
+ // set default sub if not exists
+ if ($item->mega) {
+ if (!isset($setting['sub'])) $setting['sub'] = array();
+ if (isset($this->children[$item->id]) && (!isset($setting['sub']['rows']) || !count($setting['sub']['rows']))) {
+ $c = $this->children[$item->id][0]->id;
+ $setting['sub'] = array('rows'=>array(array(array('width'=>12, 'item'=>$c))));
+ }
+ }
+ $item->setting = $setting;
+
+ $item->flink = $item->link;
+
+ // Reverted back for CMS version 2.5.6
+ switch ($item->type) {
+ case 'separator':
+ case 'heading':
+ // No further action needed.
+ continue;
+
+ case 'url':
+ if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) {
+ // If this is an internal Joomla link, ensure the Itemid is set.
+ $item->flink = $item->link . '&Itemid=' . $item->id;
+ }
+ break;
+
+ case 'alias':
+ // If this is an alias use the item id stored in the parameters to make the link.
+ $item->flink = 'index.php?Itemid=' . $item->params->get('aliasoptions');
+ break;
+
+ default:
+ $router = JSite::getRouter();
+ if ($router->getMode() == JROUTER_MODE_SEF) {
+ $item->flink = 'index.php?Itemid=' . $item->id;
+ } else {
+ $item->flink .= '&Itemid=' . $item->id;
+ }
+ break;
+ }
+
+ if (strcasecmp(substr($item->flink, 0, 4), 'http') && (strpos($item->flink, 'index.php?') !== false)) {
+ $item->flink = JRoute::_($item->flink, true, $item->params->get('secure'));
+ } else {
+ $item->flink = JRoute::_($item->flink);
+ }
+
+ // We prevent the double encoding because for some reason the $item is shared for menu modules and we get double encoding
+ // when the cause of that is found the argument should be removed
+ $item->title = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8', false);
+ $item->anchor_css = htmlspecialchars($item->params->get('menu-anchor_css', ''), ENT_COMPAT, 'UTF-8', false);
+ $item->anchor_title = htmlspecialchars($item->params->get('menu-anchor_title', ''), ENT_COMPAT, 'UTF-8', false);
+ $item->menu_image = $item->params->get('menu_image', '') ? htmlspecialchars($item->params->get('menu_image', ''), ENT_COMPAT, 'UTF-8', false) : '';
+ }
+ }
+
+ function render($return = false) {
+ $this->menu = '';
+
+ $this->_('beginmenu');
+ $keys = array_keys($this->_items);
+ if (count($keys)) { //in case the keys is empty array
+ $this->nav(null, $keys[0]);
+ }
+ $this->_('endmenu');
+
+ if ($return) {
+ return $this->menu;
+ } else {
+ echo $this->menu;
+ }
+ }
+
+ function nav($pitem, $start = 0, $end = 0) {
+ if ($start > 0) {
+ if (!isset($this->_items[$start]))
+ return;
+ $pid = $this->_items[$start]->parent_id;
+ $items = array();
+ $started = false;
+ foreach ($this->children[$pid] as $item) {
+ if ($started) {
+ if ($item->id == $end)
+ break;
+ $items[] = $item;
+ } else {
+ if ($item->id == $start) {
+ $started = true;
+ $items[] = $item;
+ }
+ }
+ }
+ if (!count($items))
+ return;
+ } else if ($start === 0) {
+ $pid = $pitem->id;
+ if (!isset($this->children[$pid]))
+ return;
+ $items = $this->children[$pid];
+ } else {
+ //empty menu
+ return;
+ }
+
+ $this->_('beginnav', array(
+ 'item' => $pitem
+ ));
+
+ foreach ($items as $item) {
+ $this->item($item);
+ }
+
+ $this->_('endnav', array(
+ 'item' => $pitem
+ ));
+ }
+
+ function item($item) {
+ // item content
+ $setting = $item->setting;
+
+ $this->_('beginitem', array(
+ 'item' => $item,
+ 'setting' => $setting,
+ 'menu' => $this
+ ));
+
+ $this->menu .= $this->_('item', array(
+ 'item' => $item,
+ 'setting' => $setting,
+ 'menu' => $this
+ ));
+
+ if ($item->mega) {
+ $this->mega($item);
+ }
+ $this->_('enditem', array(
+ 'item' => $item
+ ));
+ }
+
+ function mega($item) {
+ $setting = $item->setting;
+ $sub = $setting['sub'];
+ $items = isset($this->children[$item->id]) ? $this->children[$item->id] : array();
+ $firstitem = count($items) ? $items[0]->id : 0;
+
+ $this->_('beginmega', array(
+ 'item' => $item
+ ));
+ $endItems = array();
+ $k1 = $k2 = 0;
+ foreach ($sub['rows'] as $row) {
+ foreach ($row as $col) {
+ if (!isset($col['position'])) {
+ if ($k1) {
+ $k2 = $col['item'];
+ if (!isset($this->_items[$k2]) || $this->_items[$k2]->parent_id != $item->id)
+ break;
+ $endItems[$k1] = $k2;
+ }
+ $k1 = $col['item'];
+ }
+ }
+ }
+ $endItems[$k1] = 0;
+
+ $firstitemscol = true;
+ foreach ($sub['rows'] as $row) {
+ $this->_('beginrow', array(
+ 'menu' => $this
+ ));
+
+ foreach ($row as $col) {
+ $this->_('begincol', array(
+ 'setting' => $col,
+ 'menu' => $this
+ ));
+ if (isset($col['position'])) {
+ $this->module($col['position']);
+ } else {
+ if (!isset($endItems[$col['item']]))
+ continue;
+ $toitem = $endItems[$col['item']];
+ $startitem = $firstitemscol ? $firstitem : $col['item'];
+ $this->nav($item, $startitem, $toitem);
+ $firstitemscol = false;
+ }
+ $this->_('endcol');
+ }
+ $this->_('endrow');
+ }
+ $this->_('endmega');
+ }
+
+ function module($module) {
+ // load module
+ $id = intval($module);
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params')
+ ->from('#__modules AS m')
+ ->where('m.id = ' . $id)
+ ->where('m.published = 1')
+ ->where('m.access IN ('.implode(',', $this->settings['access']).')');
+ $db->setQuery($query);
+ $module = $db->loadObject();
+
+ //check in case the module is unpublish or deleted
+ if ($module && $module->id) {
+ $style = 'T3Xhtml';
+ $content = JModuleHelper::renderModule($module, array(
+ 'style' => $style
+ ));
+
+ $this->menu .= $content . "\n";
+ }
+ }
+
+ function _($tmpl, $vars = array()) {
+ $vars['menu'] = $this;
+ $this->menu .= T3MenuMegamenuTpl::_($tmpl, $vars);
+ }
+
+ function get($prop) {
+ if (isset($this->$prop))
+ return $this->$prop;
+ return null;
+ }
+
+ function getParam($name, $default = null) {
+ if (!$this->params)
+ return $default;
+ return $this->params->get($name, $default);
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/menu/megamenu.tpl.php b/plugins/system/t3/includes/menu/megamenu.tpl.php
new file mode 100644
index 0000000..2c4594c
--- /dev/null
+++ b/plugins/system/t3/includes/menu/megamenu.tpl.php
@@ -0,0 +1,316 @@
+getParam('navigation_animation', '');
+ $trigger = $menu->getParam('navigation_trigger', 'hover');
+ $responsive = $menu->getParam('responsive', 1);
+ $anim_duration = $menu->getParam('navigation_animation_duration', 0);
+
+ $cls = ' class="t3-megamenu' . ($trigger == 'hover' && $animation ? ' animate ' . $animation : '') . '"';
+ $data = $animation && $anim_duration ? ' data-duration="' . $anim_duration . '"' : '';
+ $data = $data . ($responsive ? ' data-responsive="true"' : '');
+
+ return "";
+ }
+
+ static function endmenu($vars)
+ {
+ return '
';
+ }
+
+ static function beginnav($vars)
+ {
+ $item = $vars['item'];
+ $cls = '';
+ if (!$item) {
+ // first nav
+ $cls = 'nav navbar-nav level0';
+ } else {
+ $cls .= ' mega-nav';
+ $cls .= ' level' . $item->level;
+ }
+ if ($cls) $cls = 'class="' . trim($cls) . '"';
+
+ return '';
+ }
+
+ static function endnav($vars)
+ {
+ return ' ';
+ }
+
+ static function beginmega($vars)
+ {
+ $item = $vars['item'];
+ $setting = $item->setting;
+ $sub = $setting['sub'];
+ $cls = 'nav-child ' . ($item->dropdown ? 'dropdown-menu mega-dropdown-menu' : 'mega-group-ct');
+ $style = '';
+ $data = '';
+ if (isset($sub['class'])) {
+ $data .= " data-class=\"{$sub['class']}\"";
+ $cls .= " {$sub['class']}";
+ }
+ if (isset($setting['alignsub']) && $setting['alignsub'] == 'justify') {
+ $cls .= ' ' . ($vars['menu']->editmode ? 'span' : T3_BASE_NONRSP_WIDTH_PREFIX) . '12';
+ } else {
+ if (isset($sub['width'])) {
+ if ($item->dropdown) $style = ' style="width: ' . str_replace('px', '', $sub['width']) . 'px"';
+ $data .= ' data-width="' . str_replace('px', '', $sub['width']) . '"';
+ }
+ }
+
+ if ($cls) $cls = 'class="' . trim($cls) . '"';
+
+ return "";
+ }
+
+ static function endmega($vars)
+ {
+ return '
';
+ }
+
+ static function beginrow($vars)
+ {
+ return '';
+ }
+
+ static function begincol($vars)
+ {
+ $setting = isset($vars['setting']) ? $vars['setting'] : array();
+ $width = isset($setting['width']) ? $setting['width'] : T3_BASE_MAX_GRID;
+ $data = "data-width=\"$width\"";
+ $cls = ($vars['menu']->editmode ? 'span' : T3_BASE_NONRSP_WIDTH_PREFIX) . $width;
+
+ if (isset($setting['position'])) {
+ $cls .= " mega-col-module";
+ $data .= " data-position=\"{$setting['position']}\"";
+ } else {
+ $cls .= " mega-col-nav";
+ }
+ if (isset($setting['class'])) {
+ $cls .= " {$setting['class']}";
+ $data .= " data-class=\"{$setting['class']}\"";
+ }
+ if (isset($setting['hidewcol'])) {
+ $cls .= " hidden-collapse";
+ $data .= " data-hidewcol=\"1\"";
+ }
+
+ return "";
+ }
+
+ static function endcol($vars)
+ {
+ return '
';
+ }
+
+ static function beginitem($vars)
+ {
+ $item = $vars['item'];
+ $setting = $item->setting;
+ $cls = $item->class;
+
+ if ($item->dropdown) {
+ $cls .= $item->level == 1 ? ' dropdown' : ' dropdown-submenu';
+ }
+
+ if ($item->mega) $cls .= ' mega';
+ if ($item->group) $cls .= ' mega-group';
+ if ($item->type == 'separator' && !$item->group && !$item->mega) $cls .= ' divider';
+
+ $data = "data-id=\"{$item->id}\" data-level=\"{$item->level}\"";
+ if ($item->group) $data .= " data-group=\"1\"";
+ if (isset($setting['class'])) {
+ $cls .= " {$setting['class']}";
+ $data .= " data-class=\"{$setting['class']}\"";
+ }
+ if (isset($setting['alignsub'])) {
+ $cls .= " mega-align-{$setting['alignsub']}";
+ $data .= " data-alignsub=\"{$setting['alignsub']}\"";
+ }
+ if (isset($setting['hidesub'])) $data .= " data-hidesub=\"1\"";
+ if (isset($setting['xicon'])) $data .= " data-xicon=\"{$setting['xicon']}\"";
+ if (isset($setting['caption'])) $data .= " data-caption=\"" . htmlspecialchars($setting['caption']) . "\"";
+ if (isset($setting['hidewcol'])) {
+ $data .= " data-hidewcol=\"1\"";
+ $cls .= " sub-hidden-collapse";
+ }
+
+ if ($cls) $cls = 'class="' . trim($cls) . '"';
+
+ return "";
+ }
+
+ static function enditem($vars)
+ {
+ return ' ';
+ }
+
+ static function item($vars)
+ {
+ $item = $vars['item'];
+ $setting = $item->setting;
+
+ // Note. It is important to remove spaces between elements.
+ $vars['class'] = $item->anchor_css ? $item->anchor_css : '';
+ $vars['title'] = $item->anchor_title ? ' title="' . $item->anchor_title . '" ' : '';
+ $vars['dropdown'] = ' data-target="#"';
+ $vars['caret'] = '';
+ $vars['icon'] = '';
+ $vars['caption'] = '';
+
+ if ($item->dropdown && $item->level < 2) {
+ $vars['class'] .= ' dropdown-toggle';
+ $vars['dropdown'] .= ' data-toggle="dropdown"'; // Note: data-target for JomSocial old bootstrap lib
+ $vars['caret'] = ' ';
+ }
+
+ if($item->group){
+ $vars['class'] .= ' dropdown-header mega-group-title';
+ }
+
+ if ($item->menu_image) {
+ $item->params->get('menu_text', 1) ?
+ $vars['linktype'] = '' . $item->title . ' ' :
+ $vars['linktype'] = ' ';
+ } else {
+ $vars['linktype'] = $item->title;
+ }
+
+ if (isset($setting['xicon']) && $setting['xicon']) {
+ $vars['icon'] = ' ';
+ }
+ if (isset($setting['caption']) && $setting['caption']) {
+ $vars['caption'] = '' . $setting['caption'] . ' ';
+ } else if ($item->level == 1 && $vars['menu']->get('top_level_caption')) {
+ $vars['caption'] = ' ';
+ }
+
+ switch ($item->type) {
+ case 'separator':
+ case 'heading':
+ $html = self::_('item_separator', $vars);
+ break;
+ case 'component':
+ $html = self::_('item_component', $vars);
+ break;
+ case 'url':
+ default:
+ $html = self::_('item_url', $vars);
+ }
+
+ return $html;
+ }
+
+ static function item_url($vars)
+ {
+ $item = $vars['item'];
+ $class = $vars['class'];
+ $title = $vars['title'];
+ $dropdown = $vars['dropdown'];
+ $caret = $vars['caret'];
+ $linktype = $vars['linktype'];
+ $icon = $vars['icon'];
+ $caption = $vars['caption'];
+
+ $flink = $item->flink;
+ $flink = JFilterOutput::ampReplace(htmlspecialchars($flink));
+
+ switch ($item->browserNav) :
+ default:
+ case 0:
+ $link = "$icon$linktype$caret$caption ";
+ break;
+ case 1:
+ // _blank
+ $link = "$icon$linktype$caret$caption ";
+ break;
+ case 2:
+ // window.open
+ $options = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes';
+ $link = "editmode ? " onclick=\"window.open(this.href,'targetWindow','$options');return false;\"" : "") . " $title $dropdown>$icon$linktype$caret$caption ";
+ break;
+ endswitch;
+
+ return $link;
+ }
+
+ static function item_separator($vars)
+ {
+ $item = $vars['item'];
+ $class = $vars['class'];
+ $title = $vars['title'];
+ $dropdown = $vars['dropdown'];
+ $caret = $vars['caret'];
+ $linktype = $vars['linktype'];
+ $icon = $vars['icon'];
+ $caption = $vars['caption'];
+ // Note. It is important to remove spaces between elements.
+
+ $class .= " separator";
+
+ return "$icon$title $linktype$caret$caption ";
+ }
+
+ static function item_component($vars)
+ {
+ $item = $vars['item'];
+ $class = $vars['class'];
+ $title = $vars['title'];
+ $dropdown = $vars['dropdown'];
+ $caret = $vars['caret'];
+ $linktype = $vars['linktype'];
+ $icon = $vars['icon'];
+ $caption = $vars['caption'];
+ // Note. It is important to remove spaces between elements.
+
+ switch ($item->browserNav) :
+ default:
+ case 0:
+ $link = "flink}\" $title $dropdown>$icon$linktype $caret$caption ";
+ break;
+ case 1:
+ // _blank
+ $link = "flink}\" target=\"_blank\" $title $dropdown>$icon$linktype $caret$caption ";
+ break;
+ case 2:
+ // window.open
+ $link = "flink}\"" . (!$vars['menu']->editmode ? " onclick=\"window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;\"" : "") . " $title $dropdown>$icon$linktype $caret$caption ";
+ break;
+ endswitch;
+
+ return $link;
+ }
+
+ static function _($tmpl, $vars) {
+ if (function_exists($func = 'T3MenuMegamenuTpl_'.$tmpl)) {
+ return $func($vars) . "\n";
+ } else if (method_exists('T3MenuMegamenuTpl', $tmpl)) {
+ return T3MenuMegamenuTpl::$tmpl($vars) . "\n";
+ } else {
+ return "$tmpl\n";
+ }
+ }
+}
diff --git a/plugins/system/t3/includes/menu/t3bootstrap.php b/plugins/system/t3/includes/menu/t3bootstrap.php
new file mode 100644
index 0000000..291cdd3
--- /dev/null
+++ b/plugins/system/t3/includes/menu/t3bootstrap.php
@@ -0,0 +1,156 @@
+menutype = $menutype;
+ $this->menu = '';
+ }
+
+ /**
+ * @return string
+ */
+ function render()
+ {
+ if(!$this->menu){
+ ob_start();
+ T3BootstrapTpl::render($this->getList());
+ $this->menu = ob_get_contents();
+ ob_end_clean();
+ }
+
+ return $this->menu;
+ }
+
+ /**
+ * @return mixed
+ */
+ function getList()
+ {
+ $app = JFactory::getApplication();
+ $menu = $app->getMenu();
+
+ // Get active menu item
+ $items = $menu->getItems('menutype', $this->menutype);
+ $lastitem = 0;
+
+ if ($items) {
+ foreach ($items as $i => $item) {
+
+ $item->deeper = false;
+ $item->shallower = false;
+ $item->level_diff = 0;
+
+ if (isset($items[$lastitem])) {
+ $items[$lastitem]->deeper = ($item->level > $items[$lastitem]->level);
+ $items[$lastitem]->shallower = ($item->level < $items[$lastitem]->level);
+ $items[$lastitem]->level_diff = ($items[$lastitem]->level - $item->level);
+ }
+
+ $item->parent = (boolean)$menu->getItems('parent_id', (int)$item->id, true);
+
+ $lastitem = $i;
+ $item->active = false;
+ $item->flink = $item->link;
+
+ // Reverted back for CMS version 2.5.6
+ switch ($item->type) {
+ case 'separator':
+ case 'heading':
+ // No further action needed.
+ continue;
+
+ case 'url':
+ if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) {
+ // If this is an internal Joomla link, ensure the Itemid is set.
+ $item->flink = $item->link . '&Itemid=' . $item->id;
+ }
+ break;
+
+ case 'alias':
+ // If this is an alias use the item id stored in the parameters to make the link.
+ $item->flink = 'index.php?Itemid=' . $item->params->get('aliasoptions');
+ break;
+
+ default:
+ $router = $app::getRouter();
+ if ($router->getMode() == JROUTER_MODE_SEF) {
+ $item->flink = 'index.php?Itemid=' . $item->id;
+ } else {
+ $item->flink .= '&Itemid=' . $item->id;
+ }
+ break;
+ }
+
+ if (strcasecmp(substr($item->flink, 0, 4), 'http') && (strpos($item->flink, 'index.php?') !== false)) {
+ $item->flink = JRoute::_($item->flink, true, $item->params->get('secure'));
+ } else {
+ $item->flink = JRoute::_($item->flink);
+ }
+
+ // We prevent the double encoding because for some reason the $item is shared for menu modules and we get double encoding
+ // when the cause of that is found the argument should be removed
+ $item->title = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8', false);
+ $item->anchor_css = htmlspecialchars($item->params->get('menu-anchor_css', ''), ENT_COMPAT, 'UTF-8', false);
+ $item->anchor_title = htmlspecialchars($item->params->get('menu-anchor_title', ''), ENT_COMPAT, 'UTF-8', false);
+ $item->menu_image = $item->params->get('menu_image', '') ? htmlspecialchars($item->params->get('menu_image', ''), ENT_COMPAT, 'UTF-8', false) : '';
+ }
+
+ if (isset($items[$lastitem])) {
+ $items[$lastitem]->deeper = (1 > $items[$lastitem]->level);
+ $items[$lastitem]->shallower = (1 < $items[$lastitem]->level);
+ $items[$lastitem]->level_diff = ($items[$lastitem]->level - 1);
+ }
+ }
+
+ return $items;
+ }
+
+ /**
+ * Get base menu item.
+ *
+ * @return object
+ */
+ public static function getBase()
+ {
+ return self::getActive();
+ }
+
+ /**
+ * Get active menu item.
+ *
+ * @return object
+ */
+ public static function getActive()
+ {
+ $menu = JFactory::getApplication()->getMenu();
+ return $menu->getActive() ? $menu->getActive() : $menu->getDefault();
+ }
+}
\ No newline at end of file
diff --git a/plugins/system/t3/includes/menu/t3bootstrap.tpl.php b/plugins/system/t3/includes/menu/t3bootstrap.tpl.php
new file mode 100644
index 0000000..13b1526
--- /dev/null
+++ b/plugins/system/t3/includes/menu/t3bootstrap.tpl.php
@@ -0,0 +1,228 @@
+id;
+ $path = $base->tree;
+ ?>
+
+ id;
+ if ($item->id == $active_id) {
+ $class .= ' current';
+ }
+
+ if (in_array($item->id, $path)) {
+ $class .= ' active';
+ } elseif ($item->type == 'alias') {
+ $aliasToId = $item->params->get('aliasoptions');
+ if (count($path) > 0 && $aliasToId == $path[count($path) - 1]) {
+ $class .= ' active';
+ } elseif (in_array($aliasToId, $path)) {
+ $class .= ' alias-parent-active';
+ }
+ }
+
+ if ($item->type == 'separator' || $item->type == 'heading') {
+ $class .= ' divider';
+ }
+
+ if ($item->deeper) {
+ if ($item->level > 1) {
+ $class .= ' dropdown-submenu';
+ } else {
+ $class .= ' deeper dropdown';
+ }
+ }
+
+ if ($item->parent) {
+ $class .= ' parent';
+ }
+
+ if (!empty($class)) {
+ $class = ' class="' . trim($class) . '"';
+ }
+
+ echo '';
+
+ // Render the menu item.
+ switch ($item->type) :
+ case 'separator':
+ case 'url':
+ case 'component':
+ case 'heading':
+ echo self::item($item->type, $item);
+ break;
+
+ default:
+ echo self::item('url', $item);
+ break;
+ endswitch;
+
+ // The next item is deeper.
+ if ($item->deeper) {
+ echo ' ';
+ echo str_repeat(' ', $item->level_diff);
+ } // The next item is on the same level.
+ else {
+ echo '';
+ }
+ endforeach;
+ ?>
+
+ anchor_css ? $item->anchor_css : '';
+ $title = $item->anchor_title ? 'title="' . $item->anchor_title . '" ' : '';
+ $caret = '';
+ $dropdown = '';
+
+ if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+ }
+
+ if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+ }
+
+ if ($item->menu_image) {
+ $item->params->get('menu_text', 1) ?
+ $linktype = '
' . $item->title . ' ' :
+ $linktype = '
';
+ } else {
+ $linktype = $item->title;
+ }
+
+ switch ($item->browserNav) :
+ default:
+ case 0:
+ ?>
+
href="flink; ?>" >
+
+
href="flink; ?>" target="_blank" >
+
+
href="flink; ?>" onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;" >
+
+
+ anchor_title ? ' title="' . $item->anchor_title . '" ' : '';
+ if ($item->menu_image) {
+ $item->params->get('menu_text', 1) ?
+ $linktype = '
' . $item->title . ' ' :
+ $linktype = '
';
+ } else {
+ $linktype = $item->title;
+ }
+
+ ?>
+
>
+ anchor_css ? $item->anchor_css : '';
+ $title = $item->anchor_title ? 'title="' . $item->anchor_title . '" ' : '';
+ $caret = '';
+ $dropdown = '';
+
+ if($item->deeper && $item->level < 2){
+ $class .= ' dropdown-toggle';
+ $dropdown = ' data-toggle="dropdown"';
+ $caret = '
';
+ }
+
+ if(!empty($class)){
+ $class = 'class="'. trim($class) .'" ';
+ }
+
+ if ($item->menu_image) {
+ $item->params->get('menu_text', 1) ?
+ $linktype = '
' . $item->title . ' ' :
+ $linktype = '
';
+ } else {
+ $linktype = $item->title;
+ }
+ $flink = $item->flink;
+ $flink = JFilterOutput::ampReplace(htmlspecialchars($flink));
+
+ switch ($item->browserNav) :
+ default:
+ case 0:
+ ?>
+
href="" >
+
+
href="" target="_blank" >
+ get('window_open');
+ ?>
+
href="" onclick="window.open(this.href,'targetWindow','');return false;" >
+
+ *
+ * @todo can use a stream wrapper to unit test this?
+ */
+class Minify_JS_ClosureCompiler {
+ const URL = 'http://closure-compiler.appspot.com/compile';
+
+ /**
+ * Minify Javascript code via HTTP request to the Closure Compiler API
+ *
+ * @param string $js input code
+ * @param array $options unused at this point
+ * @return string
+ */
+ public static function minify($js, array $options = array())
+ {
+ $obj = new self($options);
+ return $obj->min($js);
+ }
+
+ /**
+ *
+ * @param array $options
+ *
+ * fallbackFunc : default array($this, 'fallback');
+ */
+ public function __construct(array $options = array())
+ {
+ $this->_fallbackFunc = isset($options['fallbackMinifier'])
+ ? $options['fallbackMinifier']
+ : array($this, '_fallback');
+ }
+
+ public function min($js)
+ {
+ $postBody = $this->_buildPostBody($js);
+ $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
+ ? mb_strlen($postBody, '8bit')
+ : strlen($postBody);
+ if ($bytes > 200000) {
+ //T3 Framework
+ //instead of throwing error, we use fall back option
+ if (is_callable($this->_fallbackFunc)) {
+ $response = "/*\n(Using fallback minifier)\n*/\n";
+ $response .= call_user_func($this->_fallbackFunc, $js);
+ } else {
+ throw new Minify_JS_ClosureCompiler_Exception(
+ 'POST content larger than 200000 bytes'
+ );
+ }
+ }
+ $response = $this->_getResponse($postBody);
+ if (preg_match('/^Error\(\d\d?\):/', $response)) {
+ if (is_callable($this->_fallbackFunc)) {
+ $response = "/* Received errors from Closure Compiler API:\n$response"
+ . "\n(Using fallback minifier)\n*/\n";
+ $response .= call_user_func($this->_fallbackFunc, $js);
+ } else {
+ throw new Minify_JS_ClosureCompiler_Exception($response);
+ }
+ }
+ if ($response === '') {
+ $errors = $this->_getResponse($this->_buildPostBody($js, true));
+ throw new Minify_JS_ClosureCompiler_Exception($errors);
+ }
+ return $response;
+ }
+
+ protected $_fallbackFunc = null;
+
+ protected function _getResponse($postBody)
+ {
+ $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
+ if ($allowUrlFopen) {
+ $contents = file_get_contents(self::URL, false, stream_context_create(array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n",
+ 'content' => $postBody,
+ 'max_redirects' => 0,
+ 'timeout' => 15,
+ )
+ )));
+ } elseif (defined('CURLOPT_POST')) {
+ $ch = curl_init(self::URL);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
+ $contents = curl_exec($ch);
+ curl_close($ch);
+ } else {
+ throw new Minify_JS_ClosureCompiler_Exception(
+ "Could not make HTTP request: allow_url_open is false and cURL not available"
+ );
+ }
+ if (false === $contents) {
+ throw new Minify_JS_ClosureCompiler_Exception(
+ "No HTTP response from server"
+ );
+ }
+ return trim($contents);
+ }
+
+ protected function _buildPostBody($js, $returnErrors = false)
+ {
+ return http_build_query(array(
+ 'js_code' => $js,
+ 'output_info' => ($returnErrors ? 'errors' : 'compiled_code'),
+ 'output_format' => 'text',
+ 'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
+ ), null, '&');
+ }
+
+ /**
+ * Default fallback function if CC API fails
+ * @param string $js
+ * @return string
+ */
+ protected function _fallback($js)
+ {
+ //T3 Framework
+ T3::import('minify/jsmin');
+ return JSMin::minify($js);
+ }
+}
+
+class Minify_JS_ClosureCompiler_Exception extends Exception {}
diff --git a/plugins/system/t3/includes/minify/csscompressor.php b/plugins/system/t3/includes/minify/csscompressor.php
new file mode 100644
index 0000000..4b9e51d
--- /dev/null
+++ b/plugins/system/t3/includes/minify/csscompressor.php
@@ -0,0 +1,249 @@
+
+ * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
+ */
+class Minify_CSS_Compressor {
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @param array $options (currently ignored)
+ *
+ * @return string
+ */
+ public static function process($css, $options = array())
+ {
+ $obj = new Minify_CSS_Compressor($options);
+ return $obj->_process($css);
+ }
+
+ /**
+ * @var array
+ */
+ protected $_options = null;
+
+ /**
+ * Are we "in" a hack? I.e. are some browsers targetted until the next comment?
+ *
+ * @var bool
+ */
+ protected $_inHack = false;
+
+
+ /**
+ * Constructor
+ *
+ * @param array $options (currently ignored)
+ */
+ private function __construct($options) {
+ $this->_options = $options;
+ }
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @return string
+ */
+ protected function _process($css)
+ {
+ $css = str_replace("\r\n", "\n", $css);
+
+ // preserve empty comment after '>'
+ // http://www.webdevout.net/css-hacks#in_css-selectors
+ $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
+
+ // preserve empty comment between property and value
+ // http://css-discuss.incutio.com/?page=BoxModelHack
+ $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
+ $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
+
+ // apply callback to all valid comments (and strip out surrounding ws
+ $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
+ ,array($this, '_commentCB'), $css);
+
+ // remove ws around { } and last semicolon in declaration block
+ $css = preg_replace('/\\s*{\\s*/', '{', $css);
+ $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
+
+ // remove ws surrounding semicolons
+ $css = preg_replace('/\\s*;\\s*/', ';', $css);
+
+ // remove ws around urls
+ $css = preg_replace('/
+ url\\( # url(
+ \\s*
+ ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
+ \\s*
+ \\) # )
+ /x', 'url($1)', $css);
+
+ // remove ws between rules and colons
+ $css = preg_replace('/
+ \\s*
+ ([{;]) # 1 = beginning of block or rule separator
+ \\s*
+ ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
+ \\s*
+ :
+ \\s*
+ (\\b|[#\'"-]) # 3 = first character of a value
+ /x', '$1$2:$3', $css);
+
+ // remove ws in selectors
+ $css = preg_replace_callback('/
+ (?: # non-capture
+ \\s*
+ [^~>+,\\s]+ # selector part
+ \\s*
+ [,>+~] # combinators
+ )+
+ \\s*
+ [^~>+,\\s]+ # selector part
+ { # open declaration block
+ /x'
+ ,array($this, '_selectorsCB'), $css);
+
+ // minimize hex colors
+ $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
+ , '$1#$2$3$4$5', $css);
+
+ // remove spaces between font families
+ $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
+ ,array($this, '_fontFamilyCB'), $css);
+
+ $css = preg_replace('/@import\\s+url/', '@import url', $css);
+
+ // replace any ws involving newlines with a single newline
+ $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
+
+ // separate common descendent selectors w/ newlines (to limit line lengths)
+ $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
+
+ // Use newline after 1st numeric value (to limit line lengths).
+ $css = preg_replace('/
+ ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
+ \\s+
+ /x'
+ ,"$1\n", $css);
+
+ // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
+ $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
+
+ return trim($css);
+ }
+
+ /**
+ * Replace what looks like a set of selectors
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _selectorsCB($m)
+ {
+ // remove ws around the combinators
+ return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
+ }
+
+ /**
+ * Process a comment and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _commentCB($m)
+ {
+ $hasSurroundingWs = (trim($m[0]) !== $m[1]);
+ $m = $m[1];
+ // $m is the comment content w/o the surrounding tokens,
+ // but the return value will replace the entire comment.
+ if ($m === 'keep') {
+ return '/**/';
+ }
+ if ($m === '" "') {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*" "*/';
+ }
+ if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*";}}/* */';
+ }
+ if ($this->_inHack) {
+ // inversion: feeding only to one browser
+ if (preg_match('@
+ ^/ # comment started like /*/
+ \\s*
+ (\\S[\\s\\S]+?) # has at least some non-ws content
+ \\s*
+ /\\* # ends like /*/ or /**/
+ @x', $m, $n)) {
+ // end hack mode after this comment, but preserve the hack and comment content
+ $this->_inHack = false;
+ return "/*/{$n[1]}/**/";
+ }
+ }
+ if (substr($m, -1) === '\\') { // comment ends like \*/
+ // begin hack mode and preserve hack
+ $this->_inHack = true;
+ return '/*\\*/';
+ }
+ if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
+ // begin hack mode and preserve hack
+ $this->_inHack = true;
+ return '/*/*/';
+ }
+ if ($this->_inHack) {
+ // a regular comment ends hack mode but should be preserved
+ $this->_inHack = false;
+ return '/**/';
+ }
+ // Issue 107: if there's any surrounding whitespace, it may be important, so
+ // replace the comment with a single space
+ return $hasSurroundingWs // remove all other comments
+ ? ' '
+ : '';
+ }
+
+ /**
+ * Process a font-family listing and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _fontFamilyCB($m)
+ {
+ // Issue 210: must not eliminate WS between words in unquoted families
+ $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $out = 'font-family:';
+ while (null !== ($piece = array_shift($pieces))) {
+ if ($piece[0] !== '"' && $piece[0] !== "'") {
+ $piece = preg_replace('/\\s+/', ' ', $piece);
+ $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
+ }
+ $out .= $piece;
+ }
+ return $out . $m[2];
+ }
+}
diff --git a/plugins/system/t3/includes/minify/jsmin.php b/plugins/system/t3/includes/minify/jsmin.php
new file mode 100644
index 0000000..c84dd84
--- /dev/null
+++ b/plugins/system/t3/includes/minify/jsmin.php
@@ -0,0 +1,437 @@
+
+ * $minifiedJs = JSMin::minify($js);
+ *
+ *
+ * This is a modified port of jsmin.c. Improvements:
+ *
+ * Does not choke on some regexp literals containing quote characters. E.g. /'/
+ *
+ * Spaces are preserved after some add/sub operators, so they are not mistakenly
+ * converted to post-inc/dec. E.g. a + ++b -> a+ ++b
+ *
+ * Preserves multi-line comments that begin with /*!
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
+ *
+ * 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 shall be used for Good, not Evil.
+ *
+ * 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.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove
(PHP port)
+ * @author Steve Clay (modifications + cleanup)
+ * @author Andrea Giammarchi (spaceBeforeRegExp)
+ * @copyright 2002 Douglas Crockford (jsmin.c)
+ * @copyright 2008 Ryan Grove (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+ const ORD_LF = 10;
+ const ORD_SPACE = 32;
+ const ACTION_KEEP_A = 1;
+ const ACTION_DELETE_A = 2;
+ const ACTION_DELETE_A_B = 3;
+
+ protected $a = "\n";
+ protected $b = '';
+ protected $input = '';
+ protected $inputIndex = 0;
+ protected $inputLength = 0;
+ protected $lookAhead = null;
+ protected $output = '';
+ protected $lastByteOut = '';
+ protected $keptComment = '';
+
+ /**
+ * Minify Javascript.
+ *
+ * @param string $js Javascript to be minified
+ *
+ * @return string
+ */
+ public static function minify($js)
+ {
+ $jsmin = new JSMin($js);
+ return $jsmin->min();
+ }
+
+ /**
+ * @param string $input
+ */
+ public function __construct($input)
+ {
+ $this->input = $input;
+ }
+
+ /**
+ * Perform minification, return result
+ *
+ * @return string
+ */
+ public function min()
+ {
+ if ($this->output !== '') { // min already run
+ return $this->output;
+ }
+
+ $mbIntEnc = null;
+ if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
+ $mbIntEnc = mb_internal_encoding();
+ mb_internal_encoding('8bit');
+ }
+ $this->input = str_replace("\r\n", "\n", $this->input);
+ $this->inputLength = strlen($this->input);
+
+ $this->action(self::ACTION_DELETE_A_B);
+
+ while ($this->a !== null) {
+ // determine next command
+ $command = self::ACTION_KEEP_A; // default
+ if ($this->a === ' ') {
+ if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
+ && ($this->b === $this->lastByteOut)) {
+ // Don't delete this space. If we do, the addition/subtraction
+ // could be parsed as a post-increment
+ } elseif (! $this->isAlphaNum($this->b)) {
+ $command = self::ACTION_DELETE_A;
+ }
+ } elseif ($this->a === "\n") {
+ if ($this->b === ' ') {
+ $command = self::ACTION_DELETE_A_B;
+
+ // in case of mbstring.func_overload & 2, must check for null b,
+ // otherwise mb_strpos will give WARNING
+ } elseif ($this->b === null
+ || (false === strpos('{[(+-!~', $this->b)
+ && ! $this->isAlphaNum($this->b))) {
+ $command = self::ACTION_DELETE_A;
+ }
+ } elseif (! $this->isAlphaNum($this->a)) {
+ if ($this->b === ' '
+ || ($this->b === "\n"
+ && (false === strpos('}])+-"\'', $this->a)))) {
+ $command = self::ACTION_DELETE_A_B;
+ }
+ }
+ $this->action($command);
+ }
+ $this->output = trim($this->output);
+
+ if ($mbIntEnc !== null) {
+ mb_internal_encoding($mbIntEnc);
+ }
+ return $this->output;
+ }
+
+ /**
+ * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
+ * ACTION_DELETE_A = Copy B to A. Get the next B.
+ * ACTION_DELETE_A_B = Get the next B.
+ *
+ * @param int $command
+ * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
+ */
+ protected function action($command)
+ {
+ // make sure we don't compress "a + ++b" to "a+++b", etc.
+ if ($command === self::ACTION_DELETE_A_B
+ && $this->b === ' '
+ && ($this->a === '+' || $this->a === '-')) {
+ // Note: we're at an addition/substraction operator; the inputIndex
+ // will certainly be a valid index
+ if ($this->input[$this->inputIndex] === $this->a) {
+ // This is "+ +" or "- -". Don't delete the space.
+ $command = self::ACTION_KEEP_A;
+ }
+ }
+
+ switch ($command) {
+ case self::ACTION_KEEP_A: // 1
+ $this->output .= $this->a;
+
+ if ($this->keptComment) {
+ $this->output = rtrim($this->output, "\n");
+ $this->output .= $this->keptComment;
+ $this->keptComment = '';
+ }
+
+ $this->lastByteOut = $this->a;
+
+ // fallthrough intentional
+ case self::ACTION_DELETE_A: // 2
+ $this->a = $this->b;
+ if ($this->a === "'" || $this->a === '"') { // string literal
+ $str = $this->a; // in case needed for exception
+ for(;;) {
+ $this->output .= $this->a;
+ $this->lastByteOut = $this->a;
+
+ $this->a = $this->get();
+ if ($this->a === $this->b) { // end quote
+ break;
+ }
+ if ($this->isEOF($this->a)) {
+ throw new JSMin_UnterminatedStringException(
+ "JSMin: Unterminated String at byte {$this->inputIndex}: {$str}");
+ }
+ $str .= $this->a;
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->lastByteOut = $this->a;
+
+ $this->a = $this->get();
+ $str .= $this->a;
+ }
+ }
+ }
+
+ // fallthrough intentional
+ case self::ACTION_DELETE_A_B: // 3
+ $this->b = $this->next();
+ if ($this->b === '/' && $this->isRegexpLiteral()) {
+ $this->output .= $this->a . $this->b;
+ $pattern = '/'; // keep entire pattern in case we need to report it in the exception
+ for(;;) {
+ $this->a = $this->get();
+ $pattern .= $this->a;
+ if ($this->a === '[') {
+ for(;;) {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ $pattern .= $this->a;
+ if ($this->a === ']') {
+ break;
+ }
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ $pattern .= $this->a;
+ }
+ if ($this->isEOF($this->a)) {
+ throw new JSMin_UnterminatedRegExpException(
+ "JSMin: Unterminated set in RegExp at byte "
+ . $this->inputIndex .": {$pattern}");
+ }
+ }
+ }
+
+ if ($this->a === '/') { // end pattern
+ break; // while (true)
+ } elseif ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ $pattern .= $this->a;
+ } elseif ($this->isEOF($this->a)) {
+ throw new JSMin_UnterminatedRegExpException(
+ "JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}");
+ }
+ $this->output .= $this->a;
+ $this->lastByteOut = $this->a;
+ }
+ $this->b = $this->next();
+ }
+ // end case ACTION_DELETE_A_B
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ protected function isRegexpLiteral()
+ {
+ if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
+ // we obviously aren't dividing
+ return true;
+ }
+ if ($this->a === ' ' || $this->a === "\n") {
+ $length = strlen($this->output);
+ if ($length < 2) { // weird edge case
+ return true;
+ }
+ // you can't divide a keyword
+ if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
+ if ($this->output === $m[0]) { // odd but could happen
+ return true;
+ }
+ // make sure it's a keyword, not end of an identifier
+ $charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);
+ if (! $this->isAlphaNum($charBeforeKeyword)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the next character from stdin. Watch out for lookahead. If the character is a control character,
+ * translate it to a space or linefeed.
+ *
+ * @return string
+ */
+ protected function get()
+ {
+ $c = $this->lookAhead;
+ $this->lookAhead = null;
+ if ($c === null) {
+ // getc(stdin)
+ if ($this->inputIndex < $this->inputLength) {
+ $c = $this->input[$this->inputIndex];
+ $this->inputIndex += 1;
+ } else {
+ $c = null;
+ }
+ }
+ if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
+ return $c;
+ }
+ if ($c === "\r") {
+ return "\n";
+ }
+ return ' ';
+ }
+
+ /**
+ * Does $a indicate end of input?
+ *
+ * @param string $a
+ * @return bool
+ */
+ protected function isEOF($a)
+ {
+ return ord($a) <= self::ORD_LF;
+ }
+
+ /**
+ * Get next char (without getting it). If is ctrl character, translate to a space or newline.
+ *
+ * @return string
+ */
+ protected function peek()
+ {
+ $this->lookAhead = $this->get();
+ return $this->lookAhead;
+ }
+
+ /**
+ * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
+ *
+ * @param string $c
+ *
+ * @return bool
+ */
+ protected function isAlphaNum($c)
+ {
+ return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
+ }
+
+ /**
+ * Consume a single line comment from input (possibly retaining it)
+ */
+ protected function consumeSingleLineComment()
+ {
+ $comment = '';
+ while (true) {
+ $get = $this->get();
+ $comment .= $get;
+ if (ord($get) <= self::ORD_LF) { // end of line reached
+ // if IE conditional comment
+ if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
+ $this->keptComment .= "/{$comment}";
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Consume a multiple line comment from input (possibly retaining it)
+ *
+ * @throws JSMin_UnterminatedCommentException
+ */
+ protected function consumeMultipleLineComment()
+ {
+ $this->get();
+ $comment = '';
+ for(;;) {
+ $get = $this->get();
+ if ($get === '*') {
+ if ($this->peek() === '/') { // end of comment reached
+ $this->get();
+ if (0 === strpos($comment, '!')) {
+ // preserved by YUI Compressor
+ if (!$this->keptComment) {
+ // don't prepend a newline if two comments right after one another
+ $this->keptComment = "\n";
+ }
+ $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
+ } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
+ // IE conditional
+ $this->keptComment .= "/*{$comment}*/";
+ }
+ return;
+ }
+ } elseif ($get === null) {
+ throw new JSMin_UnterminatedCommentException(
+ "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
+ }
+ $comment .= $get;
+ }
+ }
+
+ /**
+ * Get the next character, skipping over comments. Some comments may be preserved.
+ *
+ * @return string
+ */
+ protected function next()
+ {
+ $get = $this->get();
+ if ($get === '/') {
+ switch ($this->peek()) {
+ case '/':
+ $this->consumeSingleLineComment();
+ $get = "\n";
+ break;
+ case '*':
+ $this->consumeMultipleLineComment();
+ $get = ' ';
+ break;
+ }
+ }
+ return $get;
+ }
+}
+
+class JSMin_UnterminatedStringException extends Exception {}
+class JSMin_UnterminatedCommentException extends Exception {}
+class JSMin_UnterminatedRegExpException extends Exception {}
diff --git a/plugins/system/t3/includes/renderer/megamenu.php b/plugins/system/t3/includes/renderer/megamenu.php
new file mode 100644
index 0000000..ac26dc8
--- /dev/null
+++ b/plugins/system/t3/includes/renderer/megamenu.php
@@ -0,0 +1,35 @@
+getParam('mm_type', 'mainmenu') : $params['name']) : $params['menutype'];
+ $currentconfig = json_decode($t3app->getParam('mm_config', ''), true);
+
+ //force to array
+ if (!is_array($currentconfig)) {
+ $currentconfig = (array)$currentconfig;
+ }
+
+ //get user access levels
+ $viewLevels = JFactory::getUser()->getAuthorisedViewLevels();
+ $mmkey = $menutype;
+ $mmconfig = array();
+ if (!empty($currentconfig)) {
+ //find best fit configuration based on view level
+ $vlevels = array_merge($viewLevels);
+ if (is_array($vlevels) && in_array(3, $vlevels)) { //we assume, if a user is special, they should be registered also
+ $vlevels[] = 2;
+ }
+ $vlevels = array_unique($vlevels);
+ rsort($vlevels);
+ if (!is_array($vlevels)) $vlevels = array();
+ $vlevels[] = ''; // extend a blank, default key
+
+ // check if available configuration for language override
+ $langcode = JFactory::getDocument()->language;
+ $shortlangcode = substr($langcode, 0, 2);
+ $types = array($menutype . '-' . $langcode, $menutype . '-' . $shortlangcode, $menutype);
+
+ foreach ($types as $type) {
+ foreach ($vlevels as $vlevel) {
+ $key = $type . ($vlevel !== '' ? '-' . $vlevel : '');
+ if(isset($currentconfig[$key])) {
+ $mmkey = $key;
+ $menutype = $type;
+ break 2;
+ }
+ }
+ }
+ if (isset($currentconfig[$mmkey])) {
+ $mmconfig = $currentconfig[$mmkey];
+ if(!is_array($mmconfig)){
+ $mmconfig = array();
+ }
+ }
+ }
+
+ JDispatcher::getInstance()->trigger('onT3Megamenu', array(&$menutype, &$mmconfig, &$viewLevels));
+
+ $mmconfig['access'] = $viewLevels;
+ $menu = new T3MenuMegamenu ($menutype, $mmconfig, $t3app->_tpl->params);
+
+ $buffer = $menu->render(true);
+
+ if (isset($params['return_result']) && $params['return_result']) {
+ return $buffer;
+ } else {
+ $t3app->setBuffer($buffer, 'megamenu', empty($params['name']) ? null : $params['name'], null);
+ return '';
+ }
+ }
+}
diff --git a/plugins/system/t3/includes/renderer/pageclass.php b/plugins/system/t3/includes/renderer/pageclass.php
new file mode 100644
index 0000000..2641143
--- /dev/null
+++ b/plugins/system/t3/includes/renderer/pageclass.php
@@ -0,0 +1,77 @@
+input;
+ $t3tpl = T3::getApp();
+ $pageclass = array();
+ if($input->getCmd('option', '')){
+ $pageclass[] = $input->getCmd('option', '');
+ }
+ if($input->getCmd('view', '')){
+ $pageclass[] = 'view-' . $input->getCmd('view', '');
+ }
+ if($input->getCmd('layout', '')){
+ $pageclass[] = 'layout-' . $input->getCmd('layout', '');
+ }
+ if($input->getCmd('task', '')){
+ $pageclass[] = 'task-' . $input->getCmd('task', '');
+ }
+ if($input->getCmd('Itemid', '')){
+ $pageclass[] = 'itemid-' . $input->getCmd('Itemid', '');
+ }
+
+ $menu = JFactory::getApplication()->getMenu();
+ if($menu){
+ $active = $menu->getActive();
+ $default = $menu->getDefault();
+
+ if ($active) {
+ if($default && $active->id == $default->id){
+ $pageclass[] = 'home';
+ }
+
+ if ($active->params && $active->params->get('pageclass_sfx')) {
+ $pageclass[] = $active->params->get('pageclass_sfx');
+ }
+ }
+ }
+
+ $pageclass[] = 'j'.str_replace('.', '', (number_format((float)JVERSION, 1, '.', '')));
+ $pageclass = array_unique(array_merge($pageclass, $t3tpl->getPageclass()));
+
+ JDispatcher::getInstance()->trigger('onT3BodyClass', array(&$pageclass));
+
+ return implode(' ', $pageclass);
+ }
+
+}
diff --git a/plugins/system/t3/includes/renderer/t3ajax.php b/plugins/system/t3/includes/renderer/t3ajax.php
new file mode 100644
index 0000000..6707024
--- /dev/null
+++ b/plugins/system/t3/includes/renderer/t3ajax.php
@@ -0,0 +1,124 @@
+input;
+ $task = $input->getCmd('t3ajax', 'position');
+ $format = $input->getCmd('f', 'html');
+
+ if($task == 'position'){
+ if($format == 'html'){
+ return $this->htmlPosition($info, $params, $content);
+ } else if($format == 'json'){
+ return $this->jsonPosition($info, $params, $content);
+ }
+ } else if($task == 'module'){
+ if($format == 'html'){
+ return $this->htmlModule($info, $params, $content);
+ } else if($format == 'json'){
+ return $this->jsonModule($info, $params, $content);
+ }
+ }
+
+ return null;
+ }
+
+ protected function htmlPosition($info, $params = array(), $content = null)
+ {
+ $renderer = $this->_doc->loadRenderer('module');
+
+ $input = JFactory::getApplication()->input;
+ $position = $input->getCmd('p');
+
+ $buffer = '';
+
+ foreach (JModuleHelper::getModules($position) as $mod)
+ {
+ $buffer .= $renderer->render($mod, $params, $content);
+ }
+
+ return $buffer;
+ }
+
+ protected function jsonPosition($info, $params = array(), $content = null)
+ {
+ $result = array();
+
+ $result['markup'] = $this->htmlPosition($info, $params = array(), $content = null);
+
+ $result['stylesheets'] = $this->_doc->_styleSheets;
+ $result['styles'] = $this->_doc->_style;
+
+ $result['scripts'] = $this->_doc->_scripts;
+ $result['scriptinlines'] = $this->_doc->_script;
+
+ return json_encode($result);
+ }
+
+ protected function htmlModule($info, $params = array(), $content = null)
+ {
+ $input = JFactory::getApplication()->input;
+ $mid = $input->getInt('m');
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params');
+ $query->from('#__modules AS m');
+ $query->where('m.id = '. $mid);
+ $query->where('m.published = 1');
+ $db->setQuery($query);
+ $module = $db->loadObject();
+
+ $buffer = '';
+ //check in case the module is unpublish or deleted
+ if($module && $module->id){
+ $buffer = JModuleHelper::renderModule($module, array('style'=> $input->getCmd('style', 'T3Xhtml')));
+ }
+
+ return $buffer;
+ }
+
+ protected function jsonModule($info, $params = array(), $content = null)
+ {
+ $result = array();
+
+ $result['markup'] = $this->htmlModule($info, $params = array(), $content = null);
+
+ $result['stylesheets'] = $this->_doc->_styleSheets;
+ $result['styles'] = $this->_doc->_style;
+
+ $result['scripts'] = $this->_doc->_scripts;
+ $result['scriptinlines'] = $this->_doc->_script;
+
+ return json_encode($result);
+ }
+}
diff --git a/plugins/system/t3/includes/renderer/t3bootstrap.php b/plugins/system/t3/includes/renderer/t3bootstrap.php
new file mode 100644
index 0000000..da13fcd
--- /dev/null
+++ b/plugins/system/t3/includes/renderer/t3bootstrap.php
@@ -0,0 +1,41 @@
+getParam('mm_type', 'mainmenu') : $params['menutype'];
+
+ JDispatcher::getInstance()->trigger('onT3BSMenu', array(&$menutype));
+ $menu = new T3Bootstrap($menutype);
+
+ return $menu->render(true);
+ }
+}
diff --git a/plugins/system/t3/index.html b/plugins/system/t3/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/system/t3/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.ini b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.ini
new file mode 100644
index 0000000..91c5bb2
--- /dev/null
+++ b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.ini
@@ -0,0 +1,586 @@
+; GLOBAL
+T3_GLOBAL_TOGGLE_FOLDING = "Collapse / Expand"
+
+; OVERVIEW
+T3_OVERVIEW_LABEL = "Overview"
+T3_OVERVIEW_NAME = "Name:"
+T3_OVERVIEW_VERSION = "Version:"
+T3_OVERVIEW_CREATE_DATE = "Released Date:"
+T3_OVERVIEW_AUTHOR = "Author:"
+
+T3_OVERVIEW_TPL_INFO = "Template Information"
+T3_OVERVIEW_FRMWRK_INFO = "Framework Information"
+
+T3_OVERVIEW_CHECK_UPDATE = "Check for new version"
+T3_OVERVIEW_GO_DOWNLOAD = "Update now"
+
+T3_OVERVIEW_FMRWRK_NAME = "T3 Framework"
+T3_OVERVIEW_TPL_SAME = "Congrats! You are using latest version of %s!"
+T3_OVERVIEW_TPL_SAME_MSG = "Your version is %s "
+T3_OVERVIEW_TPL_NEW_MSG = "Your version is %s . %s's latest version is %s ."
+T3_OVERVIEW_TPL_NEW = "Dude! There's a newer version for your %s!"
+T3_OVERVIEW_TPL_DL_CENTER = "Download Center"
+T3_OVERVIEW_TPL_UPDATE_CENTER = "Update Center"
+T3_OVERVIEW_TPL_VERSION = "You are using %s version %s"
+T3_OVERVIEW_TPL_VERSION_MSG = "This template is not available on Joomla Update channel"
+
+T3_OVERVIEW_FRMWRK_SAME = "Congrats! You are using latest version of %s!"
+T3_OVERVIEW_FRMWRK_SAME_MSG = "Your version is %s "
+T3_OVERVIEW_FRMWRK_NEW = "Dude! There's a newer version for your %s!"
+T3_OVERVIEW_FRMWRK_NEW_MSG = "Your version is %s . %s's latest version is %s ."
+
+T3_OVERVIEW_FAILED_GETLIST = "Cannot get extension list from repository"
+T3_OVERVIEW_CHK_UPDATE_OK = "Checking Completed"
+
+T3_FRMWRK_OVERVIEW = "Framework Overview"
+T3_FRMWRK_DESC_1 = "T3 Framework"
+T3_FRMWRK_DESC_2 = "The ''All New'' T3"
+T3_FRMWRK_DESC_3 = "Our T3 framework is the most popular template framework for Joomla. It powers all our T3 based templates and is available for Joomla 2.5 and 3.0. For the ease of upgrades the framework is in the plugin format and is installed separately. With over 3 years of active development T3 framework has come a long way and is more robust, user friendly, feature rich, easy to customize and not to mention the responsive layouts support which not only looks good on all browsers and devices but also works like a charm."
+T3_FRMWRK_DESC_4 = "Resources:"
+T3_FRMWRK_DESC_5 = "Download Link "
+T3_FRMWRK_DESC_6 = "Documentation Link "
+T3_FRMWRK_DESC_7 = "Change log Link "
+T3_FRMWRK_DESC_8 = "Version & Update "
+T3_FRMWRK_DESC_9 = "Forum Link "
+
+
+; GENERAL
+T3_GENERAL_LABEL = "General"
+T3_GENERAL_DESC = "The following settings will be applied for all styles, themes and layouts"
+T3_GENERAL_DEVELOPMENT_LABEL = "Development Mode"
+T3_GENERAL_DEVELOPMENT_DESC = "When Development Mode is enabled, less is used instead of css"
+T3_GENERAL_DEVELOPMENT_FOLDER_LABEL = "Development Folder"
+T3_GENERAL_DEVELOPMENT_FOLDER_DESC = "When Development Mode is enabled, T3 will compile every LESS files to CSS files into this folder for easy tracking. This folder must be writable."
+T3_GENERAL_THEMER_LABEL = "ThemeMagic"
+T3_GENERAL_THEMER_DESC = "Enable this option to access ThemeMagic customization panel."
+T3_GENERAL_LEGACY_CSS_LABEL = "Legacy Compatible"
+T3_GENERAL_LEGACY_CSS_DESC = "Load some important compatible styles for Bootstrap 2 and Font Awesome 3.x"
+T3_GENERAL_RESPONSIVE_LABEL = "Responsive"
+T3_GENERAL_RESPONSIVE_DESC = "Enable this if this template supports responsive layout. Switching this option need re-build LESS to CSS."
+T3_GENERAL_NON_RESPON_WIDTH_LABEL = "Non-Responsive Width"
+T3_GENERAL_NON_RESPON_WIDTH_DESC = "Container width for non-responsive layout"
+T3_GENERAL_BUILD_RTL_LABEL = "Build RTL CSS"
+T3_GENERAL_BUILD_RTL_DESC = "Enable this option will allow the compiling LESS to CSS process to also build the CSS file for RTL languages"
+
+T3_GENERAL_OPTIMIZE_LABEL ="Optimization"
+T3_GENERAL_OPTIMIZE_DESC ="Enable compress CSS/JS. These options only available when Development Mode is off"
+
+T3_GENERAL_ASSETS_MINIFY_LABEL = "Optimize CSS"
+T3_GENERAL_ASSETS_MINIFY_DESC = "When you enable this option, compressed CSS files will be used (.min.css files)"
+T3_GENERAL_ASSETS_MINIFYJS_LABEL = "Optimize JS"
+T3_GENERAL_ASSETS_MINIFYJS_DESC = "Combined and compress Javascript files"
+T3_GENERAL_ASSETS_MINIFYJS_TOOL_LABEL = "JS Compress Tool"
+T3_GENERAL_ASSETS_MINIFYJS_TOOL_DESC = "Choose tool to compress Javascript"
+T3_GENERAL_ASSETS_MINIFYJS_TOOL_JSMIN = "JSMin"
+T3_GENERAL_ASSETS_MINIFYJS_TOOL_CLOSURE = "Closure Compiler"
+T3_GENERAL_ASSETS_MINIFYJS_EXCLUDE_LABEL = "Exclude files"
+T3_GENERAL_ASSETS_MINIFYJS_EXCLUDE_DESC = "Enter the file you DO NOT like to apply minify. Separated by a comma"
+
+T3_GENERAL_ASSETS_FOLDER_LABEL = "T3 Assets Folder"
+T3_GENERAL_ASSETS_FOLDER_DESC = "When Development Mode or Optimize CSS is set to ''YES'', T3 will join and compress most possible CSS files into one or serveral files for site performance. This folder must be writable. This folder is configured at your Joomla! root level"
+T3_GENERAL_REMOVE_T3LOGO_LABEL = "Show T3 Logo"
+T3_GENERAL_REMOVE_T3LOGO_DESC = "T3 logo in footer. We recommend you do this so that we can help spread T3 to the word"
+
+
+; JOOMLA CORE ENHANCEMENT
+T3_GENERAL_JCORE_LABEL = "Core Joomla!"
+T3_GENERAL_JCORE_DESC = "Enhance Core Joomla! options"
+T3_GENERAL_JCORE_LINKED_TITLES_LABEL= "Link Title for Article View"
+T3_GENERAL_JCORE_LINKED_TITLES_DESC = "Override setting for Link Title in Article View. This setting only applies for Single Article view."
+
+
+; THEME
+T3_THEME_LABEL = "Theme"
+T3_THEME_DESC = "The visual settings below are for themes of your selected style. You can always use the ThemeMagic tool located on the top-right panel for further advanced settings."
+T3_THEME_THEME_LABEL = "Theme"
+T3_THEME_THEME_DESC = "Select a theme"
+T3_THEME_LOGOTYPE_LABEL = "Logo Type"
+T3_THEME_LOGOTYPE_DESC = "Select image logo type or text logo type"
+T3_THEME_LOGOTYPE_TEXT = "Text"
+T3_THEME_LOGOTYPE_IMAGE = "Image"
+T3_THEME_SITENAME_LABEL = "Site Name"
+T3_THEME_SITENAME_DESC = "Site Name"
+T3_THEME_SITENAME_HINT = "Your site name goes here"
+T3_THEME_SLOGAN_LABEL = "Slogan"
+T3_THEME_SLOGAN_DESC = "Slogan"
+T3_THEME_SLOGAN_HINT = "Your slogan goes here"
+T3_THEME_LOGOIMAGE_LABEL = "Logo Image"
+T3_THEME_LOGOIMAGE_DESC = "Browse image to replace current logo image"
+T3_THEME_LOGOWIDTH_LABEL = "Logo Width"
+T3_THEME_LOGOWIDTH_DESC = "Logo Width"
+T3_THEME_LOGOHEIGHT_LABEL = "Logo Height"
+T3_THEME_LOGOHEIGHT_DESC = "Logo Height"
+
+T3_THEME_ENABLE_LOGOIMAGE_SM_LABEL ="Enable Small Logo"
+T3_THEME_ENABLE_LOGOIMAGE_SM_DESC ="Enable this option to allow select a new version logo for small screen"
+T3_THEME_LOGOIMAGE_SM_LABEL ="Small Logo Image"
+T3_THEME_LOGOIMAGE_SM_DESC ="Small Logo Image"
+
+; LAYOUT
+T3_LAYOUT_LABEL = "Layout"
+T3_LAYOUT_DESC = "Based on Bootstrap Grid , you can add up to 6 module positions to a spotlight area which can be resized by adjusting the resizer bar to the left/right. You can change the module position by clicking on the configuration icon on the top right."
+T3_LAYOUT_LAYOUT_LABEL = "Position & Responsive Configuration"
+T3_LAYOUT_LAYOUT_DESC = "Select a layout to be configured. Select the Positions that are going to be used in the above selected layout then configure the responsive layouts (enable, disable, change size module position in specific layouts)"
+T3_LAYOUT_CONFIG_TITLE = "Layout Configuration"
+T3_LAYOUT_CONFIG_DESC = "Layout Configuration"
+T3_LAYOUT_POPOVER_TITLE = "Select a position"
+T3_LAYOUT_POPOVER_DESC = ""
+T3_LAYOUT_RESPON_PTITLE = "Visibility"
+T3_LAYOUT_RESPON_PDESC = ""
+T3_LAYOUT_EMPTY_POSITION = "None"
+T3_LAYOUT_DEFAULT_POSITION = "Default"
+T3_LAYOUT_LOGO_TEXT = "Logo"
+T3_LAYOUT_UNKN_WIDTH = "Auto"
+T3_LAYOUT_POS_WIDTH = "Position Width"
+T3_LAYOUT_POS_NAME = "Position Name"
+T3_LAYOUT_MODE_STRUCTURE = "Module Positions"
+T3_LAYOUT_MODE_LAYOUT = "Responsive Layout"
+T3_LAYOUT_RESET_ALL = "Reset All"
+T3_LAYOUT_RESET_PER_DEVICE = "Reset layout for current device"
+T3_LAYOUT_RESET_POSITION = "Reset Positions"
+T3_LAYOUT_TOGG_FULLSCREEN = "Toggle Fullscreen"
+T3_LAYOUT_LOAD_ERROR = "The layout cannot be loaded. There might be some errors in the layout file."
+T3_LAYOUT_EDIT_POSITION = "Click here to edit position"
+T3_LAYOUT_SHOW_POSITION = "Click here to show this position on current device layout"
+T3_LAYOUT_HIDE_POSITION = "Click here to hide this position on current device layout"
+T3_LAYOUT_CHANGE_NUMPOS = "Click here to select number of positions you want to display"
+T3_LAYOUT_DRAG_RESIZE = "Drag me to resize"
+T3_LAYOUT_HIDDEN_POS_DESC = "Currently hidden positions on Spotlight"
+T3_LAYOUT_CUSTOM_POSITION = "Custom Position"
+
+T3_LAYOUT_DVI_DEFAULT = "Default"
+T3_LAYOUT_DVI_WIDE = "Wide"
+T3_LAYOUT_DVI_NORMAL = "Normal"
+T3_LAYOUT_DVI_XTABLET = "XTablet"
+T3_LAYOUT_DVI_TABLET = "Tablet"
+T3_LAYOUT_DVI_MOBILE = "Mobile"
+T3_LAYOUT_DVI_LG = "Large"
+T3_LAYOUT_DVI_MD = "Medium"
+T3_LAYOUT_DVI_SM = "Small"
+T3_LAYOUT_DVI_XS = "Extra Small"
+
+T3_LAYOUT_ASK_ADD_LAYOUT = "That’s awesome way to start customizing..."
+T3_LAYOUT_ASK_ADD_LAYOUT_DESC = "Give it a cool name, how about domain_layout ?"
+T3_LAYOUT_ASK_CORRECT_NAME = "Please enter alpha numeric name"
+T3_LAYOUT_ASK_DEL_LAYOUT = "Hmm, are you sure to do it?"
+T3_LAYOUT_ASK_DEL_LAYOUT_DESC = "Deleting a layout will remove the cloned layout file in {root}/templates/{template_name}/custom/tpls folder as well as the corresponding layout setting file .ini in {root}/templates/{template_name}/custom/etc/layout . You can delete cloned layout and user setting to keep thing neat and clean. To delete default layouts you must use Purge action. This action cannot be undone! "
+T3_LAYOUT_ASK_PURGE_LAYOUT_DESC = "Purging a layout will remove the .php layout file in both {root}/templates/{template_name}/tpls and {root}/templates/{template_name}/custom/tpls folder as well as the corresponding layout setting file .ini in {root}/templates/{template_name}/etc/layout and {root}/templates/{template_name}/custom/etc/layout . You can delete cloned layout to keep thing neat and clean. However, deleting default layouts is NOT recommended. This action cannot be undone! "
+T3_LAYOUT_INVALID_DATA_TO_SAVE = "Incorrect data format"
+T3_LAYOUT_OPERATION_FAILED = "Saving progress is failed. It might cause by file permission"
+T3_LAYOUT_SAVE_SUCCESSFULLY = "Layout changes has been saved successfully"
+T3_LAYOUT_NOT_FOUND = "The source layout does not found"
+T3_CUSTOM_LAYOUT_NOT_FOUND = "The source layout does not found"
+T3_LAYOUT_EXISTED = "New layout already exists"
+T3_LAYOUT_DELETE_FAIL = "Failed to delete layout"
+T3_LAYOUT_DELETE_SUCCESSFULLY = "Layout delete successfully"
+T3_LAYOUT_NO_PERMISSION = "You do not have permission to make change of theme"
+T3_LAYOUT_UNKNOW_ACTION = "Unknown request"
+T3_LAYOUT_LAYOUT_NAME = "Layout name"
+T3_LAYOUT_LABEL_CLONEIT = "Clone it!"
+T3_LAYOUT_LABEL_DELETEIT = "Got it! delete this layout!"
+T3_LAYOUT_LABEL_SAVE_AS_COPY = "Save as Copy"
+T3_LAYOUT_LABEL_DELETE = "Delete"
+T3_LAYOUT_LABEL_PURGE = "Purge"
+T3_LAYOUT_DESC_DELETE = "Remove cloned layout & setting"
+T3_LAYOUT_DESC_PURGE = "Remove both cloned and default layout"
+
+
+; NAVIGATION
+T3_NAVIGATION_LABEL = "Navigation"
+T3_NAVIGATION_DESC = "The tab includes settings of the Megamenu - a missing feature in Joomla!. With an intuitive configuration visualization, you can setup an advanced menu in a few clicks."
+T3_NAVIGATION_MEGAMENU_CONFIG = "Megamenu"
+T3_NAVIGATION_TRIGGER_LABEL = "Dropdown Trigger"
+T3_NAVIGATION_TRIGGER_DESC = "Mouse Event to trigger dropdown menu"
+T3_NAVIGATION_TRIG_HOVER = "Hover"
+T3_NAVIGATION_TRIG_CLICK = "Click"
+T3_NAVIGATION_ANIMATION_LABEL = "Animation"
+T3_NAVIGATION_ANIMATION_DESC = "Select animation for Megamenu"
+T3_NAVIGATION_ANIMATION_DURATION_LABEL = "Duration"
+T3_NAVIGATION_ANIMATION_DURATION_DESC = "Animation effect duration for dropdown of Megamenu (in miliseconds)"
+T3_NAVIGATION_COLLAPSE_OFFCANVAS = "Off-Canvas Navigation"
+T3_NAVIGATION_COLLAPSE_OFFCANVAS_DESC = "Enable Off-Canvas Navigation type for Collapsed menu on small screen"
+T3_NAVIGATION_COLLAPSE_LABEL = "Always show submenu"
+T3_NAVIGATION_COLLAPSE_DESC = "Always show submenu when collapse"
+
+T3_NAVIGATION_COLLAPSE_GROUP_LABEL = "Collapse navigation for small screens"
+T3_NAVIGATION_COLLAPSE_GROUP_DESC = "Enable default Bootstrap collapse navigation for main navigation on small screens. This option should be turned off if you want to use Off-canvas style for collapse navigation"
+T3_NAVIGATION_COLLAPSE_ENABLE_LABEL = "Enable"
+T3_NAVIGATION_COLLAPSE_ENABLE_DESC = "Enable collapsible navigation for Main navigation"
+
+T3_NAVIGATION_TYPE_LABEL = "Navigation Style"
+T3_NAVIGATION_BOOTSTRAP = "Bootstrap"
+T3_NAVIGATION_MEGAMENU = "Megamenu"
+T3_NAVIGATION_TYPE_DESC = "Joomla Module This is default Joomla menu system.Megamenu A new feature supported in T3 Framework (a missing feature in Joomla)."
+
+T3_NAVIGATION_MM_GROUP_LABEL = "Megamenu Configuration"
+T3_NAVIGATION_MM_GROUP_DESC = "Configuration for megamenu"
+T3_NAVIGATION_MM_ENABLE_LABEL = "Enable MegaMenu"
+T3_NAVIGATION_MM_ENABLE_DESC = "Enable or disable Megamenu"
+T3_NAVIGATION_MM_TYPE_LABEL = "Menu"
+T3_NAVIGATION_MM_TYPE_DESC = "Select a menu to configure Megamenu for the menu items in the selected menu."
+T3_NAVIGATION_ACL_LABEL = "Access"
+T3_NAVIGATION_ACL_DESC = "The access level group that allow to view menu"
+
+T3_NAVIGATION_SAVE_SUCCESSFULLY = "Configuration changes saved successfully"
+T3_NAVIGATION_SAVE_FAILED = "Configuration has not been saved"
+T3_NAVIGATION_DELETE_SUCCESSFULLY = "Configuration has been deleted successfully"
+T3_NAVIGATION_DELETE_FAILED = "Error!!! Can't delete the configuration"
+T3_NAVIGATION_ASK_DELETE = "Megamenu"
+T3_NAVIGATION_ASK_DELETE_DESC = "Are you sure you want to delete configuration?"
+T3_NAVIGATION_LABEL_DELETEIT = "Delete"
+
+T3_NAVIGATION_MM_TITLE = "Megamenu configuration"
+T3_NAVIGATION_MM_SUBMENU = "Submenu"
+T3_NAVIGATION_MM_SUBMENU_DESC = "Enable or disable submenus"
+T3_NAVIGATION_MM_GROUP = "Group"
+T3_NAVIGATION_MM_GROUP_DESC = "Enable Megamenu first then go to Megamenu setting panel to configure Megamenu"
+T3_NAVIGATION_MM_POSITIONS = "Positions"
+T3_NAVIGATION_MM_POSITIONS_DESC = "Move menu item to right or left column"
+T3_NAVIGATION_MM_EX_CLASS = "Extra Class"
+T3_NAVIGATION_MM_EX_CLASS_DESC = "Add extra class to style megamenu."
+T3_NAVIGATION_MM_ICON = "Icon"
+T3_NAVIGATION_MM_ICON_DESC = "Add Icon for Menu Item. Click Icon label to visit bootstrap icons page and get Icon Class. E.g.: [icon-search], [fa fa-home], [glyphicon glyphicon-heart],... without square brackets. Note: [fa] and [glyphicon] icons support by Bootstrap 3 base theme only"
+T3_NAVIGATION_MM_CAPTION = "Item caption"
+T3_NAVIGATION_MM_CAPTION_DESC = "Item caption"
+T3_NAVIGATION_MM_WIDTH_SPAN = "Width (1-12)"
+T3_NAVIGATION_MM_WIDTH_SPAN_DESC = "Add the appropriate number of span columns"
+T3_NAVIGATION_MM_MOVE_LEFT = "Move to Left Column"
+T3_NAVIGATION_MM_MOVE_RIGHT = "Move to Right Column"
+T3_NAVIGATION_MM_MODULE = "Module"
+T3_NAVIGATION_MM_MODULE_DESC = "Select module to place in MegaMenu"
+T3_NAVIGATION_MM_SELECT_MODULE = "Select Module"
+T3_NAVIGATION_MM_SAVE = "Save"
+T3_NAVIGATION_MM_RESET = "Reset"
+T3_NAVIGATION_MM_TOOLBOX = "Megamenu Toolbox"
+T3_NAVIGATION_MM_TOOLBOX_DESC = "This toolbox includes all settings of megamenu, just select menu then configure. There are 3 level of configuration: sub-megamenu setting, column setting and menu item setting."
+T3_NAVIGATION_MM_ITEM_CONF = "Item Configuration"
+T3_NAVIGATION_MM_SUBMNEU_CONF = "Submenu Configuration"
+T3_NAVIGATION_MM_COLUMN_CONF = "Column Configuration"
+T3_NAVIGATION_MM_ADD_REMOVE_COLUMN = "Add/remove Column"
+T3_NAVIGATION_MM_ADD_REMOVE_COLUMN_DESC = "Click to add a new column right after the column selection Click to remove the selected column"
+T3_NAVIGATION_MM_SUBMNEU_GRID = "Add row"
+T3_NAVIGATION_MM_SUBMNEU_GRID_DESC = "Add a new row to the selected submenu"
+T3_NAVIGATION_MM_SUBMNEU_WIDTH_PX = "Submenu Width (px)"
+T3_NAVIGATION_MM_SUBMNEU_WIDTH_PX_DESC = "Set submenu width(in pixel)"
+T3_NAVIGATION_MM_ALIGN = "Alignment"
+T3_NAVIGATION_MM_ALIGN_DESC = "Align submenu"
+T3_NAVIGATION_MM_ALIGN_LEFT = "Left"
+T3_NAVIGATION_MM_ALIGN_CENTER = "Center"
+T3_NAVIGATION_MM_ALIGN_RIGHT = "Right"
+T3_NAVIGATION_MM_ALIGN_JUSTIFY = "Justify"
+T3_NAVIGATION_MM_HIDE_COLLAPSE = "Hide when collapse"
+T3_NAVIGATION_MM_HIDE_COLLAPSE_DESC = "Hide this column when the menu is collapsed on small screen"
+T3_NAVIGATION_MM_LOADING = "Loading Menu..."
+
+; ASSIGNMENT
+T3_MENUS_ASSIGNMENT_LABEL = "Assignment"
+T3_MENUS_ASSIGNMENT_DESC = "Assign the current template style to the selected menu items that can be viewed by users."
+
+; THEMEMAGIC
+T3_TM_TITLE = "ThemeMagic"
+T3_TM_MINIMIZE = "Minimize"
+T3_TM_THEME_LABEL = "Theme"
+T3_TM_BACK_TO_ADMIN = "Back to Administrator"
+T3_TM_EXIT = "Exit ThemeMagic"
+T3_TM_CUSTOMIZING = "You are customizing:"
+T3_TM_PREVIEW = "Preview"
+T3_TM_SAVE = "Save"
+T3_TM_SAVEAS = "Save As"
+T3_TM_DELETE = "Delete"
+T3_TM_LABEL_OK = "Accept"
+T3_TM_THEME_MAGIC = "Theme magic"
+T3_TM_THEME_NAME = "Theme name"
+T3_TM_ASK_ADD_THEME = "Please enter new theme name"
+T3_TM_ASK_DEL_THEME = "Are you sure you want to delete this theme?"
+T3_TM_ASK_SAVE_CHANGED = "Theme %THEME% has been modified, save changes?"
+T3_TM_ASK_OVERWRITE_THEME = "Theme %THEME% already exists. Do you want to replace the existing file?"
+T3_TM_ASK_CORRECT_NAME = "Please enter alpha numeric name"
+T3_TM_UNKNOWN_THEME = "Unknown theme name"
+T3_TM_INVALID_DATA_TO_SAVE = "The data does not have correct format"
+T3_TM_OPERATION_FAILED = "Saving progress was failed. It might cause by file permission"
+T3_TM_SAVE_SUCCESSFULLY = "Theme changes saved successfully"
+T3_TM_NOT_FOUND = "The source theme was not found"
+T3_TM_EXISTED = "This theme already exists"
+T3_TM_CLONE_SUCCESSFULLY = "Theme cloned successfully"
+T3_TM_DELETE_FAIL = "Delete theme"
+T3_TM_DELETE_SUCCESSFULLY = "Theme deleted successfully"
+T3_TM_COMPILE_FAILED = "Theme complied unsucessfully"
+T3_TM_COMPILE_SUCCESS = "Theme compiled successfully"
+T3_TM_PLUGIN_NOT_READY = "T3 plugin is not ready"
+T3_TM_NO_PERMISSION = "You don't have permission to make change of theme"
+T3_TM_UNKNOW_ACTION = "Unknown request"
+T3_TM_PREVIEW_ERROR = "You have navigated to another page which using another template or your current preview page does not support LESS. ThemeMagic has been temporarily disabled."
+
+
+; GRID EXTENED
+T3_TM_GRID = "Grid"
+T3_TM_VARS_SCFD_WIDE_WIDTH_LABEL = "Wide Layout Width"
+T3_TM_VARS_SCFD_WIDE_WIDTH_DESC = "Wide Layout Width"
+T3_TM_VARS_SCFD_WIDE_GUTTER_LABEL = "Wide Gutter Width"
+T3_TM_VARS_SCFD_WIDE_GUTTER_DESC = "Wide Gutter Width"
+
+T3_TM_VARS_SCFD_NORMAL_WIDTH_LABEL = "Normal Layout Width"
+T3_TM_VARS_SCFD_NORMAL_WIDTH_DESC = "Normal Layout Width"
+T3_TM_VARS_SCFD_NORMAL_GUTTER_LABEL = "Normal Gutter Width"
+T3_TM_VARS_SCFD_NORMAL_GUTTER_DESC = "Normal Gutter Width"
+
+T3_TM_VARS_SCFD_XTABLET_WIDTH_LABEL = "XTablet Layout Width"
+T3_TM_VARS_SCFD_XTABLET_WIDTH_DESC = "XTablet Layout Width"
+T3_TM_VARS_SCFD_XTABLET_GUTTER_LABEL = "XTablet Gutter Width"
+T3_TM_VARS_SCFD_XTABLET_GUTTER_DESC = "XTablet Gutter Width"
+
+T3_TM_VARS_SCFD_TABLET_WIDTH_LABEL = "Tablet Layout Width"
+T3_TM_VARS_SCFD_TABLET_WIDTH_DESC = "Tablet Layout Width"
+T3_TM_VARS_SCFD_TABLET_GUTTER_LABEL = "Tablet Gutter Width"
+T3_TM_VARS_SCFD_TABLET_GUTTER_DESC = "Tablet Gutter Width"
+
+T3_TM_VARS_SCFD_LG_WIDTH_LABEL = "Large Desktop Width"
+T3_TM_VARS_SCFD_LG_WIDTH_DESC = "Large Desktop Width"
+
+T3_TM_VARS_SCFD_MID_WIDTH_LABEL = "Desktop Width"
+T3_TM_VARS_SCFD_MID_WIDTH_DESC = "Desktop Width"
+
+T3_TM_VARS_SCFD_SM_WIDTH_LABEL = "Tablet Width"
+T3_TM_VARS_SCFD_SM_WIDTH_DESC = "Tablet Width"
+
+
+; SCAFFOLDING
+T3_TM_SCAFFOLDING = "Scaffolding"
+T3_TM_VARS_BODY_BKG_LABEL = "Background Color"
+T3_TM_VARS_BODY_BKG_DESC = "Background Color"
+T3_TM_VARS_TEXT_COLOR_LABEL = "Text Color"
+T3_TM_VARS_TEXT_COLOR_DESC = "Text Color"
+T3_TM_VARS_LINK_COLOR_LABEL = "Link Color"
+T3_TM_VARS_LINK_COLOR_DESC = "Link Color"
+
+; VISUAL
+T3_TM_VISUAL = "Visual"
+T3_TM_VARS_ELEMENT_RADIUS_LABEL = "Elements Radius"
+T3_TM_VARS_ELEMENT_RADIUS_DESC = "Elements Radius"
+T3_TM_VARS_NAVBAR_INVERTED_LABEL = "Navbar Inverted"
+T3_TM_VARS_NAVBAR_INVERTED_LDESC = "Navbar Inverted"
+T3_TM_VARS_SPOTLIGHT_INVERTED_LABEL = "Spotlight Inverted"
+T3_TM_VARS_SPOTLIGHT_INVERTED_DESC = "Spotlight Inverted"
+T3_TM_VARS_HIDE_SLOGAN_LABEL = "Hide Slogan"
+T3_TM_VARS_HIDE_SLOGAN_DESC = "Hide Slogan"
+
+; MODULE
+T3_TM_MODULE = "Module"
+T3_TM_VARS_MODULE_BGCOLOR_LABEL = "Module Background Color"
+T3_TM_VARS_MODULE_BGCOLOR_DESC = "Module Background Color"
+T3_TM_VARS_MODULE_COLOR_LABEL = "Module Text Color"
+T3_TM_VARS_MODULE_COLOR_DESC = "Module Text Color"
+T3_TM_VARS_MODULE_TITLE_BGCOLOR_LABEL = "Module Title Background Color"
+T3_TM_VARS_MODULE_TITLE_BGCOLOR_DESC = "Module Title Background Color"
+T3_TM_VARS_MODULE_TITLE_COLOR_LABEL = "Module Title Text Color"
+T3_TM_VARS_MODULE_TITLE_COLOR_DESC = "Module Title Text Color"
+
+; SPOTLIGHTS
+T3_TM_SPOTLIGHTS = "Spotlights"
+T3_TM_VARS_INVERT_SPOTLIGHT_LABEL = "Use 'inverted' spotlights"
+T3_TM_VARS_INVERT_SPOTLIGHT_DESC = "Use 'inverted' spotlights"
+
+; TYPO
+T3_TM_TYPO = "Typo"
+T3_TM_VARS_FONTSIZE_LABEL = "Font Size"
+T3_TM_VARS_FONTSIZE_DESC = "Font Size"
+
+T3_TM_VARS_FONTFAMILY_LABEL = "Font Family"
+T3_TM_VARS_FONTFAMILY_DESC = "Font Family"
+T3_TM_VARS_FONTFAMILY_SERIF = "Serif"
+T3_TM_VARS_FONTFAMILY_SANS_SERIF = "Sans Serif"
+T3_TM_VARS_FONTFAMILY_MONOSPACE = "Monospace"
+T3_TM_VARS_HEADINGFONTFAMILY_LABEL = "Heading Font Family"
+T3_TM_VARS_HEADINGFONTFAMILY_DESC = "Heading Font Family"
+
+T3_TM_VARS_FONTFAMILY_CUSTOM = "Custom Font"
+T3_TM_VARS_FONTFAMILY_CUSTOM_LABEL = "Custom Font"
+T3_TM_VARS_FONTFAMILY_CUSTOM_DESC = "Example: 'Segoe UI', Arial, sans-serif. If you need load external font, go to tab Advanced and put your font urls in External CSS Urls param"
+
+;ADVANCED
+T3_TM_ADVANCED = "Advanced"
+T3_TM_VARS_IMPORT_EXTERNAL_URLS_LABEL = "External CSS Urls"
+T3_TM_VARS_IMPORT_EXTERNAL_URLS_DESC = "List external css urls here to import. It's usefull to load web fonts such as Google Fonts. List each url in a line"
+
+
+; INJECTION
+T3_INJECTION_LABEL = "Custom Code"
+T3_INJECTION_DESC = "Add custom code to some special positions of webpage. Those markup will not filter. Please be careful when copy code from other websites."
+T3_INJECTION_OPEN_HEAD_LABEL = "After <head>"
+T3_INJECTION_OPEN_HEAD_DESC = "Add custom code right after open <head> tag"
+T3_INJECTION_CLOSE_HEAD_LABEL = "Before </head>"
+T3_INJECTION_CLOSE_HEAD_DESC = "Add custom code before closing </head> tag"
+T3_INJECTION_OPEN_BODY_LABEL = "After <body>"
+T3_INJECTION_OPEN_BODY_DESC = "Add custom code right after open <body> tag"
+T3_INJECTION_CLOSE_BODY_LABEL = "Before </body>"
+T3_INJECTION_CLOSE_BODY_DESC = "Add custom code before closing </body> tag"
+T3_INJECTION_DEBUG_LABEL = "Show debug module position"
+T3_INJECTION_DEBUG_DESC = "Add modules in debug position before closing </body> tag"
+
+
+; TOUR GUIDE
+T3_TOUR_INTRO_1 = "Welcome to T3!"
+T3_TOUR_INTRO_2 = "Are you ready to discover the best framework for Joomla! yet? Click the buttons below to start your travel and having fun!"
+T3_TOUR_CTRL_START = "Start the tour!"
+T3_TOUR_CTRL_END = "End"
+T3_TOUR_CTRL_NEXT = "Next"
+T3_TOUR_CTRL_PREV = "Prev"
+
+T3_TOUR_INTRO_FIRST = "Welcome to T3! Are you ready to discover the best framework for Joomla! yet? Click the buttons below to start your travel and having fun!
"
+T3_TOUR_INTRO_TOUR1 = "The settings are applied for all themes, layouts. Setting included in the tab: enable or disable development mode, responsive and ThemeMagic feature."
+T3_TOUR_INTRO_TOUR2 = "The settings in the tab is also included in the ThemeMagic. The settings allow you to select default theme for the style and change logo if you wish."
+T3_TOUR_INTRO_TOUR3 = "JA T3 comes with multiple layouts, in the layout setting, it allows to configure/customize the layout you wish to use in each style. Each layout contains number of block, and each block includes one or many module positions."
+T3_TOUR_INTRO_TOUR4 = "The tab includes settings of the Megamenu - a missing feature in Joomla!. With Megamenu, you can create any type of menu that your site needs."
+T3_TOUR_INTRO_TOUR5 = "The settings let you override template. In your site, you can use multiple styles simultaneously, each style is applied in specific menus. The menus that are assigned in settings of style A will override the same menus in default style."
+
+T3_TOUR_GUIDE_1_TITLE = "Compile LESS to CSS"
+T3_TOUR_GUIDE_1_CONTENT = " Feel free to enable the option when you are in development mode. This option will allow you to compile LESS to CSS. Whatever changes in your customization for the LESS files will then be compiled to the corresponding CSS files, which are the actual files that get your site running on.
"
+T3_TOUR_GUIDE_2_TITLE = "ThemeMagic"
+T3_TOUR_GUIDE_2_CONTENT = " ThemeMagic is the visual customization. It includes multiple parameters which allow you to customize as you wish. The changes in the front-end are displayed on the right panel.
"
+T3_TOUR_GUIDE_3_TITLE = "Select Style to Edit"
+T3_TOUR_GUIDE_3_CONTENT = " You can use this option to quickly select style for customization.
"
+T3_TOUR_GUIDE_4_TITLE = "Language of current style"
+T3_TOUR_GUIDE_4_CONTENT = "Select the language that you wish to set as default if your site is multilingual. If your site is in a single language only, this field will be disabled."
+T3_TOUR_GUIDE_5_TITLE = "Template version and update"
+T3_TOUR_GUIDE_5_CONTENT = "To check out whether or not your T3 Blank template is up to date, simply click on the button and get the status. If it's not up to the latest version, no worry, you can get the upgrade for free."
+T3_TOUR_GUIDE_6_TITLE = "FrameWork version and update"
+T3_TOUR_GUIDE_6_CONTENT = "This button allows you to: Check and Update the latest version of framework in case yours are not up to date. "
+T3_TOUR_GUIDE_7_TITLE = "Global Settings"
+T3_TOUR_GUIDE_7_CONTENT = " The settings are applied for all styles, themes, layouts. Setting included in the tab: enable or disable development mode, responsive and ThemeMagic feature.
"
+T3_TOUR_GUIDE_8_TITLE = "Development mode"
+T3_TOUR_GUIDE_8_CONTENT = "Please enable this option when you are in development mode. It should be turned off if you are not developing your site so that your site speed is better."
+T3_TOUR_GUIDE_9_TITLE = "Enable ThemeMagic"
+T3_TOUR_GUIDE_9_CONTENT = "If you want to use ThemeMagic to customize your theme, you gotta have to enable the ThemeMagic first.
Click on the ThemeMagic to go to the ThemeMagic configuration panel.
"
+T3_TOUR_GUIDE_10_TITLE = "Enable or Disable responsive"
+T3_TOUR_GUIDE_10_CONTENT = "T3 allows you to enable responsive feature or not. If you select No, your site is a non-responsive website."
+T3_TOUR_GUIDE_11_TITLE = "Theme Settings"
+T3_TOUR_GUIDE_11_CONTENT = " The settings in the tab are also included in the ThemeMagic. The settings allow you to select default theme for the style and change logo if you wish.
"
+T3_TOUR_GUIDE_12_TITLE = "Select theme for current style"
+T3_TOUR_GUIDE_12_CONTENT = " T3 supports multiple Themes, select the Theme you want to apply for the style then customize it as you wish.
"
+T3_TOUR_GUIDE_13_TITLE = "Logo Setting"
+T3_TOUR_GUIDE_13_CONTENT = " You can use either image or text logo type. To change your current logo, just select a new logo image, it will automatically replace the current logo. Note that this settings can be configured in the ThemeMagic as well.
"
+T3_TOUR_GUIDE_14_TITLE = "Layout Settings"
+T3_TOUR_GUIDE_14_CONTENT = " JA T3 comes with multiple layouts, in the layout setting, it allows to configure/customize the layout you wish to use in each style. Each layout contains number of block, and each block includes one or many module positions.
"
+T3_TOUR_GUIDE_15_TITLE = "Assign layout to current style"
+T3_TOUR_GUIDE_15_CONTENT = " From the multiple layouts, select the one that the style uses. You can easily customize the layout using the Layout Configuration below.
"
+T3_TOUR_GUIDE_16_TITLE = ""
+T3_TOUR_GUIDE_16_CONTENT = ""
+T3_TOUR_GUIDE_17_TITLE = "MegaMenu Settings"
+T3_TOUR_GUIDE_17_CONTENT = "The tab includes settings of the Megamenu - a missing feature in Joomla!. With Megamenu, you can create any type of menu that your site needs."
+T3_TOUR_GUIDE_18_TITLE = "Enable or disable MegaMenu"
+T3_TOUR_GUIDE_18_CONTENT = "If you only want to use Joomla! menu system, just turn it off"
+T3_TOUR_GUIDE_19_TITLE = "Menu Assignment"
+T3_TOUR_GUIDE_19_CONTENT = "The settings let you override template. In your site, you can use multiple styles simultaneously, each style is applied in specific menus. The menus that are assigned in settings of style A will override the same menus in default style.
"
+T3_TOUR_GUIDE_20_TITLE = "Module Positions Setting"
+T3_TOUR_GUIDE_20_CONTENT = "Using the button to assign module position to the block.
You can set the number of module positions for a spotlight block.
"
+T3_TOUR_GUIDE_21_TITLE = "Module Positions"
+T3_TOUR_GUIDE_21_CONTENT = "Select the positions that are going to be used in the above selected layout. In other words, this will allow you to freely configure which content to be displayed in that specific selected layout according to your preferences."
+T3_TOUR_GUIDE_22_TITLE = "Responsive Layout"
+T3_TOUR_GUIDE_22_CONTENT = "In this setting panel, you can enable/disable and resize the module positions for the spotlight blocks only for each specific layout: wide, mobile, tablet, etc.
"
+T3_TOUR_GUIDE_23_TITLE = "Layouts Configuration"
+T3_TOUR_GUIDE_23_CONTENT = "Using the icon to enable/disable the module position for the spotlight block in the current layout.
Drag to resize the module position (basegrid: 12). Please do keep in mind that it is applied in the current modifying layout only and not applied to all unless you make changes in each layout accordingly.
"
+T3_TOUR_GUIDE_25_TITLE = "Navigation Configuration"
+T3_TOUR_GUIDE_25_CONTENT = "This place let you set the behavior of the main navigation bar. It also let you choose a cool feature of T3 - Megamenu and its options.
"
+T3_TOUR_GUIDE_26_TITLE = "Option to open sub-menu"
+T3_TOUR_GUIDE_26_CONTENT = "You can select to display sub-menu when hovering or clicking on its parent menu."
+T3_TOUR_GUIDE_27_TITLE = "Select Menu"
+T3_TOUR_GUIDE_27_CONTENT = "Select menu for current style, each style can be assigned different menu."
+T3_TOUR_GUIDE_28_TITLE = "Enable Megamenu"
+T3_TOUR_GUIDE_28_CONTENT = "Enable this option so that Megamenu will be active in this style. After enable this option, go to Megamenu setting panel to configure megamenu.
"
+T3_TOUR_GUIDE_29_TITLE = "Collapse menu in small screens"
+T3_TOUR_GUIDE_29_CONTENT = "Enable this option to use default Bootstrap navigation (dropdown menu style) on small screens like iPhone, tablet
"
+T3_TOUR_GUIDE_30_TITLE = "Custom Code"
+T3_TOUR_GUIDE_30_CONTENT = "Thinking of a way to add-in a custom code after and before the special tags (such as <head></head>, <body>></body>)? Worry free, we have your back!"
+T3_TOUR_GUIDE_31_TITLE = "Megamenu Configuration"
+T3_TOUR_GUIDE_31_CONTENT = "We provide you a huge canvas for to focus on configuring your Megamenu. This feature is what Joomla is lacking of and gurantee to change your classic navigation system experience.
"
+T3_TOUR_GUIDE_32_TITLE = "Add-ons Configuration"
+T3_TOUR_GUIDE_32_CONTENT = "This tab will include the add-ons. Right now, it has configurations for Off-Canvas sidebar.
"
+T3_TOUR_GUIDE_33_TITLE = "Build CSS for RTL"
+T3_TOUR_GUIDE_33_CONTENT = "If you use RTL language layout, when compile LESS to CSS, you need to enable this option so that it will build CSS for RTL.
"
+
+
+T3_TOUR_GUIDE_DISMISS_1 = "Dismiss"
+T3_TOUR_GUIDE_DISMISS_2 = "Ok, got it!"
+T3_TOUR_GUIDE_DISMISS_3 = "Roger"
+T3_TOUR_GUIDE_DISMISS_4 = "Cool!"
+T3_TOUR_GUIDE_DISMISS_5 = "Thanks, that's Awesome"
+T3_TOUR_GUIDE_DISMISS_6 = "Got it dude!"
+T3_TOUR_QUICK_HELP = "Click here to get more help"
+
+
+; MISC
+T3_TOOLBAR_SAVE = "Save"
+T3_TOOLBAR_SAVECLOSE = "Save & Close"
+T3_TOOLBAR_SAVE_AS_CLONE = "Save as Copy"
+T3_TOOLBAR_COMPILE_LESS_CSS = "LESS to CSS"
+T3_TOOLBAR_COMPILE_LESS_CSS_DESC = "Compile LESS to CSS"
+T3_TOOLBAR_COMPILE_THIS = "[%s] theme only"
+T3_TOOLBAR_COMPILE_THIS_DESC = "Compile the theme for current template style only"
+T3_TOOLBAR_THEMER = "ThemeMagic"
+T3_TOOLBAR_THEMER_DESC = "ThemeMagic"
+T3_TOOLBAR_COPY = "Copy"
+T3_TOOLBAR_CLOSE = "Close"
+T3_TOOLBAR_DELETE = "Delete"
+T3_TOOLBAR_HELP = "Help"
+T3_TOOLBAR_MEGAMENU = "Megamenu"
+T3_TOOLBAR_MEGAMENU_DESC = "Go to Megamenu configuration page"
+
+T3_SELECT_STYLE_LABEL = "Current Style"
+T3_SELECT_STYLE_DESC = "Select a style from T3 template to customize"
+T3_LBL_OK = "Ok"
+T3_LBL_VIEWTHEMER = "ThemeMagic"
+
+T3_MSG_PLUGIN_NOT_READY = "T3 Framework is not ready"
+T3_MSG_FAILED_INIT_BASE = "Base theme is not ready"
+T3_MSG_COMPILE_SUCCESS = "Successfully compile LESS to CSS"
+T3_MSG_COMPILE_FAILURE = "Compile LESS to CSS failed %s
"
+T3_MSG_UNKNOWN_ERROR = "Unexpected error. Please refresh the page try again later."
+T3_MSG_NO_PERMISSION = "You does have permission to make change of theme"
+T3_MSG_UNKNOW_ACTION = "Unknown request"
+T3_MSG_ENABLE_THEMEMAGIC = "Please enable ThemeMagic Mode in General tab first"
+T3_MSG_MEGAMENU_NOT_USED = "This will direct you to the Megamenu Configuration page. However, you have chosen using the Joomla Module over Megamenu, hence the Megamenu Configuration is not necessary in this case. Please click again to continue!"
+T3_MSG_WARNING = "Warning!"
+T3_MSG_FILE_NOT_WRITABLE = "File system Not writable. Please check again server file permission."
+T3_MSG_PACKAGE_DAMAGED = "The framework has not been installed correctly"
+T3_MSG_DEVFOLDER_NOT_WRITABLE = "Cannot create css cached file in development folder: %s"
+T3_MSG_LESS_NOT_VALID = "Template Less structure was not compatible with T3 compiler"
+T3_MSG_MODULE_NOT_AVAIL = "This module might not available with current Access Level"
+T3_MSG_CANNOT_DETECT_TEMPLATE = "Cannot detect current T3 template"
+T3_MSG_SWITCH_RESPONSIVE_MODE = "Please save the config then re-build LESS to CSS to enable/disable Responsive mode"
+
+
+; ADDON
+T3_ADDON_LABEL = "Add-ons"
+T3_ADDON_DESC = "Built-in Add-ons for T3 Framework"
+T3_ADDON_OFFCANVAS_GROUP_LABEL = "Off-canvas Sidebar"
+T3_ADDON_OFFCANVAS_GROUP_DESC = "Enable off-canvas sidebar then select effect for the Off-canvas sidebar."
+T3_ADDON_OFFCANVAS_ENABLE_LABEL = "Enable"
+T3_ADDON_OFFCANVAS_ENABLE_DESC = "Enable to load off-canvas library"
+T3_ADDON_OFFCANVAS_EFFECT_LABEL = "Off-Canvas Effect"
+T3_ADDON_OFFCANVAS_EFFECT_DESC = "Sidebar transition effect for Off-canvas menu"
+T3_ADDON_OFFCANVAS_EFFECT_1 = "Slide in on top"
+T3_ADDON_OFFCANVAS_EFFECT_2 = "Reveal"
+T3_ADDON_OFFCANVAS_EFFECT_3 = "Push"
+T3_ADDON_OFFCANVAS_EFFECT_4 = "Slide along"
+T3_ADDON_OFFCANVAS_EFFECT_5 = "Reverse slide out"
+T3_ADDON_OFFCANVAS_EFFECT_6 = "Rotate pusher"
+T3_ADDON_OFFCANVAS_EFFECT_7 = "3D rotate in"
+T3_ADDON_OFFCANVAS_EFFECT_8 = "3D rotate out"
+T3_ADDON_OFFCANVAS_EFFECT_9 = "Scale down pusher"
+T3_ADDON_OFFCANVAS_EFFECT_10 = "Scale up"
+T3_ADDON_OFFCANVAS_EFFECT_11 = "Scale & Rotate pusher"
+T3_ADDON_OFFCANVAS_EFFECT_12 = "Open door"
+T3_ADDON_OFFCANVAS_EFFECT_13 = "Fall down"
+T3_ADDON_OFFCANVAS_EFFECT_14 = "Delayed 3D rotate"
+
+; ADDON - Extras
+T3_ADDON_THEME_EXTRAS_LABEL = "Template Extended styles"
+T3_ADDON_THEME_EXTRAS_DESC = "This allow you load extra style file for the selected menu items"
+T3_ADDON_THEME_EXTRAS_ALL = "All pages"
+T3_ADDON_THEME_EXTRAS_NONE = "Not use"
+
+; Extra fields
+T3_EXTRA_FIELDS_GROUP_LABEL = "Extra Fields"
+T3_EXTRA_FIELDS_GROUP_DESC = "Extend Article's fields for current category"
+T3_EXTRA_FIELDS_LABEL = "Extra Fields Group"
+T3_EXTRA_FIELDS_DESC = "Select the extra fields group for extend those articles in this category"
\ No newline at end of file
diff --git a/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.j25.compat.ini b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.j25.compat.ini
new file mode 100644
index 0000000..4353feb
--- /dev/null
+++ b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.j25.compat.ini
@@ -0,0 +1 @@
+JGLOBAL_HITS_COUNT="Hits: %s"
\ No newline at end of file
diff --git a/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.sys.ini b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.sys.ini
new file mode 100644
index 0000000..dfd6384
--- /dev/null
+++ b/plugins/system/t3/language/en-GB/en-GB.plg_system_t3.sys.ini
@@ -0,0 +1 @@
+PLG_T3_XML_DESCRIPTION="T3 Framework plugin"
\ No newline at end of file
diff --git a/plugins/system/t3/t3.php b/plugins/system/t3/t3.php
new file mode 100644
index 0000000..3c59804
--- /dev/null
+++ b/plugins/system/t3/t3.php
@@ -0,0 +1,375 @@
+isAdmin()) {
+ return;
+ }
+
+ $input = $app->input;
+
+ if($input->getCmd('themer', 0) && ($t3tmid = $input->getCmd('t3tmid', 0))){
+ $user = JFactory::getUser();
+
+ if($t3tmid > 0 && ($user->authorise('core.manage', 'com_templates') ||
+ (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], JUri::base()) !== false))){
+
+ $current = T3::getDefaultTemplate();
+ if(!$current || ($current->id != $t3tmid)){
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query
+ ->select('home, template, params')
+ ->from('`#__template_styles`')
+ ->where('`client_id` = 0 AND `id`= ' . (int)$t3tmid)
+ ->order('`id` ASC');
+ $db->setQuery($query);
+ $tm = $db->loadObject();
+
+ if (is_object($tm) && file_exists(JPATH_THEMES . '/' . $tm->template)) {
+
+ $app->setTemplate($tm->template, (new JRegistry($tm->params)));
+ // setTemplate is buggy, we need to update more info
+ // update the template
+ $template = $app->getTemplate(true);
+ $template->id = $t3tmid;
+ $template->home = $tm->template;
+ }
+ }
+ }
+ }
+ }
+
+ function onAfterRoute()
+ {
+ if(defined('T3_PLUGIN')){
+
+ T3Bot::preload();
+ $template = T3::detect();
+
+ if ($template) {
+
+ // load the language
+ $this->loadLanguage();
+
+ T3Bot::beforeInit();
+ T3::init($template);
+ T3Bot::afterInit();
+
+ //load T3 plugins
+ JPluginHelper::importPlugin('t3');
+
+ if (is_file(T3_TEMPLATE_PATH . '/templateHook.php')) {
+ include_once T3_TEMPLATE_PATH . '/templateHook.php';
+ }
+
+ $tplHookCls = preg_replace('/(^[^A-Z_]+|[^A-Z0-9_])/i', '', T3_TEMPLATE . 'Hook');
+ $dispatcher = JDispatcher::getInstance();
+
+ if (class_exists($tplHookCls)) {
+ new $tplHookCls($dispatcher, array());
+ }
+
+ $dispatcher->trigger('onT3Init');
+
+ //check and execute the t3action
+ T3::checkAction();
+
+ //check and change template for ajax
+ T3::checkAjax();
+ }
+ }
+ }
+
+ function onBeforeRender()
+ {
+ if (defined('T3_PLUGIN') && T3::detect()) {
+ $japp = JFactory::getApplication();
+
+ JDispatcher::getInstance()->trigger('onT3BeforeRender');
+
+ if ($japp->isAdmin()) {
+
+ $t3app = T3::getApp();
+ $t3app->addAssets();
+ } else {
+ $params = $japp->getTemplate(true)->params;
+ if (defined('T3_THEMER') && $params->get('themermode', 1)) {
+ T3::import('admin/theme');
+ T3AdminTheme::addAssets();
+ }
+
+ //check for ajax action and render t3ajax type to before head type
+ if (class_exists('T3Ajax')) {
+ T3Ajax::render();
+ }
+ }
+ }
+ }
+
+ function onBeforeCompileHead()
+ {
+ if (defined('T3_PLUGIN') && T3::detect() && !JFactory::getApplication()->isAdmin()) {
+ // call update head for replace css to less if in devmode
+ $t3app = T3::getApp();
+ if ($t3app) {
+
+ JDispatcher::getInstance()->trigger('onT3BeforeCompileHead');
+
+ $t3app->updateHead();
+
+ JDispatcher::getInstance()->trigger('onT3AfterCompileHead');
+ }
+ }
+ }
+
+ function onAfterRender()
+ {
+ if (defined('T3_PLUGIN') && T3::detect()) {
+ $t3app = T3::getApp();
+
+ if ($t3app) {
+
+ if (JFactory::getApplication()->isAdmin()) {
+ $t3app->render();
+ } else {
+ $t3app->snippet();
+ }
+
+ JDispatcher::getInstance()->trigger('onT3AfterRender');
+ }
+ }
+ }
+
+ /**
+ * Add JA Extended menu parameter in administrator
+ *
+ * @param JForm $form The form to be altered.
+ * @param array $data The associated data for the form
+ *
+ * @return null
+ */
+ function onContentPrepareForm($form, $data)
+ {
+
+ if(defined('T3_PLUGIN')){
+ if (T3::detect() && (
+ $form->getName() == 'com_templates.style'
+ || $form->getName() == 'com_config.templates'
+ )) {
+
+ $_form = clone $form;
+ $_form->loadFile(T3_PATH . '/params/template.xml', false);
+ //custom config in custom/etc/assets.xml
+ $cusXml = T3Path::getPath ('etc/assets.xml');
+ if ($cusXml && file_exists($cusXml))
+ $_form->loadFile($cusXml, true, '//config');
+
+ // extend parameters
+ T3Bot::prepareForm($form);
+
+ //search for global parameters and store in user state
+ $app = JFactory::getApplication();
+ $gparams = array();
+ foreach($_form->getGroup('params') as $param){
+ if($_form->getFieldAttribute($param->fieldname, 'global', 0, 'params')){
+ $gparams[] = $param->fieldname;
+ }
+ }
+ $this->gparams = $gparams;
+ }
+
+ $tmpl = T3::detect() ? T3::detect() : (T3::getDefaultTemplate(true) ? T3::getDefaultTemplate(true) : false);
+
+ if ($tmpl) {
+ $tplpath = JPATH_ROOT . '/templates/' . (is_object($tmpl) && !empty($tmpl->tplname) ? $tmpl->tplname : $tmpl);
+ $formpath = $tplpath . '/etc/form/';
+ JForm::addFormPath($formpath);
+
+ $extended = $formpath . $form->getName() . '.xml';
+ if (is_file($extended)) {
+ JFactory::getLanguage()->load('tpl_' . $tmpl, JPATH_SITE);
+ $form->loadFile($form->getName(), false);
+ }
+
+ // load extra fields for specified module in format com_modules.module.module_name.xml
+ if ($form->getName() == 'com_modules.module') {
+ $module = isset($data->module) ? $data->module : '';
+ if (!$module) {
+ $jform = JFactory::getApplication()->input->get ("jform", null, 'array');
+ $module = $jform['module'];
+ }
+ $extended = $formpath . $module . '.xml';
+ if (is_file($extended)) {
+ JFactory::getLanguage()->load('tpl_' . $tmpl, JPATH_SITE);
+ $form->loadFile($module, false);
+ }
+ }
+
+ //extend extra fields
+ T3Bot::extraFields($form, $data, $tplpath);
+ }
+ }
+ }
+
+ function onExtensionAfterSave($option, $data)
+ {
+ if (defined('T3_PLUGIN') && T3::detect() && $option == 'com_templates.style' && !empty($data->id)) {
+ //get new params value
+ $japp = JFactory::getApplication();
+ $params = new JRegistry;
+ $params->loadString($data->params);
+ //if we have any changed, we will update to global
+ if (isset($this->gparams) && count($this->gparams)) {
+
+ //get all other styles that have the same template
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query
+ ->select('*')
+ ->from('#__template_styles')
+ ->where('template=' . $db->quote($data->template));
+
+ $db->setQuery($query);
+ $themes = $db->loadObjectList();
+
+ //update all global parameters
+ foreach ($themes as $theme) {
+ $registry = new JRegistry;
+ $registry->loadString($theme->params);
+
+ foreach ($this->gparams as $pname) {
+ $registry->set($pname, $params->get($pname)); //overwrite with new value
+ }
+
+ $query = $db->getQuery(true);
+ $query
+ ->update('#__template_styles')
+ ->set('params =' . $db->quote($registry->toString()))
+ ->where('id =' . (int)$theme->id)
+ ->where('id <>' . (int)$data->id);
+
+ $db->setQuery($query);
+ $db->execute();
+ }
+ }
+ }
+ }
+
+ /**
+ * Implement event onRenderModule to include the module chrome provide by T3
+ * This event is fired by overriding ModuleHelper class
+ * Return false for continueing render module
+ *
+ * @param object &$module A module object.
+ * @param array $attribs An array of attributes for the module (probably from the XML).
+ *
+ * @return bool
+ */
+ function onRenderModule(&$module, $attribs)
+ {
+ static $chromed = false;
+ // Detect layout path in T3 themes
+ if (defined('T3_PLUGIN') && T3::detect()) {
+
+ // fix JA Backlink
+ if($module->module == 'mod_footer'){
+ $module->content = T3::fixJALink($module->content);
+ }
+
+ // Chrome for module
+ if (!$chromed) {
+ $chromed = true;
+ // We don't need chrome multi times
+ $chromePath = T3Path::getPath('html/modules.php');
+ if (file_exists($chromePath)) {
+ include_once $chromePath;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Implement event onGetLayoutPath to return the layout which override by T3 & T3 templates
+ * This event is fired by overriding ModuleHelper class
+ * Return path to layout if found, false if not
+ *
+ * @param string $module The name of the module
+ * @param string $layout The name of the module layout. If alternative
+ * layout, in the form template:filename.
+ *
+ * @return null
+ */
+ function onGetLayoutPath($module, $layout)
+ {
+ // Detect layout path in T3 themes
+ if (defined('T3_PLUGIN') && T3::detect()) {
+
+ T3::import('core/path');
+
+ $tPath = T3Path::getPath('html/' . $module . '/' . $layout . '.php');
+ if ($tPath) {
+ return $tPath;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Update params before rendering content
+ *
+ * @param string $context The context of the content being passed to the plugin.
+ * @param object &$article The article object. Note $article->text is also available
+ * @param mixed &$params The article params
+ * @param integer $page The 'page' number
+ *
+ * @return mixed true if there is an error. Void otherwise.
+ *
+ * @since 1.6
+ */
+ public function onContentPrepare ($context, &$article, &$params, $page = 0) {
+ // update params for Article View
+ if ($context == 'com_content.article') {
+ $app = JFactory::getApplication();
+ $tmpl = $app->getTemplate(true);
+ if ($tmpl->params->get('link_titles') !== NULL) {
+ if (isset($article->params) && is_object($article->params)) $article->params->set('link_titles', $tmpl->params->get('link_titles'));
+ }
+ }
+ }
+}
diff --git a/plugins/system/t3/t3.script.php b/plugins/system/t3/t3.script.php
new file mode 100644
index 0000000..33512a7
--- /dev/null
+++ b/plugins/system/t3/t3.script.php
@@ -0,0 +1,38 @@
+getQuery(true);
+ $query
+ ->update('#__extensions')
+ ->set("`enabled`='1'")
+ ->where("`type`='plugin'")
+ ->where("`folder`='system'")
+ ->where("`element`='t3'");
+ $db->setQuery($query);
+ $db->execute();
+
+ return true;
+ }
+}
diff --git a/plugins/system/t3/t3.xml b/plugins/system/t3/t3.xml
new file mode 100644
index 0000000..b3042f8
--- /dev/null
+++ b/plugins/system/t3/t3.xml
@@ -0,0 +1,46 @@
+
+
+ T3 Framework
+ JoomlArt.com
+ Dec 23, 2014
+ Copyright (C) 2005 - 2013 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ info@joomlart.com
+ http://www.t3-framework.org
+ 2.4.2
+
+
+
+
+
+ ]]>
+
+
t3.script.php
+
+ t3.php
+ index.html
+ admin
+ base
+ base-bs3
+ includes
+ language
+
+
+ en-GB/en-GB.plg_system_t3.ini
+ en-GB/en-GB.plg_system_t3.sys.ini
+ en-GB/en-GB.plg_system_t3.j25.compat.ini
+
+
+
+
+
+
+ http://update.joomlart.com/service/tracking/list.xml
+
+
diff --git a/plugins/system/updatenotification/postinstall/updatecachetime.php b/plugins/system/updatenotification/postinstall/updatecachetime.php
new file mode 100644
index 0000000..3dab71c
--- /dev/null
+++ b/plugins/system/updatenotification/postinstall/updatecachetime.php
@@ -0,0 +1,55 @@
+params->get('cachetimeout', 6);
+
+ // Check if cachetimeout is eq zero
+ if ($cacheTimeout === 0 && JPluginHelper::isEnabled('system', 'updatenotification'))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Sets the cachtimeout back to the default (6 hours)
+ *
+ * @return void
+ *
+ * @since 3.6.3
+ */
+function updatecachetime_postinstall_action()
+{
+ $installer = JComponentHelper::getComponent('com_installer');
+
+ // Sets the cachtimeout back to the default (6 hours)
+ $installer->params->set('cachetimeout', 6);
+
+ // Save the new parameters back to com_installer
+ $table = JTable::getInstance('extension');
+ $table->load($installer->id);
+ $table->bind(array('params' => $installer->params->toString()));
+
+ // Store the changes
+ if (!$table->store())
+ {
+ // If there is an error show it to the admin
+ JFactory::getApplication()->enqueueMessage($table->getError(), 'error');
+ }
+}
diff --git a/plugins/system/updatenotification/updatenotification.php b/plugins/system/updatenotification/updatenotification.php
new file mode 100644
index 0000000..8af6dcd
--- /dev/null
+++ b/plugins/system/updatenotification/updatenotification.php
@@ -0,0 +1,420 @@
+params;
+ $cache_timeout = (int) $params->get('cachetimeout', 6);
+ $cache_timeout = 3600 * $cache_timeout;
+
+ // Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
+ // timestamp. If the difference is greater than the cache timeout we shall not execute again.
+ $now = time();
+ $last = (int) $this->params->get('lastrun', 0);
+
+ if (!defined('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG') && (abs($now - $last) < $cache_timeout))
+ {
+ return;
+ }
+
+ // Update last run status
+ // If I have the time of the last run, I can update, otherwise insert
+ $this->params->set('lastrun', $now);
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true)
+ ->update($db->qn('#__extensions'))
+ ->set($db->qn('params') . ' = ' . $db->q($this->params->toString('JSON')))
+ ->where($db->qn('type') . ' = ' . $db->q('plugin'))
+ ->where($db->qn('folder') . ' = ' . $db->q('system'))
+ ->where($db->qn('element') . ' = ' . $db->q('updatenotification'));
+
+ try
+ {
+ // Lock the tables to prevent multiple plugin executions causing a race condition
+ $db->lockTable('#__extensions');
+ }
+ catch (Exception $e)
+ {
+ // If we can't lock the tables it's too risky to continue execution
+ return;
+ }
+
+ try
+ {
+ // Update the plugin parameters
+ $result = $db->setQuery($query)->execute();
+
+ $this->clearCacheGroups(array('com_plugins'), array(0, 1));
+ }
+ catch (Exception $exc)
+ {
+ // If we failed to execite
+ $db->unlockTables();
+ $result = false;
+ }
+
+ try
+ {
+ // Unlock the tables after writing
+ $db->unlockTables();
+ }
+ catch (Exception $e)
+ {
+ // If we can't lock the tables assume we have somehow failed
+ $result = false;
+ }
+
+ // Abort on failure
+ if (!$result)
+ {
+ return;
+ }
+
+ // This is the extension ID for Joomla! itself
+ $eid = 700;
+
+ // Get any available updates
+ $updater = JUpdater::getInstance();
+ $results = $updater->findUpdates(array($eid), $cache_timeout);
+
+ // If there are no updates our job is done. We need BOTH this check AND the one below.
+ if (!$results)
+ {
+ return;
+ }
+
+ // Unfortunately Joomla! MVC doesn't allow us to autoload classes
+ JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_installer/models', 'InstallerModel');
+
+ // Get the update model and retrieve the Joomla! core updates
+ $model = JModelLegacy::getInstance('Update', 'InstallerModel');
+ $model->setState('filter.extension_id', $eid);
+ $updates = $model->getItems();
+
+ // If there are no updates we don't have to notify anyone about anything. This is NOT a duplicate check.
+ if (empty($updates))
+ {
+ return;
+ }
+
+ // Get the available update
+ $update = array_pop($updates);
+
+ // Check the available version. If it's the same or less than the installed version we have no updates to notify about.
+ if (version_compare($update->version, JVERSION, 'le'))
+ {
+ return;
+ }
+
+ // If we're here, we have updates. First, get a link to the Joomla! Update component.
+ $baseURL = JUri::base();
+ $baseURL = rtrim($baseURL, '/');
+ $baseURL .= (substr($baseURL, -13) !== 'administrator') ? '/administrator/' : '/';
+ $baseURL .= 'index.php?option=com_joomlaupdate';
+ $uri = new JUri($baseURL);
+
+ /**
+ * Some third party security solutions require a secret query parameter to allow log in to the administrator
+ * backend of the site. The link generated above will be invalid and could probably block the user out of their
+ * site, confusing them (they can't understand the third party security solution is not part of Joomla! proper).
+ * So, we're calling the onBuildAdministratorLoginURL system plugin event to let these third party solutions
+ * add any necessary secret query parameters to the URL. The plugins are supposed to have a method with the
+ * signature:
+ *
+ * public function onBuildAdministratorLoginURL(JUri &$uri);
+ *
+ * The plugins should modify the $uri object directly and return null.
+ */
+
+ JEventDispatcher::getInstance()->trigger('onBuildAdministratorLoginURL', array(&$uri));
+
+ // Let's find out the email addresses to notify
+ $superUsers = array();
+ $specificEmail = $this->params->get('email', '');
+
+ if (!empty($specificEmail))
+ {
+ $superUsers = $this->getSuperUsers($specificEmail);
+ }
+
+ if (empty($superUsers))
+ {
+ $superUsers = $this->getSuperUsers();
+ }
+
+ if (empty($superUsers))
+ {
+ return;
+ }
+
+ /*
+ * Load the appropriate language. We try to load English (UK), the current user's language and the forced
+ * language preference, in this order. This ensures that we'll never end up with untranslated strings in the
+ * update email which would make Joomla! seem bad. So, please, if you don't fully understand what the
+ * following code does DO NOT TOUCH IT. It makes the difference between a hobbyist CMS and a professional
+ * solution!
+ */
+ $jLanguage = JFactory::getLanguage();
+ $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, 'en-GB', true, true);
+ $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, null, true, false);
+
+ // Then try loading the preferred (forced) language
+ $forcedLanguage = $this->params->get('language_override', '');
+
+ if (!empty($forcedLanguage))
+ {
+ $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, $forcedLanguage, true, false);
+ }
+
+ // Set up the email subject and body
+
+ $email_subject = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT');
+ $email_body = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY');
+
+ // Replace merge codes with their values
+ $newVersion = $update->version;
+
+ $jVersion = new JVersion;
+ $currentVersion = $jVersion->getShortVersion();
+
+ $jConfig = JFactory::getConfig();
+ $sitename = $jConfig->get('sitename');
+ $mailFrom = $jConfig->get('mailfrom');
+ $fromName = $jConfig->get('fromname');
+
+ $substitutions = array(
+ '[NEWVERSION]' => $newVersion,
+ '[CURVERSION]' => $currentVersion,
+ '[SITENAME]' => $sitename,
+ '[URL]' => JUri::base(),
+ '[LINK]' => $uri->toString(),
+ '[RELEASENEWS]' => 'https://www.joomla.org/announcements/release-news/',
+ '\\n' => "\n",
+ );
+
+ foreach ($substitutions as $k => $v)
+ {
+ $email_subject = str_replace($k, $v, $email_subject);
+ $email_body = str_replace($k, $v, $email_body);
+ }
+
+ // Send the emails to the Super Users
+ foreach ($superUsers as $superUser)
+ {
+ $mailer = JFactory::getMailer();
+ $mailer->setSender(array($mailFrom, $fromName));
+ $mailer->addRecipient($superUser->email);
+ $mailer->setSubject($email_subject);
+ $mailer->setBody($email_body);
+ $mailer->Send();
+ }
+ }
+
+ /**
+ * Returns the Super Users email information. If you provide a comma separated $email list
+ * we will check that these emails do belong to Super Users and that they have not blocked
+ * system emails.
+ *
+ * @param null|string $email A list of Super Users to email
+ *
+ * @return array The list of Super User emails
+ *
+ * @since 3.5
+ */
+ private function getSuperUsers($email = null)
+ {
+ // Get a reference to the database object
+ $db = JFactory::getDbo();
+
+ // Convert the email list to an array
+ if (!empty($email))
+ {
+ $temp = explode(',', $email);
+ $emails = array();
+
+ foreach ($temp as $entry)
+ {
+ $entry = trim($entry);
+ $emails[] = $db->q($entry);
+ }
+
+ $emails = array_unique($emails);
+ }
+ else
+ {
+ $emails = array();
+ }
+
+ // Get a list of groups which have Super User privileges
+ $ret = array();
+
+ try
+ {
+ $rootId = JTable::getInstance('Asset', 'JTable')->getRootId();
+ $rules = JAccess::getAssetRules($rootId)->getData();
+ $rawGroups = $rules['core.admin']->getData();
+ $groups = array();
+
+ if (empty($rawGroups))
+ {
+ return $ret;
+ }
+
+ foreach ($rawGroups as $g => $enabled)
+ {
+ if ($enabled)
+ {
+ $groups[] = $db->q($g);
+ }
+ }
+
+ if (empty($groups))
+ {
+ return $ret;
+ }
+ }
+ catch (Exception $exc)
+ {
+ return $ret;
+ }
+
+ // Get the user IDs of users belonging to the SA groups
+ try
+ {
+ $query = $db->getQuery(true)
+ ->select($db->qn('user_id'))
+ ->from($db->qn('#__user_usergroup_map'))
+ ->where($db->qn('group_id') . ' IN(' . implode(',', $groups) . ')');
+ $db->setQuery($query);
+ $rawUserIDs = $db->loadColumn(0);
+
+ if (empty($rawUserIDs))
+ {
+ return $ret;
+ }
+
+ $userIDs = array();
+
+ foreach ($rawUserIDs as $id)
+ {
+ $userIDs[] = $db->q($id);
+ }
+ }
+ catch (Exception $exc)
+ {
+ return $ret;
+ }
+
+ // Get the user information for the Super Administrator users
+ try
+ {
+ $query = $db->getQuery(true)
+ ->select(
+ array(
+ $db->qn('id'),
+ $db->qn('username'),
+ $db->qn('email'),
+ )
+ )->from($db->qn('#__users'))
+ ->where($db->qn('id') . ' IN(' . implode(',', $userIDs) . ')')
+ ->where($db->qn('block') . ' = 0')
+ ->where($db->qn('sendEmail') . ' = ' . $db->q('1'));
+
+ if (!empty($emails))
+ {
+ $query->where($db->qn('email') . 'IN(' . implode(',', $emails) . ')');
+ }
+
+ $db->setQuery($query);
+ $ret = $db->loadObjectList();
+ }
+ catch (Exception $exc)
+ {
+ return $ret;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
+ *
+ * @param array $clearGroups The cache groups to clean
+ * @param array $cacheClients The cache clients (site, admin) to clean
+ *
+ * @return void
+ *
+ * @since 3.5
+ */
+ private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
+ {
+ $conf = JFactory::getConfig();
+
+ foreach ($clearGroups as $group)
+ {
+ foreach ($cacheClients as $client_id)
+ {
+ try
+ {
+ $options = array(
+ 'defaultgroup' => $group,
+ 'cachebase' => $client_id ? JPATH_ADMINISTRATOR . '/cache' :
+ $conf->get('cache_path', JPATH_SITE . '/cache')
+ );
+
+ $cache = JCache::getInstance('callback', $options);
+ $cache->clean();
+ }
+ catch (Exception $e)
+ {
+ // Ignore it
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/system/updatenotification/updatenotification.xml b/plugins/system/updatenotification/updatenotification.xml
new file mode 100644
index 0000000..fc9e17a
--- /dev/null
+++ b/plugins/system/updatenotification/updatenotification.xml
@@ -0,0 +1,51 @@
+
+
+ plg_system_updatenotification
+ Joomla! Project
+ May 2015
+ Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.5.0
+ PLG_SYSTEM_UPDATENOTIFICATION_XML_DESCRIPTION
+
+ updatenotification.php
+
+
+ en-GB.plg_system_updatenotification.ini
+ en-GB.plg_system_updatenotification.sys.ini
+
+
+
+
+
+
+
+ PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE
+
+
+
+
+
+
+
diff --git a/plugins/twofactorauth/index.html b/plugins/twofactorauth/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/totp/index.html b/plugins/twofactorauth/totp/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/totp/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/totp/postinstall/actions.php b/plugins/twofactorauth/totp/postinstall/actions.php
new file mode 100644
index 0000000..c6989b7
--- /dev/null
+++ b/plugins/twofactorauth/totp/postinstall/actions.php
@@ -0,0 +1,63 @@
+getQuery(true)
+ ->select('*')
+ ->from($db->qn('#__extensions'))
+ ->where($db->qn('type') . ' = ' . $db->q('plugin'))
+ ->where($db->qn('enabled') . ' = ' . $db->q('1'))
+ ->where($db->qn('folder') . ' = ' . $db->q('twofactorauth'));
+ $db->setQuery($query);
+ $enabled_plugins = $db->loadObjectList();
+
+ return count($enabled_plugins) === 0;
+}
+
+/**
+ * Enables the two factor authentication plugin and redirects the user to their
+ * user profile page so that they can enable two factor authentication on their
+ * account.
+ *
+ * @return void
+ *
+ * @since 3.2
+ */
+function twofactorauth_postinstall_action()
+{
+ // Enable the plugin
+ $db = JFactory::getDbo();
+
+ $query = $db->getQuery(true)
+ ->update($db->qn('#__extensions'))
+ ->set($db->qn('enabled') . ' = ' . $db->q(1))
+ ->where($db->qn('type') . ' = ' . $db->q('plugin'))
+ ->where($db->qn('folder') . ' = ' . $db->q('twofactorauth'));
+ $db->setQuery($query);
+ $db->execute();
+
+ // Redirect the user to their profile editor page
+ $url = 'index.php?option=com_users&task=user.edit&id=' . JFactory::getUser()->id;
+ JFactory::getApplication()->redirect($url);
+}
diff --git a/plugins/twofactorauth/totp/postinstall/index.html b/plugins/twofactorauth/totp/postinstall/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/totp/postinstall/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/totp/tmpl/form.php b/plugins/twofactorauth/totp/tmpl/form.php
new file mode 100644
index 0000000..3a155ef
--- /dev/null
+++ b/plugins/twofactorauth/totp/tmpl/form.php
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/twofactorauth/totp/tmpl/index.html b/plugins/twofactorauth/totp/tmpl/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/totp/tmpl/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/totp/totp.php b/plugins/twofactorauth/totp/totp.php
new file mode 100644
index 0000000..a70e91d
--- /dev/null
+++ b/plugins/twofactorauth/totp/totp.php
@@ -0,0 +1,304 @@
+params->get('section', 3);
+
+ $current_section = 0;
+
+ try
+ {
+ $app = JFactory::getApplication();
+
+ if ($app->isClient('administrator'))
+ {
+ $current_section = 2;
+ }
+ elseif ($app->isClient('site'))
+ {
+ $current_section = 1;
+ }
+ }
+ catch (Exception $exc)
+ {
+ $current_section = 0;
+ }
+
+ if (!($current_section & $section))
+ {
+ return false;
+ }
+
+ return (object) array(
+ 'method' => $this->methodName,
+ 'title' => JText::_('PLG_TWOFACTORAUTH_TOTP_METHOD_TITLE')
+ );
+ }
+
+ /**
+ * Shows the configuration page for this two factor authentication method.
+ *
+ * @param object $otpConfig The two factor auth configuration object
+ * @param integer $user_id The numeric user ID of the user whose form we'll display
+ *
+ * @return boolean|string False if the method is not ours, the HTML of the configuration page otherwise
+ *
+ * @see UsersModelUser::getOtpConfig
+ * @since 3.2
+ */
+ public function onUserTwofactorShowConfiguration($otpConfig, $user_id = null)
+ {
+ // Create a new TOTP class with Google Authenticator compatible settings
+ $totp = new FOFEncryptTotp(30, 6, 10);
+
+ if ($otpConfig->method === $this->methodName)
+ {
+ // This method is already activated. Reuse the same secret key.
+ $secret = $otpConfig->config['code'];
+ }
+ else
+ {
+ // This methods is not activated yet. Create a new secret key.
+ $secret = $totp->generateSecret();
+ }
+
+ // These are used by Google Authenticator to tell accounts apart
+ $username = JFactory::getUser($user_id)->username;
+ $hostname = JUri::getInstance()->getHost();
+
+ // This is the URL to the QR code for Google Authenticator
+ $url = $totp->getUrl($username, $hostname, $secret);
+
+ // Is this a new TOTP setup? If so, we'll have to show the code validation field.
+ $new_totp = $otpConfig->method !== 'totp';
+
+ // Start output buffering
+ @ob_start();
+
+ // Include the form.php from a template override. If none is found use the default.
+ $path = FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_totp', true);
+
+ JLoader::import('joomla.filesystem.file');
+
+ if (JFile::exists($path . '/form.php'))
+ {
+ include_once $path . '/form.php';
+ }
+ else
+ {
+ include_once __DIR__ . '/tmpl/form.php';
+ }
+
+ // Stop output buffering and get the form contents
+ $html = @ob_get_clean();
+
+ // Return the form contents
+ return array(
+ 'method' => $this->methodName,
+ 'form' => $html
+ );
+ }
+
+ /**
+ * The save handler of the two factor configuration method's configuration
+ * page.
+ *
+ * @param string $method The two factor auth method for which we'll show the config page
+ *
+ * @return boolean|stdClass False if the method doesn't match or we have an error, OTP config object if it succeeds
+ *
+ * @see UsersModelUser::setOtpConfig
+ * @since 3.2
+ */
+ public function onUserTwofactorApplyConfiguration($method)
+ {
+ if ($method !== $this->methodName)
+ {
+ return false;
+ }
+
+ // Get a reference to the input data object
+ $input = JFactory::getApplication()->input;
+
+ // Load raw data
+ $rawData = $input->get('jform', array(), 'array');
+
+ if (!isset($rawData['twofactor']['totp']))
+ {
+ return false;
+ }
+
+ $data = $rawData['twofactor']['totp'];
+
+ // Warn if the securitycode is empty
+ if (array_key_exists('securitycode', $data) && empty($data['securitycode']))
+ {
+ try
+ {
+ $app = JFactory::getApplication();
+ $app->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_TOTP_ERR_VALIDATIONFAILED'), 'error');
+ }
+ catch (Exception $exc)
+ {
+ // This only happens when we are in a CLI application. We cannot
+ // enqueue a message, so just do nothing.
+ }
+
+ return false;
+ }
+
+ // Create a new TOTP class with Google Authenticator compatible settings
+ $totp = new FOFEncryptTotp(30, 6, 10);
+
+ // Check the security code entered by the user (exact time slot match)
+ $code = $totp->getCode($data['key']);
+ $check = $code === $data['securitycode'];
+
+ /*
+ * If the check fails, test the previous 30 second slot. This allow the
+ * user to enter the security code when it's becoming red in Google
+ * Authenticator app (reaching the end of its 30 second lifetime)
+ */
+ if (!$check)
+ {
+ $time = time() - 30;
+ $code = $totp->getCode($data['key'], $time);
+ $check = $code === $data['securitycode'];
+ }
+
+ /*
+ * If the check fails, test the next 30 second slot. This allows some
+ * time drift between the authentication device and the server
+ */
+ if (!$check)
+ {
+ $time = time() + 30;
+ $code = $totp->getCode($data['key'], $time);
+ $check = $code === $data['securitycode'];
+ }
+
+ if (!$check)
+ {
+ // Check failed. Do not change two factor authentication settings.
+ return false;
+ }
+
+ // Check succeedeed; return an OTP configuration object
+ $otpConfig = (object) array(
+ 'method' => 'totp',
+ 'config' => array(
+ 'code' => $data['key']
+ ),
+ 'otep' => array()
+ );
+
+ return $otpConfig;
+ }
+
+ /**
+ * This method should handle any two factor authentication and report back
+ * to the subject.
+ *
+ * @param array $credentials Array holding the user credentials
+ * @param array $options Array of extra options
+ *
+ * @return boolean True if the user is authorised with this two-factor authentication method
+ *
+ * @since 3.2
+ */
+ public function onUserTwofactorAuthenticate($credentials, $options)
+ {
+ // Get the OTP configuration object
+ $otpConfig = $options['otp_config'];
+
+ // Make sure it's an object
+ if (empty($otpConfig) || !is_object($otpConfig))
+ {
+ return false;
+ }
+
+ // Check if we have the correct method
+ if ($otpConfig->method !== $this->methodName)
+ {
+ return false;
+ }
+
+ // Check if there is a security code
+ if (empty($credentials['secretkey']))
+ {
+ return false;
+ }
+
+ // Create a new TOTP class with Google Authenticator compatible settings
+ $totp = new FOFEncryptTotp(30, 6, 10);
+
+ // Check the code
+ $code = $totp->getCode($otpConfig->config['code']);
+ $check = $code === $credentials['secretkey'];
+
+ /*
+ * If the check fails, test the previous 30 second slot. This allow the
+ * user to enter the security code when it's becoming red in Google
+ * Authenticator app (reaching the end of its 30 second lifetime)
+ */
+ if (!$check)
+ {
+ $time = time() - 30;
+ $code = $totp->getCode($otpConfig->config['code'], $time);
+ $check = $code === $credentials['secretkey'];
+ }
+
+ /*
+ * If the check fails, test the next 30 second slot. This allows some
+ * time drift between the authentication device and the server
+ */
+ if (!$check)
+ {
+ $time = time() + 30;
+ $code = $totp->getCode($otpConfig->config['code'], $time);
+ $check = $code === $credentials['secretkey'];
+ }
+
+ return $check;
+ }
+}
diff --git a/plugins/twofactorauth/totp/totp.xml b/plugins/twofactorauth/totp/totp.xml
new file mode 100644
index 0000000..96d5f36
--- /dev/null
+++ b/plugins/twofactorauth/totp/totp.xml
@@ -0,0 +1,39 @@
+
+
+ plg_twofactorauth_totp
+ Joomla! Project
+ August 2013
+ Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.2.0
+ PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION
+
+ totp.php
+ postinstall
+ tmpl
+
+
+ en-GB.plg_twofactorauth_totp.ini
+ en-GB.plg_twofactorauth_totp.sys.ini
+
+
+
+
+
+ PLG_TWOFACTORAUTH_TOTP_SECTION_SITE
+ PLG_TWOFACTORAUTH_TOTP_SECTION_ADMIN
+ PLG_TWOFACTORAUTH_TOTP_SECTION_BOTH
+
+
+
+
+
diff --git a/plugins/twofactorauth/yubikey/index.html b/plugins/twofactorauth/yubikey/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/yubikey/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/yubikey/tmpl/form.php b/plugins/twofactorauth/yubikey/tmpl/form.php
new file mode 100644
index 0000000..f5ae02c
--- /dev/null
+++ b/plugins/twofactorauth/yubikey/tmpl/form.php
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/twofactorauth/yubikey/tmpl/index.html b/plugins/twofactorauth/yubikey/tmpl/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/twofactorauth/yubikey/tmpl/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/twofactorauth/yubikey/yubikey.php b/plugins/twofactorauth/yubikey/yubikey.php
new file mode 100644
index 0000000..a4d5e79
--- /dev/null
+++ b/plugins/twofactorauth/yubikey/yubikey.php
@@ -0,0 +1,371 @@
+params->get('section', 3);
+ $current_section = 0;
+
+ try
+ {
+ $app = JFactory::getApplication();
+
+ if ($app->isClient('administrator'))
+ {
+ $current_section = 2;
+ }
+ elseif ($app->isClient('site'))
+ {
+ $current_section = 1;
+ }
+ }
+ catch (Exception $exc)
+ {
+ $current_section = 0;
+ }
+
+ if (!($current_section & $section))
+ {
+ return false;
+ }
+
+ return (object) array(
+ 'method' => $this->methodName,
+ 'title' => JText::_('PLG_TWOFACTORAUTH_YUBIKEY_METHOD_TITLE'),
+ );
+ }
+
+ /**
+ * Shows the configuration page for this two factor authentication method.
+ *
+ * @param object $otpConfig The two factor auth configuration object
+ * @param integer $user_id The numeric user ID of the user whose form we'll display
+ *
+ * @return boolean|string False if the method is not ours, the HTML of the configuration page otherwise
+ *
+ * @see UsersModelUser::getOtpConfig
+ * @since 3.2
+ */
+ public function onUserTwofactorShowConfiguration($otpConfig, $user_id = null)
+ {
+ if ($otpConfig->method === $this->methodName)
+ {
+ // This method is already activated. Reuse the same Yubikey ID.
+ $yubikey = $otpConfig->config['yubikey'];
+ }
+ else
+ {
+ // This methods is not activated yet. We'll need a Yubikey TOTP to setup this Yubikey.
+ $yubikey = '';
+ }
+
+ // Is this a new TOTP setup? If so, we'll have to show the code validation field.
+ $new_totp = $otpConfig->method !== $this->methodName;
+
+ // Start output buffering
+ @ob_start();
+
+ // Include the form.php from a template override. If none is found use the default.
+ $path = FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_yubikey', true);
+
+ JLoader::import('joomla.filesystem.file');
+
+ if (JFile::exists($path . '/form.php'))
+ {
+ include_once $path . '/form.php';
+ }
+ else
+ {
+ include_once __DIR__ . '/tmpl/form.php';
+ }
+
+ // Stop output buffering and get the form contents
+ $html = @ob_get_clean();
+
+ // Return the form contents
+ return array(
+ 'method' => $this->methodName,
+ 'form' => $html,
+ );
+ }
+
+ /**
+ * The save handler of the two factor configuration method's configuration
+ * page.
+ *
+ * @param string $method The two factor auth method for which we'll show the config page
+ *
+ * @return boolean|stdClass False if the method doesn't match or we have an error, OTP config object if it succeeds
+ *
+ * @see UsersModelUser::setOtpConfig
+ * @since 3.2
+ */
+ public function onUserTwofactorApplyConfiguration($method)
+ {
+ if ($method !== $this->methodName)
+ {
+ return false;
+ }
+
+ // Get a reference to the input data object
+ $input = JFactory::getApplication()->input;
+
+ // Load raw data
+ $rawData = $input->get('jform', array(), 'array');
+
+ if (!isset($rawData['twofactor']['yubikey']))
+ {
+ return false;
+ }
+
+ $data = $rawData['twofactor']['yubikey'];
+
+ // Warn if the securitycode is empty
+ if (array_key_exists('securitycode', $data) && empty($data['securitycode']))
+ {
+ try
+ {
+ JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'), 'error');
+ }
+ catch (Exception $exc)
+ {
+ // This only happens when we are in a CLI application. We cannot
+ // enqueue a message, so just do nothing.
+ }
+
+ return false;
+ }
+
+ // Validate the Yubikey OTP
+ $check = $this->validateYubikeyOtp($data['securitycode']);
+
+ if (!$check)
+ {
+ JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'), 'error');
+
+ // Check failed. Do not change two factor authentication settings.
+ return false;
+ }
+
+ // Remove the last 32 digits and store the rest in the user configuration parameters
+ $yubikey = substr($data['securitycode'], 0, -32);
+
+ // Check succeedeed; return an OTP configuration object
+ $otpConfig = (object) array(
+ 'method' => $this->methodName,
+ 'config' => array(
+ 'yubikey' => $yubikey
+ ),
+ 'otep' => array()
+ );
+
+ return $otpConfig;
+ }
+
+ /**
+ * This method should handle any two factor authentication and report back
+ * to the subject.
+ *
+ * @param array $credentials Array holding the user credentials
+ * @param array $options Array of extra options
+ *
+ * @return boolean True if the user is authorised with this two-factor authentication method
+ *
+ * @since 3.2
+ */
+ public function onUserTwofactorAuthenticate($credentials, $options)
+ {
+ // Get the OTP configuration object
+ $otpConfig = $options['otp_config'];
+
+ // Make sure it's an object
+ if (empty($otpConfig) || !is_object($otpConfig))
+ {
+ return false;
+ }
+
+ // Check if we have the correct method
+ if ($otpConfig->method !== $this->methodName)
+ {
+ return false;
+ }
+
+ // Check if there is a security code
+ if (empty($credentials['secretkey']))
+ {
+ return false;
+ }
+
+ // Check if the Yubikey starts with the configured Yubikey user string
+ $yubikey_valid = $otpConfig->config['yubikey'];
+ $yubikey = substr($credentials['secretkey'], 0, -32);
+
+ $check = $yubikey === $yubikey_valid;
+
+ if ($check)
+ {
+ $check = $this->validateYubikeyOtp($credentials['secretkey']);
+ }
+
+ return $check;
+ }
+
+ /**
+ * Validates a Yubikey OTP against the Yubikey servers
+ *
+ * @param string $otp The OTP generated by your Yubikey
+ *
+ * @return boolean True if it's a valid OTP
+ *
+ * @since 3.2
+ */
+ public function validateYubikeyOtp($otp)
+ {
+ $server_queue = array(
+ 'api.yubico.com',
+ 'api2.yubico.com',
+ 'api3.yubico.com',
+ 'api4.yubico.com',
+ 'api5.yubico.com',
+ );
+
+ shuffle($server_queue);
+
+ $gotResponse = false;
+ $check = false;
+
+ $token = JSession::getFormToken();
+ $nonce = md5($token . uniqid(mt_rand()));
+
+ while (!$gotResponse && !empty($server_queue))
+ {
+ $server = array_shift($server_queue);
+ $uri = new JUri('https://' . $server . '/wsapi/2.0/verify');
+
+ // I don't see where this ID is used?
+ $uri->setVar('id', 1);
+
+ // The OTP we read from the user
+ $uri->setVar('otp', $otp);
+
+ // This prevents a REPLAYED_OTP status of the token doesn't change
+ // after a user submits an invalid OTP
+ $uri->setVar('nonce', $nonce);
+
+ // Minimum service level required: 50% (at least 50% of the YubiCloud
+ // servers must reply positively for the OTP to validate)
+ $uri->setVar('sl', 50);
+
+ // Timeou waiting for YubiCloud servers to reply: 5 seconds.
+ $uri->setVar('timeout', 5);
+
+ try
+ {
+ $http = JHttpFactory::getHttp();
+ $response = $http->get($uri->toString(), null, 6);
+
+ if (!empty($response))
+ {
+ $gotResponse = true;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ catch (Exception $exc)
+ {
+ // No response, continue with the next server
+ continue;
+ }
+ }
+
+ // No server replied; we can't validate this OTP
+ if (!$gotResponse)
+ {
+ return false;
+ }
+
+ // Parse response
+ $lines = explode("\n", $response->body);
+ $data = array();
+
+ foreach ($lines as $line)
+ {
+ $line = trim($line);
+ $parts = explode('=', $line, 2);
+
+ if (count($parts) < 2)
+ {
+ continue;
+ }
+
+ $data[$parts[0]] = $parts[1];
+ }
+
+ // Validate the response - We need an OK message reply
+ if ($data['status'] !== 'OK')
+ {
+ return false;
+ }
+
+ // Validate the response - We need a confidence level over 50%
+ if ($data['sl'] < 50)
+ {
+ return false;
+ }
+
+ // Validate the response - The OTP must match
+ if ($data['otp'] !== $otp)
+ {
+ return false;
+ }
+
+ // Validate the response - The token must match
+ if ($data['nonce'] !== $nonce)
+ {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/twofactorauth/yubikey/yubikey.xml b/plugins/twofactorauth/yubikey/yubikey.xml
new file mode 100644
index 0000000..df9cd82
--- /dev/null
+++ b/plugins/twofactorauth/yubikey/yubikey.xml
@@ -0,0 +1,38 @@
+
+
+ plg_twofactorauth_yubikey
+ Joomla! Project
+ September 2013
+ Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.2.0
+ PLG_TWOFACTORAUTH_YUBIKEY_XML_DESCRIPTION
+
+ yubikey.php
+ tmpl
+
+
+ en-GB.plg_twofactorauth_yubikey.ini
+ en-GB.plg_twofactorauth_yubikey.sys.ini
+
+
+
+
+
+ PLG_TWOFACTORAUTH_YUBIKEY_SECTION_SITE
+ PLG_TWOFACTORAUTH_YUBIKEY_SECTION_ADMIN
+ PLG_TWOFACTORAUTH_YUBIKEY_SECTION_BOTH
+
+
+
+
+
diff --git a/plugins/user/cmc/cmc.php b/plugins/user/cmc/cmc.php
new file mode 100644
index 0000000..3459f3b
--- /dev/null
+++ b/plugins/user/cmc/cmc.php
@@ -0,0 +1,306 @@
+
+ * @date 2016-04-15
+ *
+ * @copyright Copyright (C) 2008 - 2016 compojoom.com - Daniel Dimitrov, Yves Hoppe. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+// No direct access
+defined('_JEXEC') or die('Restricted access');
+
+use Joomla\Utilities\ArrayHelper;
+
+// Load Compojoom library
+require_once JPATH_LIBRARIES . '/compojoom/include.php';
+
+JLoader::discover('cmcHelper', JPATH_ADMINISTRATOR . '/components/com_cmc/helpers/');
+
+/**
+ * Class PlgUserCmc
+ *
+ * @since 1.4
+ */
+class PlgUserCmc extends JPlugin
+{
+ /**
+ * Prepares the form
+ *
+ * @param string $form - the form
+ * @param object $data - the data object
+ *
+ * @return bool
+ *
+ * @since 3.0.1
+ */
+
+ public function onContentPrepareForm($form, $data)
+ {
+ if (!($form instanceof JForm))
+ {
+ $this->_subject->setError('JERROR_NOT_A_FORM');
+
+ return false;
+ }
+
+ // Check we are manipulating a valid form.
+ $name = $form->getName();
+
+ if (in_array($name, array('com_users.user', 'com_users.profile')))
+ {
+ $this->edit($form, $data);
+
+ return true;
+ }
+
+ if (!in_array($name, array('com_users.registration')))
+ {
+ return true;
+ }
+
+ $this->subscribe($form, $data);
+
+ return true;
+ }
+
+ /**
+ * This function displays the newsletter form on the user profile
+ *
+ * @param JForm $form - the user form
+ * @param array $data - the user data
+ *
+ * @return bool
+ *
+ * @since 3.0.1
+ */
+ public function edit($form, $data)
+ {
+ $appl = JFactory::getApplication();
+ $subscriptionData = CmcHelperUsers::getSubscription($data->email, $this->params->get('listid'));
+
+ $renderer = CmcHelperXmlbuilder::getInstance($this->params);
+
+ // Render Content
+ $html = $renderer->build();
+
+ if ($appl->isSite())
+ {
+ CompojoomHtmlBehavior::jquery();
+ JHtml::script('media/plg_user_cmc/js/cmc.js');
+ }
+
+ // Inject fields into the form
+ $form->load($html, false);
+
+ if ($subscriptionData)
+ {
+ $form->setFieldAttribute('newsletter', 'checked', 'checked', 'cmc');
+ $form->bind(CmcHelperSubscription::convertMergesToFormData($subscriptionData->merges, $this->params->get('listid')), $this->params->get('listid'));
+ }
+ }
+
+ /**
+ * Subscribe a user to our list
+ *
+ * @param JForm $form - the user form
+ * @param array $data - the user data
+ *
+ * @return bool
+ *
+ * @throws Exception
+ *
+ * @since 3.0.1
+ */
+ public function subscribe($form, $data)
+ {
+ $needToValidate = true;
+
+ $input = JFactory::getApplication()->input;
+ $task = $input->get('task');
+
+ if (in_array($task, array('register', 'apply', 'save')))
+ {
+ $requestData = JFactory::getApplication()->input->get('jform', array(), 'array');
+ $needToValidate = isset($requestData['cmc']) && isset($requestData['cmc']['newsletter']);
+ }
+
+ if ($needToValidate)
+ {
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_user_cmc', JPATH_ADMINISTRATOR);
+
+ CompojoomHtmlBehavior::jquery();
+ JHtml::script('media/plg_user_cmc/js/cmc.js');
+ $renderer = CmcHelperXmlbuilder::getInstance($this->params);
+
+ // Render Content
+ $html = $renderer->build();
+
+ // Inject fields into the form
+ $form->load($html, false);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Prepares the form
+ *
+ * @param array $data - the users data
+ * @param boolean $isNew - is the user new
+ * @param object $result - the db result
+ * @param string $error - the error message
+ *
+ * @return boolean
+ *
+ * @since 3.0.1
+ */
+
+ public function onUserAfterSave($data, $isNew, $result, $error)
+ {
+ $userId = ArrayHelper::getValue($data, 'id', 0, 'int');
+
+ $input = JFactory::getApplication()->input;
+ $task = $input->get('task');
+
+ if (in_array($task, array('register','activate')))
+ {
+ if ($userId && $result && isset($data['cmc']) && (count($data['cmc'])))
+ {
+ if ($data["cmc"]["newsletter"] != "1" && $isNew != false)
+ {
+ // Abort if Newsletter is not checked
+ return true;
+ }
+
+ $mappedData = $this->getMapping($this->params->get('mapfields'), $data);
+
+ if (count($mappedData))
+ {
+ $mergedGroups = array_merge($mappedData, $data['cmc_groups']);
+ $data = array_merge($data, array('cmc_groups' => $mergedGroups));
+ }
+
+ $user = JFactory::getUser($data["id"]);
+
+ if ($data["block"] == 1)
+ {
+ // Temporary save user
+ CmcHelperRegistration::saveTempUser($user, $data, _CPLG_JOOMLA);
+ }
+ else
+ {
+ if (!$isNew)
+ {
+ // Activate User to Mailchimp
+ CmcHelperRegistration::activateTempUser($user);
+ }
+ else
+ {
+ // Directly activate user
+ $activated = CmcHelperRegistration::activateDirectUser(
+ $user, $data["cmc"], _CPLG_JOOMLA
+ );
+
+ if ($activated)
+ {
+ JFactory::getApplication()->enqueueMessage(JText::_('COM_CMC_YOU_VE_BEEN_SUBSCRIBED_BUT_CONFIRMATION_IS_NEEDED'));
+ }
+ }
+ }
+ }
+ else
+ {
+ // We only do something if the user is unblocked
+ if ($data["block"] == 0)
+ {
+ // Checking if user exists etc. is taken place in activate function
+ CmcHelperRegistration::activateTempUser(JFactory::getUser($data["id"]));
+ }
+ }
+ }
+
+ if (in_array($task, array('apply', 'save')))
+ {
+ if ($userId && $result && isset($data['cmc']) && (count($data['cmc'])))
+ {
+ if ($data["cmc"]["newsletter"] != "1")
+ {
+ // Abort if Newsletter is not checked
+ return true;
+ }
+
+ $mappedData = $this->getMapping($this->params->get('mapfields'), $data);
+
+ if (count($mappedData))
+ {
+ $mergedGroups = array_merge($mappedData, $data['cmc_groups']);
+ $data = array_merge($data, array('cmc_groups' => $mergedGroups));
+ }
+ }
+
+ $subscription = CmcHelperUsers::getSubscription($data['email'], $data['cmc']['listid']);
+
+ // Updating it to mailchimp
+ $update = $subscription ? true : false;
+
+ CmcHelperList::subscribe(
+ $data['cmc']['listid'],
+ $data['email'],
+ $data['cmc_groups']['FNAME'],
+ $data['cmc_groups']['LNAME'],
+ CmcHelperList::mergeVars($data, $data['cmc']['listid']),
+ 'html',
+ $update,
+ true
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates an array with the mapped data
+ *
+ * @param string $raw - the raw mapping definition as taken out of the params
+ * @param array $user - array with the user data
+ *
+ * @return array
+ *
+ * @since 3.0.1
+ */
+ public static function getMapping($raw, $user)
+ {
+ if (!$raw)
+ {
+ return array();
+ }
+
+ $lines = explode("\n", trim($raw));
+ $groups = array();
+
+ foreach ($lines as $line)
+ {
+ $map = explode('=', $line);
+
+ if (strstr($map[1], ':'))
+ {
+ $parts = explode(':', $map[1]);
+ $field = explode(' ', $user[$parts[0]]);
+
+ $value = trim($field[(int) $parts[1]]);
+ }
+ else
+ {
+ $value = $user[trim($map[1])];
+ }
+
+ $groups[$map[0]] = $value;
+ }
+
+ return $groups;
+ }
+}
diff --git a/plugins/user/cmc/cmc.xml b/plugins/user/cmc/cmc.xml
new file mode 100644
index 0000000..a17d27b
--- /dev/null
+++ b/plugins/user/cmc/cmc.xml
@@ -0,0 +1,60 @@
+
+
+ User - CMC Registration plugin
+ compojoom.com
+ 2019-01-13
+ Copyright (C) 2012 - 2019 Yves Hoppe - compojoom.com. All rights reserved.
+ GNU/GPL http://www.gnu.org/licenses/gpl-3.0.html
+ http://compojoom.com
+ Copyright (C) 2012 - 2019 Yves Hoppe - compojoom.com. All rights reserved.
+ PLG_CMC_USER_REGISTRATION_DESCRIPTION
+
+ cmc.xml
+cmc.php
+
+
+ js
+
+
+ en-GB/en-GB.plg_user_cmc.ini
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MOD_CMC_US_FORMAT
+ MOD_CMC_INTERNATIONAL_FORMAT
+
+
+ JNO
+ JYES
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/user/contactcreator/contactcreator.php b/plugins/user/contactcreator/contactcreator.php
new file mode 100644
index 0000000..56b6638
--- /dev/null
+++ b/plugins/user/contactcreator/contactcreator.php
@@ -0,0 +1,171 @@
+params->get('category', 0);
+
+ if (empty($categoryId))
+ {
+ JError::raiseWarning('', JText::_('PLG_CONTACTCREATOR_ERR_NO_CATEGORY'));
+
+ return false;
+ }
+
+ if ($contact = $this->getContactTable())
+ {
+ /**
+ * Try to pre-load a contact for this user. Apparently only possible if other plugin creates it
+ * Note: $user_id is cleaned above
+ */
+ if (!$contact->load(array('user_id' => (int) $user_id)))
+ {
+ $contact->published = $this->params->get('autopublish', 0);
+ }
+
+ $contact->name = $user['name'];
+ $contact->user_id = $user_id;
+ $contact->email_to = $user['email'];
+ $contact->catid = $categoryId;
+ $contact->access = (int) JFactory::getConfig()->get('access');
+ $contact->language = '*';
+ $contact->generateAlias();
+
+ // Check if the contact already exists to generate new name & alias if required
+ if ($contact->id == 0)
+ {
+ list($name, $alias) = $this->generateAliasAndName($contact->alias, $contact->name, $categoryId);
+
+ $contact->name = $name;
+ $contact->alias = $alias;
+ }
+
+ $autowebpage = $this->params->get('autowebpage', '');
+
+ if (!empty($autowebpage))
+ {
+ // Search terms
+ $search_array = array('[name]', '[username]', '[userid]', '[email]');
+
+ // Replacement terms, urlencoded
+ $replace_array = array_map('urlencode', array($user['name'], $user['username'], $user['id'], $user['email']));
+
+ // Now replace it in together
+ $contact->webpage = str_replace($search_array, $replace_array, $autowebpage);
+ }
+
+ if ($contact->check() && $contact->store())
+ {
+ return true;
+ }
+ }
+
+ JError::raiseWarning('', JText::_('PLG_CONTACTCREATOR_ERR_FAILED_CREATING_CONTACT'));
+
+ return false;
+ }
+
+ /**
+ * Method to change the name & alias if alias is already in use
+ *
+ * @param string $alias The alias.
+ * @param string $name The name.
+ * @param integer $categoryId Category identifier
+ *
+ * @return array Contains the modified title and alias.
+ *
+ * @since 3.2.3
+ */
+ protected function generateAliasAndName($alias, $name, $categoryId)
+ {
+ $table = $this->getContactTable();
+
+ while ($table->load(array('alias' => $alias, 'catid' => $categoryId)))
+ {
+ if ($name === $table->name)
+ {
+ $name = StringHelper::increment($name);
+ }
+
+ $alias = StringHelper::increment($alias, 'dash');
+ }
+
+ return array($name, $alias);
+ }
+
+ /**
+ * Get an instance of the contact table
+ *
+ * @return ContactTableContact
+ *
+ * @since 3.2.3
+ */
+ protected function getContactTable()
+ {
+ JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_contact/tables');
+
+ return JTable::getInstance('contact', 'ContactTable');
+ }
+}
diff --git a/plugins/user/contactcreator/contactcreator.xml b/plugins/user/contactcreator/contactcreator.xml
new file mode 100644
index 0000000..b06a1e9
--- /dev/null
+++ b/plugins/user/contactcreator/contactcreator.xml
@@ -0,0 +1,52 @@
+
+
+ plg_user_contactcreator
+ Joomla! Project
+ August 2009
+ (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.0.0
+ PLG_CONTACTCREATOR_XML_DESCRIPTION
+
+ contactcreator.php
+
+
+ en-GB.plg_user_contactcreator.ini
+ en-GB.plg_user_contactcreator.sys.ini
+
+
+
+
+
+
+
+
+
+ JYES
+ JNO
+
+
+
+
+
diff --git a/plugins/user/contactcreator/index.html b/plugins/user/contactcreator/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/user/contactcreator/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/user/index.html b/plugins/user/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/user/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/user/joomla/index.html b/plugins/user/joomla/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/user/joomla/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/user/joomla/joomla.php b/plugins/user/joomla/joomla.php
new file mode 100644
index 0000000..e248f07
--- /dev/null
+++ b/plugins/user/joomla/joomla.php
@@ -0,0 +1,396 @@
+db->getQuery(true)
+ ->delete($this->db->quoteName('#__session'))
+ ->where($this->db->quoteName('userid') . ' = ' . (int) $user['id']);
+
+ try
+ {
+ $this->db->setQuery($query)->execute();
+ }
+ catch (JDatabaseExceptionExecuting $e)
+ {
+ return false;
+ }
+
+ $query = $this->db->getQuery(true)
+ ->delete($this->db->quoteName('#__messages'))
+ ->where($this->db->quoteName('user_id_from') . ' = ' . (int) $user['id']);
+
+ try
+ {
+ $this->db->setQuery($query)->execute();
+ }
+ catch (JDatabaseExceptionExecuting $e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Utility method to act on a user after it has been saved.
+ *
+ * This method sends a registration email to new users created in the backend.
+ *
+ * @param array $user Holds the new user data.
+ * @param boolean $isnew True if a new user is stored.
+ * @param boolean $success True if user was successfully stored in the database.
+ * @param string $msg Message.
+ *
+ * @return void
+ *
+ * @since 1.6
+ */
+ public function onUserAfterSave($user, $isnew, $success, $msg)
+ {
+ $mail_to_user = $this->params->get('mail_to_user', 1);
+
+ if (!$isnew || !$mail_to_user)
+ {
+ return;
+ }
+
+ // TODO: Suck in the frontend registration emails here as well. Job for a rainy day.
+ // The method check here ensures that if running as a CLI Application we don't get any errors
+ if (method_exists($this->app, 'isClient') && !$this->app->isClient('administrator'))
+ {
+ return;
+ }
+
+ // Check if we have a sensible from email address, if not bail out as mail would not be sent anyway
+ if (strpos($this->app->get('mailfrom'), '@') === false)
+ {
+ $this->app->enqueueMessage(JText::_('JERROR_SENDING_EMAIL'), 'warning');
+
+ return;
+ }
+
+ $lang = JFactory::getLanguage();
+ $defaultLocale = $lang->getTag();
+
+ /**
+ * Look for user language. Priority:
+ * 1. User frontend language
+ * 2. User backend language
+ */
+ $userParams = new Registry($user['params']);
+ $userLocale = $userParams->get('language', $userParams->get('admin_language', $defaultLocale));
+
+ if ($userLocale !== $defaultLocale)
+ {
+ $lang->setLanguage($userLocale);
+ }
+
+ $lang->load('plg_user_joomla', JPATH_ADMINISTRATOR);
+
+ // Compute the mail subject.
+ $emailSubject = JText::sprintf(
+ 'PLG_USER_JOOMLA_NEW_USER_EMAIL_SUBJECT',
+ $user['name'],
+ $this->app->get('sitename')
+ );
+
+ // Compute the mail body.
+ $emailBody = JText::sprintf(
+ 'PLG_USER_JOOMLA_NEW_USER_EMAIL_BODY',
+ $user['name'],
+ $this->app->get('sitename'),
+ JUri::root(),
+ $user['username'],
+ $user['password_clear']
+ );
+
+ $res = JFactory::getMailer()->sendMail(
+ $this->app->get('mailfrom'),
+ $this->app->get('fromname'),
+ $user['email'],
+ $emailSubject,
+ $emailBody
+ );
+
+ if ($res === false)
+ {
+ $this->app->enqueueMessage(JText::_('JERROR_SENDING_EMAIL'), 'warning');
+ }
+
+ // Set application language back to default if we changed it
+ if ($userLocale !== $defaultLocale)
+ {
+ $lang->setLanguage($defaultLocale);
+ }
+ }
+
+ /**
+ * This method should handle any login logic and report back to the subject
+ *
+ * @param array $user Holds the user data
+ * @param array $options Array holding options (remember, autoregister, group)
+ *
+ * @return boolean True on success
+ *
+ * @since 1.5
+ */
+ public function onUserLogin($user, $options = array())
+ {
+ $instance = $this->_getUser($user, $options);
+
+ // If _getUser returned an error, then pass it back.
+ if ($instance instanceof Exception)
+ {
+ return false;
+ }
+
+ // If the user is blocked, redirect with an error
+ if ($instance->block == 1)
+ {
+ $this->app->enqueueMessage(JText::_('JERROR_NOLOGIN_BLOCKED'), 'warning');
+
+ return false;
+ }
+
+ // Authorise the user based on the group information
+ if (!isset($options['group']))
+ {
+ $options['group'] = 'USERS';
+ }
+
+ // Check the user can login.
+ $result = $instance->authorise($options['action']);
+
+ if (!$result)
+ {
+ $this->app->enqueueMessage(JText::_('JERROR_LOGIN_DENIED'), 'warning');
+
+ return false;
+ }
+
+ // Mark the user as logged in
+ $instance->guest = 0;
+
+ $session = JFactory::getSession();
+
+ // Grab the current session ID
+ $oldSessionId = $session->getId();
+
+ // Fork the session
+ $session->fork();
+
+ $session->set('user', $instance);
+
+ // Ensure the new session's metadata is written to the database
+ $this->app->checkSession();
+
+ // Purge the old session
+ $query = $this->db->getQuery(true)
+ ->delete('#__session')
+ ->where($this->db->quoteName('session_id') . ' = ' . $this->db->quote($oldSessionId));
+
+ try
+ {
+ $this->db->setQuery($query)->execute();
+ }
+ catch (RuntimeException $e)
+ {
+ // The old session is already invalidated, don't let this block logging in
+ }
+
+ // Hit the user last visit field
+ $instance->setLastVisit();
+
+ // Add "user state" cookie used for reverse caching proxies like Varnish, Nginx etc.
+ if ($this->app->isClient('site'))
+ {
+ $this->app->input->cookie->set(
+ 'joomla_user_state',
+ 'logged_in',
+ 0,
+ $this->app->get('cookie_path', '/'),
+ $this->app->get('cookie_domain', ''),
+ $this->app->isHttpsForced(),
+ true
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * This method should handle any logout logic and report back to the subject
+ *
+ * @param array $user Holds the user data.
+ * @param array $options Array holding options (client, ...).
+ *
+ * @return bool True on success
+ *
+ * @since 1.5
+ */
+ public function onUserLogout($user, $options = array())
+ {
+ $my = JFactory::getUser();
+ $session = JFactory::getSession();
+
+ // Make sure we're a valid user first
+ if ($user['id'] == 0 && !$my->get('tmp_user'))
+ {
+ return true;
+ }
+
+ $sharedSessions = $this->app->get('shared_session', '0');
+
+ // Check to see if we're deleting the current session
+ if ($my->id == $user['id'] && ($sharedSessions || (!$sharedSessions && $options['clientid'] == $this->app->getClientId())))
+ {
+ // Hit the user last visit field
+ $my->setLastVisit();
+
+ // Destroy the php session for this user
+ $session->destroy();
+ }
+
+ // Enable / Disable Forcing logout all users with same userid
+ $forceLogout = $this->params->get('forceLogout', 1);
+
+ if ($forceLogout)
+ {
+ $query = $this->db->getQuery(true)
+ ->delete($this->db->quoteName('#__session'))
+ ->where($this->db->quoteName('userid') . ' = ' . (int) $user['id']);
+
+ if (!$sharedSessions)
+ {
+ $query->where($this->db->quoteName('client_id') . ' = ' . (int) $options['clientid']);
+ }
+
+ try
+ {
+ $this->db->setQuery($query)->execute();
+ }
+ catch (RuntimeException $e)
+ {
+ return false;
+ }
+ }
+
+ // Delete "user state" cookie used for reverse caching proxies like Varnish, Nginx etc.
+ if ($this->app->isClient('site'))
+ {
+ $this->app->input->cookie->set('joomla_user_state', '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));
+ }
+
+ return true;
+ }
+
+ /**
+ * This method will return a user object
+ *
+ * If options['autoregister'] is true, if the user doesn't exist yet they will be created
+ *
+ * @param array $user Holds the user data.
+ * @param array $options Array holding options (remember, autoregister, group).
+ *
+ * @return JUser
+ *
+ * @since 1.5
+ */
+ protected function _getUser($user, $options = array())
+ {
+ $instance = JUser::getInstance();
+ $id = (int) JUserHelper::getUserId($user['username']);
+
+ if ($id)
+ {
+ $instance->load($id);
+
+ return $instance;
+ }
+
+ // TODO : move this out of the plugin
+ $config = JComponentHelper::getParams('com_users');
+
+ // Hard coded default to match the default value from com_users.
+ $defaultUserGroup = $config->get('new_usertype', 2);
+
+ $instance->id = 0;
+ $instance->name = $user['fullname'];
+ $instance->username = $user['username'];
+ $instance->password_clear = $user['password_clear'];
+
+ // Result should contain an email (check).
+ $instance->email = $user['email'];
+ $instance->groups = array($defaultUserGroup);
+
+ // If autoregister is set let's register the user
+ $autoregister = isset($options['autoregister']) ? $options['autoregister'] : $this->params->get('autoregister', 1);
+
+ if ($autoregister)
+ {
+ if (!$instance->save())
+ {
+ JLog::add('Error in autoregistration for user ' . $user['username'] . '.', JLog::WARNING, 'error');
+ }
+ }
+ else
+ {
+ // No existing user and autoregister off, this is a temporary user.
+ $instance->set('tmp_user', true);
+ }
+
+ return $instance;
+ }
+}
diff --git a/plugins/user/joomla/joomla.xml b/plugins/user/joomla/joomla.xml
new file mode 100644
index 0000000..8ea25ff
--- /dev/null
+++ b/plugins/user/joomla/joomla.xml
@@ -0,0 +1,60 @@
+
+
+ plg_user_joomla
+ Joomla! Project
+ December 2006
+ (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.0.0
+ PLG_USER_JOOMLA_XML_DESCRIPTION
+
+ joomla.php
+
+
+ en-GB.plg_user_joomla.ini
+ en-GB.plg_user_joomla.sys.ini
+
+
+
+
+
+ JYES
+ JNO
+
+
+
+ JYES
+ JNO
+
+
+
+ JYES
+ JNO
+
+
+
+
+
diff --git a/plugins/user/k2/k2.php b/plugins/user/k2/k2.php
new file mode 100644
index 0000000..c474294
--- /dev/null
+++ b/plugins/user/k2/k2.php
@@ -0,0 +1,292 @@
+onAfterStoreUser($user, $isnew, $success, $msg);
+ }
+
+ function onUserLogin($user, $options)
+ {
+ return $this->onLoginUser($user, $options);
+ }
+
+ function onUserLogout($user)
+ {
+ return $this->onLogoutUser($user);
+ }
+
+ function onUserAfterDelete($user, $success, $msg)
+ {
+ return $this->onAfterDeleteUser($user, $success, $msg);
+ }
+
+ function onUserBeforeSave($user, $isNew)
+ {
+ return $this->onBeforeStoreUser($user, $isNew);
+ }
+
+ function onAfterStoreUser($user, $isnew, $success, $msg)
+ {
+
+ $mainframe = JFactory::getApplication();
+ $params = JComponentHelper::getParams('com_k2');
+ jimport('joomla.filesystem.file');
+ $task = JRequest::getCmd('task');
+
+ if ($mainframe->isSite() && ($task == 'activate' || $isnew) && $params->get('stopForumSpam'))
+ {
+ $this->checkSpammer($user);
+
+ }
+
+ if ($mainframe->isSite() && $task != 'activate' && JRequest::getInt('K2UserForm'))
+ {
+ JPlugin::loadLanguage('com_k2');
+ JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'tables');
+ $row = JTable::getInstance('K2User', 'Table');
+ $k2id = $this->getK2UserID($user['id']);
+ JRequest::setVar('id', $k2id, 'post');
+ $row->bind(JRequest::get('post'));
+ $row->set('userID', $user['id']);
+ $row->set('userName', $user['name']);
+ $row->set('ip', $_SERVER['REMOTE_ADDR']);
+ $row->set('hostname', gethostbyaddr($_SERVER['REMOTE_ADDR']));
+ if (isset($user['notes']))
+ {
+ $row->set('notes', $user['notes']);
+ }
+ if ($isnew)
+ {
+ $row->set('group', $params->get('K2UserGroup', 1));
+ }
+ else
+ {
+ $row->set('group', NULL);
+ $row->set('gender', JRequest::getVar('gender'));
+ $row->set('url', JRequest::getString('url'));
+ }
+ if ($row->gender != 'm' && $row->gender != 'f')
+ {
+ $row->gender = 'm';
+ }
+ $row->url = JString::str_ireplace(' ', '', $row->url);
+ $row->url = JString::str_ireplace('"', '', $row->url);
+ $row->url = JString::str_ireplace('<', '', $row->url);
+ $row->url = JString::str_ireplace('>', '', $row->url);
+ $row->url = JString::str_ireplace('\'', '', $row->url);
+ $row->set('description', JRequest::getVar('description', '', 'post', 'string', 4));
+ if ($params->get('xssFiltering'))
+ {
+ $filter = new JFilterInput( array(), array(), 1, 1, 0);
+ $row->description = $filter->clean($row->description);
+ }
+
+ $file = JRequest::get('files');
+
+ require_once (JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'lib'.DS.'class.upload.php');
+ $savepath = JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS;
+
+ if (isset($file['image']) && $file['image']['error'] == 0 && !JRequest::getBool('del_image'))
+ {
+ $handle = new Upload($file['image']);
+ $handle->allowed = array('image/*');
+ if ($handle->uploaded)
+ {
+ $handle->file_auto_rename = false;
+ $handle->file_overwrite = true;
+ $handle->file_new_name_body = $row->id;
+ $handle->image_resize = true;
+ $handle->image_ratio_y = true;
+ $handle->image_x = $params->get('userImageWidth', '100');
+ $handle->Process($savepath);
+ $handle->Clean();
+ }
+ else
+ {
+ $mainframe->enqueueMessage(JText::_('K2_COULD_NOT_UPLOAD_YOUR_IMAGE').$handle->error, 'notice');
+ }
+ $row->image = $handle->file_dst_name;
+ }
+
+ if (JRequest::getBool('del_image'))
+ {
+
+ if (JFile::exists(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS.$row->image))
+ {
+ JFile::delete(JPATH_ROOT.DS.'media'.DS.'k2'.DS.'users'.DS.$row->image);
+ }
+ $row->image = '';
+ }
+
+ $row->store();
+ $itemid = $params->get('redirect');
+
+ if (!$isnew && $itemid)
+ {
+ $menu = JSite::getMenu();
+ $item = $menu->getItem($itemid);
+ $url = JRoute::_($item->link.'&Itemid='.$itemid, false);
+ if (JURI::isInternal($url))
+ {
+ $mainframe->enqueueMessage(JText::_('K2_YOUR_SETTINGS_HAVE_BEEN_SAVED'));
+ $mainframe->redirect($url);
+ }
+ }
+ }
+
+ }
+
+ function onLoginUser($user, $options)
+ {
+ $params = JComponentHelper::getParams('com_k2');
+ $mainframe = JFactory::getApplication();
+ if ($mainframe->isSite())
+ {
+ // Get the user id
+ $db = JFactory::getDBO();
+ $db->setQuery("SELECT id FROM #__users WHERE username = ".$db->Quote($user['username']));
+ $id = $db->loadResult();
+
+ // If K2 profiles are enabled assign non-existing K2 users to the default K2 group. Update user info for existing K2 users.
+ if ($params->get('K2UserProfile') && $id)
+ {
+ $k2id = $this->getK2UserID($id);
+ JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'tables');
+ $row = JTable::getInstance('K2User', 'Table');
+ if ($k2id)
+ {
+ $row->load($k2id);
+ }
+ else
+ {
+ $row->set('userID', $id);
+ $row->set('userName', $user['fullname']);
+ $row->set('group', $params->get('K2UserGroup', 1));
+ }
+ $row->ip = $_SERVER['REMOTE_ADDR'];
+ $row->hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
+ $row->store();
+ }
+
+ // Set the Cookie domain for user based on K2 parameters
+ if ($params->get('cookieDomain') && $id)
+ {
+ setcookie("userID", $id, 0, '/', $params->get('cookieDomain'), 0);
+ }
+ }
+ return true;
+ }
+
+ function onLogoutUser($user)
+ {
+ $params = JComponentHelper::getParams('com_k2');
+ $mainframe = JFactory::getApplication();
+ if ($mainframe->isSite() && $params->get('cookieDomain'))
+ {
+ setcookie("userID", "", time() - 3600, '/', $params->get('cookieDomain'), 0);
+ }
+ return true;
+ }
+
+ function onAfterDeleteUser($user, $succes, $msg)
+ {
+
+ $mainframe = JFactory::getApplication();
+ $db = JFactory::getDBO();
+ $query = "DELETE FROM #__k2_users WHERE userID={$user['id']}";
+ $db->setQuery($query);
+ $db->query();
+ }
+
+ function onBeforeStoreUser($user, $isNew)
+ {
+ $mainframe = JFactory::getApplication();
+ $params = JComponentHelper::getParams('com_k2');
+ $session = JFactory::getSession();
+ if ($params->get('K2UserProfile') && $isNew && $params->get('recaptchaOnRegistration') && $mainframe->isSite() && !$session->get('socialConnectData'))
+ {
+ if (!function_exists('_recaptcha_qsencode'))
+ {
+ require_once (JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'lib'.DS.'recaptchalib.php');
+ }
+ $privatekey = $params->get('recaptcha_private_key');
+ $recaptcha_challenge_field = isset($_POST["recaptcha_challenge_field"]) ? $_POST["recaptcha_challenge_field"] : '';
+ $recaptcha_response_field = isset($_POST["recaptcha_response_field"]) ? $_POST["recaptcha_response_field"] : '';
+ $resp = recaptcha_check_answer($privatekey, $_SERVER["REMOTE_ADDR"], $recaptcha_challenge_field, $recaptcha_response_field);
+ if (!$resp->is_valid)
+ {
+ if (K2_JVERSION != '15')
+ {
+ $url = 'index.php?option=com_users&view=registration';
+ }
+ else
+ {
+ $url = 'index.php?option=com_user&view=register';
+ }
+ $mainframe->enqueueMessage(JText::_('K2_THE_WORDS_YOU_TYPED_DID_NOT_MATCH_THE_ONES_DISPLAYED_PLEASE_TRY_AGAIN'), 'error');
+ $mainframe->redirect($url);
+ }
+ }
+ }
+
+ function getK2UserID($id)
+ {
+
+ $db = JFactory::getDBO();
+ $query = "SELECT id FROM #__k2_users WHERE userID={$id}";
+ $db->setQuery($query);
+ $result = $db->loadResult();
+ return $result;
+ }
+
+ function checkSpammer(&$user)
+ {
+ if (!$user['block'])
+ {
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $email = urlencode($user['email']);
+ $username = urlencode($user['username']);
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, 'http://www.stopforumspam.com/api?ip='.$ip.'&email='.$email.'&username='.$username.'&f=json');
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ if ($httpCode == 200)
+ {
+ $response = json_decode($response);
+ if ($response->ip->appears || $response->email->appears || $response->username->appears)
+ {
+ $db = JFactory::getDBO();
+ $db->setQuery("UPDATE #__users SET block = 1 WHERE id = ".$user['id']);
+ $db->query();
+ $user['notes'] = JText::_('K2_POSSIBLE_SPAMMER_DETECTED_BY_STOPFORUMSPAM');
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/user/k2/k2.xml b/plugins/user/k2/k2.xml
new file mode 100644
index 0000000..9bb61af
--- /dev/null
+++ b/plugins/user/k2/k2.xml
@@ -0,0 +1,15 @@
+
+
+ User - K2
+ JoomlaWorks
+ February 28th, 2014
+ Copyright (c) 2006 - 2014 JoomlaWorks Ltd. All rights reserved.
+ please-use-the-contact-form@joomlaworks.net
+ www.joomlaworks.net
+ 2.6.8
+ http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
+ K2_A_USER_SYNCHRONIZATION_PLUGIN_FOR_K2
+
+ k2.php
+
+
diff --git a/plugins/user/profile/field/dob.php b/plugins/user/profile/field/dob.php
new file mode 100644
index 0000000..b295758
--- /dev/null
+++ b/plugins/user/profile/field/dob.php
@@ -0,0 +1,63 @@
+element['info'] ? (string) $this->element['info'] : '';
+ $text = $this->translateLabel ? JText::_($text) : $text;
+
+ if ($text)
+ {
+ $app = JFactory::getApplication();
+ $layout = new JLayoutFile('plugins.user.profile.fields.dob');
+ $view = $app->input->getString('view', '');
+
+ // Only display the tip when editing profile
+ if ($view === 'registration' || $view === 'profile' || $app->isClient('administrator'))
+ {
+ $layout = new JLayoutFile('plugins.user.profile.fields.dob');
+ $info = $layout->render(array('text' => $text));
+ $label = $info . $label;
+ }
+ }
+
+ return $label;
+ }
+}
diff --git a/plugins/user/profile/field/tos.php b/plugins/user/profile/field/tos.php
new file mode 100644
index 0000000..4c167c7
--- /dev/null
+++ b/plugins/user/profile/field/tos.php
@@ -0,0 +1,126 @@
+hidden)
+ {
+ return $label;
+ }
+
+ // Get the label text from the XML element, defaulting to the element name.
+ $text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
+ $text = $this->translateLabel ? JText::_($text) : $text;
+
+ // Set required to true as this field is not displayed at all if not required.
+ $this->required = true;
+
+ // Add CSS and JS for the TOS field
+ $doc = JFactory::getDocument();
+ $css = '#jform_profile_tos {width: 18em; margin: 0 !important; padding: 0 2px !important;}
+ #jform_profile_tos input {margin: 0 5px 0 0 !important; width: 10px !important;}
+ #jform_profile_tos label {margin: 0 15px 0 0 !important; width: auto;}
+ ';
+ $doc->addStyleDeclaration($css);
+ JHtml::_('behavior.modal');
+
+ // Build the class for the label.
+ $class = !empty($this->description) ? 'hasTooltip' : '';
+ $class = $class . ' required';
+ $class = !empty($this->labelClass) ? $class . ' ' . $this->labelClass : $class;
+
+ // Add the opening label tag and main attributes attributes.
+ $label .= '
description))
+ {
+ $label .= ' title="'
+ . htmlspecialchars(
+ trim($text, ':') . ' ' . ($this->translateDescription ? JText::_($this->description) : $this->description),
+ ENT_COMPAT, 'UTF-8'
+ ) . '"';
+ }
+
+ $tosarticle = $this->element['article'] > 0 ? (int) $this->element['article'] : 0;
+
+ if ($tosarticle)
+ {
+ JLoader::register('ContentHelperRoute', JPATH_BASE . '/components/com_content/helpers/route.php');
+
+ $attribs = array();
+ $attribs['class'] = 'modal';
+ $attribs['rel'] = '{handler: \'iframe\', size: {x:800, y:500}}';
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+ $query->select('id, alias, catid, language')
+ ->from('#__content')
+ ->where('id = ' . $tosarticle);
+ $db->setQuery($query);
+ $article = $db->loadObject();
+
+ if (JLanguageAssociations::isEnabled())
+ {
+ $tosassociated = JLanguageAssociations::getAssociations('com_content', '#__content', 'com_content.item', $tosarticle);
+ }
+
+ $current_lang = JFactory::getLanguage()->getTag();
+
+ if (isset($tosassociated) && $current_lang !== $article->language && array_key_exists($current_lang, $tosassociated))
+ {
+ $url = ContentHelperRoute::getArticleRoute($tosassociated[$current_lang]->id, $tosassociated[$current_lang]->catid);
+ $link = JHtml::_('link', JRoute::_($url . '&tmpl=component&lang=' . $tosassociated[$current_lang]->language), $text, $attribs);
+ }
+ else
+ {
+ $slug = $article->alias ? ($article->id . ':' . $article->alias) : $article->id;
+ $url = ContentHelperRoute::getArticleRoute($slug, $article->catid);
+ $link = JHtml::_('link', JRoute::_($url . '&tmpl=component&lang=' . $article->language), $text, $attribs);
+ }
+ }
+ else
+ {
+ $link = $text;
+ }
+
+ // Add the label text and closing tag.
+ $label .= '>' . $link . ' * ';
+
+ return $label;
+ }
+}
diff --git a/plugins/user/profile/index.html b/plugins/user/profile/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/user/profile/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/user/profile/profile.php b/plugins/user/profile/profile.php
new file mode 100644
index 0000000..29f98e6
--- /dev/null
+++ b/plugins/user/profile/profile.php
@@ -0,0 +1,520 @@
+id) ? $data->id : 0;
+
+ if (!isset($data->profile) && $userId > 0)
+ {
+ // Load the profile data from the database.
+ $db = JFactory::getDbo();
+ $db->setQuery(
+ 'SELECT profile_key, profile_value FROM #__user_profiles'
+ . ' WHERE user_id = ' . (int) $userId . " AND profile_key LIKE 'profile.%'"
+ . ' ORDER BY ordering'
+ );
+
+ try
+ {
+ $results = $db->loadRowList();
+ }
+ catch (RuntimeException $e)
+ {
+ $this->_subject->setError($e->getMessage());
+
+ return false;
+ }
+
+ // Merge the profile data.
+ $data->profile = array();
+
+ foreach ($results as $v)
+ {
+ $k = str_replace('profile.', '', $v[0]);
+ $data->profile[$k] = json_decode($v[1], true);
+
+ if ($data->profile[$k] === null)
+ {
+ $data->profile[$k] = $v[1];
+ }
+ }
+ }
+
+ if (!JHtml::isRegistered('users.url'))
+ {
+ JHtml::register('users.url', array(__CLASS__, 'url'));
+ }
+
+ if (!JHtml::isRegistered('users.calendar'))
+ {
+ JHtml::register('users.calendar', array(__CLASS__, 'calendar'));
+ }
+
+ if (!JHtml::isRegistered('users.tos'))
+ {
+ JHtml::register('users.tos', array(__CLASS__, 'tos'));
+ }
+
+ if (!JHtml::isRegistered('users.dob'))
+ {
+ JHtml::register('users.dob', array(__CLASS__, 'dob'));
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns an anchor tag generated from a given value
+ *
+ * @param string $value URL to use
+ *
+ * @return mixed|string
+ */
+ public static function url($value)
+ {
+ if (empty($value))
+ {
+ return JHtml::_('users.value', $value);
+ }
+ else
+ {
+ // Convert website URL to utf8 for display
+ $value = JStringPunycode::urlToUTF8(htmlspecialchars($value));
+
+ if (strpos($value, 'http') === 0)
+ {
+ return '
' . $value . ' ';
+ }
+ else
+ {
+ return '
' . $value . ' ';
+ }
+ }
+ }
+
+ /**
+ * Returns html markup showing a date picker
+ *
+ * @param string $value valid date string
+ *
+ * @return mixed
+ */
+ public static function calendar($value)
+ {
+ if (empty($value))
+ {
+ return JHtml::_('users.value', $value);
+ }
+ else
+ {
+ return JHtml::_('date', $value, null, null);
+ }
+ }
+
+ /**
+ * Returns the date of birth formatted and calculated using server timezone.
+ *
+ * @param string $value valid date string
+ *
+ * @return mixed
+ */
+ public static function dob($value)
+ {
+ if (!$value)
+ {
+ return '';
+ }
+
+ return JHtml::_('date', $value, JText::_('DATE_FORMAT_LC1'), false);
+ }
+
+ /**
+ * Return the translated strings yes or no depending on the value
+ *
+ * @param boolean $value input value
+ *
+ * @return string
+ */
+ public static function tos($value)
+ {
+ if ($value)
+ {
+ return JText::_('JYES');
+ }
+ else
+ {
+ return JText::_('JNO');
+ }
+ }
+
+ /**
+ * Adds additional fields to the user editing form
+ *
+ * @param JForm $form The form to be altered.
+ * @param mixed $data The associated data for the form.
+ *
+ * @return boolean
+ *
+ * @since 1.6
+ */
+ public function onContentPrepareForm($form, $data)
+ {
+ if (!($form instanceof JForm))
+ {
+ $this->_subject->setError('JERROR_NOT_A_FORM');
+
+ return false;
+ }
+
+ // Check we are manipulating a valid form.
+ $name = $form->getName();
+
+ if (!in_array($name, array('com_admin.profile', 'com_users.user', 'com_users.profile', 'com_users.registration')))
+ {
+ return true;
+ }
+
+ // Add the registration fields to the form.
+ JForm::addFormPath(__DIR__ . '/profiles');
+ $form->loadFile('profile', false);
+
+ $fields = array(
+ 'address1',
+ 'address2',
+ 'city',
+ 'region',
+ 'country',
+ 'postal_code',
+ 'phone',
+ 'website',
+ 'favoritebook',
+ 'aboutme',
+ 'dob',
+ 'tos',
+ );
+
+ // Change fields description when displayed in frontend or backend profile editing
+ $app = JFactory::getApplication();
+
+ if ($app->isClient('site') || $name === 'com_users.user' || $name === 'com_admin.profile')
+ {
+ $form->setFieldAttribute('address1', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('address2', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('city', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('region', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('country', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('postal_code', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('phone', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('website', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('favoritebook', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('aboutme', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('dob', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
+ $form->setFieldAttribute('tos', 'description', 'PLG_USER_PROFILE_FIELD_TOS_DESC_SITE', 'profile');
+ }
+
+ $tosarticle = $this->params->get('register_tos_article');
+ $tosenabled = $this->params->get('register-require_tos', 0);
+
+ // We need to be in the registration form and field needs to be enabled
+ if ($name !== 'com_users.registration' || !$tosenabled)
+ {
+ // We only want the TOS in the registration form
+ $form->removeField('tos', 'profile');
+ }
+ else
+ {
+ // Push the TOS article ID into the TOS field.
+ $form->setFieldAttribute('tos', 'article', $tosarticle, 'profile');
+ }
+
+ foreach ($fields as $field)
+ {
+ // Case using the users manager in admin
+ if ($name === 'com_users.user')
+ {
+ // Toggle whether the field is required.
+ if ($this->params->get('profile-require_' . $field, 1) > 0)
+ {
+ $form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profile');
+ }
+ // Remove the field if it is disabled in registration and profile
+ elseif ($this->params->get('register-require_' . $field, 1) == 0
+ && $this->params->get('profile-require_' . $field, 1) == 0)
+ {
+ $form->removeField($field, 'profile');
+ }
+ }
+ // Case registration
+ elseif ($name === 'com_users.registration')
+ {
+ // Toggle whether the field is required.
+ if ($this->params->get('register-require_' . $field, 1) > 0)
+ {
+ $form->setFieldAttribute($field, 'required', ($this->params->get('register-require_' . $field) == 2) ? 'required' : '', 'profile');
+ }
+ else
+ {
+ $form->removeField($field, 'profile');
+ }
+ }
+ // Case profile in site or admin
+ elseif ($name === 'com_users.profile' || $name === 'com_admin.profile')
+ {
+ // Toggle whether the field is required.
+ if ($this->params->get('profile-require_' . $field, 1) > 0)
+ {
+ $form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profile');
+ }
+ else
+ {
+ $form->removeField($field, 'profile');
+ }
+ }
+ }
+
+ // Drop the profile form entirely if there aren't any fields to display.
+ $remainingfields = $form->getGroup('profile');
+
+ if (!count($remainingfields))
+ {
+ $form->removeGroup('profile');
+ }
+
+ return true;
+ }
+
+ /**
+ * Method is called before user data is stored in the database
+ *
+ * @param array $user Holds the old user data.
+ * @param boolean $isnew True if a new user is stored.
+ * @param array $data Holds the new user data.
+ *
+ * @return boolean
+ *
+ * @since 3.1
+ * @throws InvalidArgumentException on invalid date.
+ */
+ public function onUserBeforeSave($user, $isnew, $data)
+ {
+ // Check that the date is valid.
+ if (!empty($data['profile']['dob']))
+ {
+ try
+ {
+ $date = new JDate($data['profile']['dob']);
+ $this->date = $date->format('Y-m-d H:i:s');
+ }
+ catch (Exception $e)
+ {
+ // Throw an exception if date is not valid.
+ throw new InvalidArgumentException(JText::_('PLG_USER_PROFILE_ERROR_INVALID_DOB'));
+ }
+
+ if (JDate::getInstance('now') < $date)
+ {
+ // Throw an exception if dob is greather than now.
+ throw new InvalidArgumentException(JText::_('PLG_USER_PROFILE_ERROR_INVALID_DOB_FUTURE_DATE'));
+ }
+ }
+
+ // Check that the tos is checked if required ie only in registration from frontend.
+ $task = JFactory::getApplication()->input->getCmd('task');
+ $option = JFactory::getApplication()->input->getCmd('option');
+ $tosarticle = $this->params->get('register_tos_article');
+ $tosenabled = ($this->params->get('register-require_tos', 0) == 2);
+
+ // Check that the tos is checked.
+ if ($task === 'register' && $tosenabled && $tosarticle && $option === 'com_users' && !$data['profile']['tos'])
+ {
+ throw new InvalidArgumentException(JText::_('PLG_USER_PROFILE_FIELD_TOS_DESC_SITE'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Saves user profile data
+ *
+ * @param array $data entered user data
+ * @param boolean $isNew true if this is a new user
+ * @param boolean $result true if saving the user worked
+ * @param string $error error message
+ *
+ * @return bool
+ */
+ public function onUserAfterSave($data, $isNew, $result, $error)
+ {
+ $userId = ArrayHelper::getValue($data, 'id', 0, 'int');
+
+ if ($userId && $result && isset($data['profile']) && count($data['profile']))
+ {
+ try
+ {
+ $db = JFactory::getDbo();
+
+ // Sanitize the date
+ if (!empty($data['profile']['dob']))
+ {
+ $data['profile']['dob'] = $this->date;
+ }
+
+ $keys = array_keys($data['profile']);
+
+ foreach ($keys as &$key)
+ {
+ $key = 'profile.' . $key;
+ $key = $db->quote($key);
+ }
+
+ $query = $db->getQuery(true)
+ ->delete($db->quoteName('#__user_profiles'))
+ ->where($db->quoteName('user_id') . ' = ' . (int) $userId)
+ ->where($db->quoteName('profile_key') . ' IN (' . implode(',', $keys) . ')');
+ $db->setQuery($query);
+ $db->execute();
+
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('ordering'))
+ ->from($db->quoteName('#__user_profiles'))
+ ->where($db->quoteName('user_id') . ' = ' . (int) $userId);
+ $db->setQuery($query);
+ $usedOrdering = $db->loadColumn();
+
+ $tuples = array();
+ $order = 1;
+
+ foreach ($data['profile'] as $k => $v)
+ {
+ while (in_array($order, $usedOrdering))
+ {
+ $order++;
+ }
+
+ $tuples[] = '(' . $userId . ', ' . $db->quote('profile.' . $k) . ', ' . $db->quote(json_encode($v)) . ', ' . ($order++) . ')';
+ }
+
+ $db->setQuery('INSERT INTO #__user_profiles VALUES ' . implode(', ', $tuples));
+ $db->execute();
+ }
+ catch (RuntimeException $e)
+ {
+ $this->_subject->setError($e->getMessage());
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Remove all user profile information for the given user ID
+ *
+ * Method is called after user data is deleted from the database
+ *
+ * @param array $user Holds the user data
+ * @param boolean $success True if user was succesfully stored in the database
+ * @param string $msg Message
+ *
+ * @return boolean
+ */
+ public function onUserAfterDelete($user, $success, $msg)
+ {
+ if (!$success)
+ {
+ return false;
+ }
+
+ $userId = ArrayHelper::getValue($user, 'id', 0, 'int');
+
+ if ($userId)
+ {
+ try
+ {
+ $db = JFactory::getDbo();
+ $db->setQuery(
+ 'DELETE FROM #__user_profiles WHERE user_id = ' . $userId
+ . " AND profile_key LIKE 'profile.%'"
+ );
+
+ $db->execute();
+ }
+ catch (Exception $e)
+ {
+ $this->_subject->setError($e->getMessage());
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/user/profile/profile.xml b/plugins/user/profile/profile.xml
new file mode 100644
index 0000000..57227ca
--- /dev/null
+++ b/plugins/user/profile/profile.xml
@@ -0,0 +1,310 @@
+
+
+ plg_user_profile
+ Joomla! Project
+ January 2008
+ (C) 2005 - 2018 Open Source Matters. All rights reserved.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 3.0.0
+ PLG_USER_PROFILE_XML_DESCRIPTION
+
+ profile.php
+ profiles
+ field
+
+
+ en-GB.plg_user_profile.ini
+ en-GB.plg_user_profile.sys.ini
+
+
+
+
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JDISABLED
+
+
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+ JOPTION_REQUIRED
+ JOPTION_OPTIONAL
+ JDISABLED
+
+
+
+
+
diff --git a/plugins/user/profile/profiles/index.html b/plugins/user/profile/profiles/index.html
new file mode 100644
index 0000000..2efb97f
--- /dev/null
+++ b/plugins/user/profile/profiles/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/user/profile/profiles/profile.xml b/plugins/user/profile/profiles/profile.xml
new file mode 100644
index 0000000..77b0e96
--- /dev/null
+++ b/plugins/user/profile/profiles/profile.xml
@@ -0,0 +1,130 @@
+
+
diff --git a/plugins/xmap/com_content/com_content.php b/plugins/xmap/com_content/com_content.php
new file mode 100644
index 0000000..c66076f
--- /dev/null
+++ b/plugins/xmap/com_content/com_content.php
@@ -0,0 +1,513 @@
+link);
+ if (!isset($link_query['query'])) {
+ return;
+ }
+
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $view = JArrayHelper::getValue($link_vars, 'view', '');
+ $layout = JArrayHelper::getValue($link_vars, 'layout', '');
+ $id = JArrayHelper::getValue($link_vars, 'id', 0);
+
+ //----- Set add_images param
+ $params['add_images'] = JArrayHelper::getValue($params, 'add_images', 0);
+
+ //----- Set add pagebreaks param
+ $add_pagebreaks = JArrayHelper::getValue($params, 'add_pagebreaks', 1);
+ $params['add_pagebreaks'] = JArrayHelper::getValue($params, 'add_pagebreaks', 1);
+
+ switch ($view) {
+ case 'category':
+ if ($id) {
+ $node->uid = 'com_contentc' . $id;
+ } else {
+ $node->uid = 'com_content' . $layout;
+ }
+ $node->expandible = true;
+ break;
+ case 'article':
+ $node->uid = 'com_contenta' . $id;
+ $node->expandible = false;
+
+ $query = $db->getQuery(true);
+
+ $query->select($db->quoteName('created'))
+ ->select($db->quoteName('modified'))
+ ->from($db->quoteName('#__content'))
+ ->where($db->quoteName('id').'='.intval($id));
+
+ if ($params['add_pagebreaks'] || $params['add_images']){
+ $query->select($db->quoteName('introtext'))
+ ->select($db->quoteName('fulltext'));
+ }
+
+
+ $db->setQuery($query);
+ if (($row = $db->loadObject()) != NULL) {
+ $node->modified = $row->modified;
+
+ $text = @$item->introtext . @$item->fulltext;
+ if ($params['add_images']) {
+ $node->images = XmapHelper::getImages($text,JArrayHelper::getValue($params, 'max_images', 1000));
+ }
+
+ if ($params['add_pagebreaks']) {
+ $node->subnodes = XmapHelper::getPagebreaks($text,$node->link);
+ $node->expandible = (count($node->subnodes) > 0); // This article has children
+ }
+ }
+ break;
+ case 'archive':
+ $node->expandible = true;
+ break;
+ case 'featured':
+ $node->uid = 'com_contentfeatured';
+ $node->expandible = false;
+ }
+ }
+
+ /**
+ * Expands a com_content menu item
+ *
+ * @return void
+ * @since 1.0
+ */
+ static function getTree($xmap, $parent, &$params)
+ {
+ $db = JFactory::getDBO();
+ $app = JFactory::getApplication();
+ $user = JFactory::getUser();
+ $result = null;
+
+ $link_query = parse_url($parent->link);
+ if (!isset($link_query['query'])) {
+ return;
+ }
+
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $view = JArrayHelper::getValue($link_vars, 'view', '');
+ $id = intval(JArrayHelper::getValue($link_vars, 'id', ''));
+
+ /* * *
+ * Parameters Initialitation
+ * */
+ //----- Set expand_categories param
+ $expand_categories = JArrayHelper::getValue($params, 'expand_categories', 1);
+ $expand_categories = ( $expand_categories == 1
+ || ( $expand_categories == 2 && $xmap->view == 'xml')
+ || ( $expand_categories == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['expand_categories'] = $expand_categories;
+
+ //----- Set expand_featured param
+ $expand_featured = JArrayHelper::getValue($params, 'expand_featured', 1);
+ $expand_featured = ( $expand_featured == 1
+ || ( $expand_featured == 2 && $xmap->view == 'xml')
+ || ( $expand_featured == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['expand_featured'] = $expand_featured;
+
+ //----- Set expand_featured param
+ $include_archived = JArrayHelper::getValue($params, 'include_archived', 2);
+ $include_archived = ( $include_archived == 1
+ || ( $include_archived == 2 && $xmap->view == 'xml')
+ || ( $include_archived == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['include_archived'] = $include_archived;
+
+ //----- Set show_unauth param
+ $show_unauth = JArrayHelper::getValue($params, 'show_unauth', 1);
+ $show_unauth = ( $show_unauth == 1
+ || ( $show_unauth == 2 && $xmap->view == 'xml')
+ || ( $show_unauth == 3 && $xmap->view == 'html'));
+ $params['show_unauth'] = $show_unauth;
+
+ //----- Set add_images param
+ $add_images = JArrayHelper::getValue($params, 'add_images', 0) && $xmap->isImages;
+ $add_images = ( $add_images && $xmap->view == 'xml');
+ $params['add_images'] = $add_images;
+ $params['max_images'] = JArrayHelper::getValue($params, 'max_images', 1000);
+
+ //----- Set add pagebreaks param
+ $add_pagebreaks = JArrayHelper::getValue($params, 'add_pagebreaks', 1);
+ $add_pagebreaks = ( $add_pagebreaks == 1
+ || ( $add_pagebreaks == 2 && $xmap->view == 'xml')
+ || ( $add_pagebreaks == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['add_pagebreaks'] = $add_pagebreaks;
+
+ if ($params['add_pagebreaks'] && !defined('_XMAP_COM_CONTENT_LOADED')) {
+ define('_XMAP_COM_CONTENT_LOADED',1); // Load it just once
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_content_pagebreak');
+ }
+
+ //----- Set cat_priority and cat_changefreq params
+ $priority = JArrayHelper::getValue($params, 'cat_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'cat_changefreq', $parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+
+ //----- Set art_priority and art_changefreq params
+ $priority = JArrayHelper::getValue($params, 'art_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'art_changefreq', $parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['art_priority'] = $priority;
+ $params['art_changefreq'] = $changefreq;
+
+ $params['max_art'] = intval(JArrayHelper::getValue($params, 'max_art', 0));
+ $params['max_art_age'] = intval(JArrayHelper::getValue($params, 'max_art_age', 0));
+
+ $params['nullDate'] = $db->Quote($db->getNullDate());
+
+ $params['nowDate'] = $db->Quote(JFactory::getDate()->toSql());
+ $params['groups'] = implode(',', $user->getAuthorisedViewLevels());
+
+ // Define the language filter condition for the query
+ $params['language_filter'] = $app->getLanguageFilter();
+
+ switch ($view) {
+ case 'category':
+ if (!$id) {
+ $id = intval(JArrayHelper::getValue($params, 'id', 0));
+ }
+ if ($params['expand_categories'] && $id) {
+ $result = self::expandCategory($xmap, $parent, $id, $params, $parent->id);
+ }
+ break;
+ case 'featured':
+ if ($params['expand_featured']) {
+ $result = self::includeCategoryContent($xmap, $parent, 'featured', $params,$parent->id);
+ }
+ break;
+ case 'categories':
+ if ($params['expand_categories']) {
+ $result = self::expandCategory($xmap, $parent, ($id ? $id : 1), $params, $parent->id);
+ }
+ break;
+ case 'archive':
+ if ($params['expand_featured']) {
+ $result = self::includeCategoryContent($xmap, $parent, 'archived', $params,$parent->id);
+ }
+ break;
+ case 'article':
+ // if it's an article menu item, we have to check if we have to expand the
+ // article's page breaks
+ if ($params['add_pagebreaks']){
+ $query = $db->getQuery(true);
+
+ $query->select($db->quoteName('introtext'))
+ ->select($db->quoteName('fulltext'))
+ ->select($db->quoteName('alias'))
+ ->select($db->quoteName('catid'))
+ ->from($db->quoteName('#__content'))
+ ->where($db->quoteName('id').'='.intval($id));
+ $db->setQuery($query);
+
+ $row = $db->loadObject();
+
+ $parent->slug = $row->alias ? ($id . ':' . $row->alias) : $id;
+ $parent->link = ContentHelperRoute::getArticleRoute($parent->slug, $row->catid);
+
+ $subnodes = XmapHelper::getPagebreaks($row->introtext.$row->fulltext,$parent->link);
+ self::printNodes($xmap, $parent, $params, $subnodes);
+ }
+
+ }
+ return $result;
+ }
+
+ /**
+ * Get all content items within a content category.
+ * Returns an array of all contained content items.
+ *
+ * @param object $xmap
+ * @param object $parent the menu item
+ * @param int $catid the id of the category to be expanded
+ * @param array $params an assoc array with the params for this plugin on Xmap
+ * @param int $itemid the itemid to use for this category's children
+ */
+ static function expandCategory($xmap, $parent, $catid, &$params, $itemid)
+ {
+ $db = JFactory::getDBO();
+
+ $where = array('a.parent_id = ' . $catid . ' AND a.published = 1 AND a.extension=\'com_content\'');
+
+ if ($params['language_filter'] ) {
+ $where[] = 'a.language in ('.$db->quote(JFactory::getLanguage()->getTag()).','.$db->quote('*').')';
+ }
+
+ if (!$params['show_unauth']) {
+ $where[] = 'a.access IN (' . $params['groups'] . ') ';
+ }
+
+ $orderby = 'a.lft';
+ $query = 'SELECT a.id, a.title, a.alias, a.access, a.path AS route, '
+ . 'a.created_time created, a.modified_time modified '
+ . 'FROM #__categories AS a '
+ . 'WHERE '. implode(' AND ',$where)
+ . ( $xmap->view != 'xml' ? "\n ORDER BY " . $orderby . "" : '' );
+
+ $db->setQuery($query);
+ #echo nl2br(str_replace('#__','jos_',$db->getQuery()));exit;
+ $items = $db->loadObjectList();
+
+ if (count($items) > 0) {
+ $xmap->changeLevel(1);
+ foreach ($items as $item) {
+ $node = new stdclass();
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'c' . $item->id;
+ $node->browserNav = $parent->browserNav;
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->name = $item->title;
+ $node->expandible = true;
+ $node->secure = $parent->secure;
+ // TODO: Should we include category name or metakey here?
+ // $node->keywords = $item->metakey;
+ $node->newsItem = 0;
+
+ // For the google news we should use te publication date instead
+ // the last modification date. See
+ if ($xmap->isNews || !$item->modified)
+ $item->modified = $item->created;
+
+ $node->slug = $item->route ? ($item->id . ':' . $item->route) : $item->id;
+ $node->link = ContentHelperRoute::getCategoryRoute($node->slug);
+ if (strpos($node->link,'Itemid=')===false) {
+ $node->itemid = $itemid;
+ $node->link .= '&Itemid='.$itemid;
+ } else {
+ $node->itemid = preg_replace('/.*Itemid=([0-9]+).*/','$1',$node->link);
+ }
+ if ($xmap->printNode($node)) {
+ self::expandCategory($xmap, $parent, $item->id, $params, $node->itemid);
+ }
+ }
+ $xmap->changeLevel(-1);
+ }
+
+ // Include Category's content
+ self::includeCategoryContent($xmap, $parent, $catid, $params, $itemid);
+ return true;
+ }
+
+ /**
+ * Get all content items within a content category.
+ * Returns an array of all contained content items.
+ *
+ * @since 2.0
+ */
+ static function includeCategoryContent($xmap, $parent, $catid, &$params,$Itemid)
+ {
+ $db = JFactory::getDBO();
+
+ // We do not do ordering for XML sitemap.
+ if ($xmap->view != 'xml') {
+ $orderby = self::buildContentOrderBy($parent->params,$parent->id,$Itemid);
+ //$orderby = !empty($menuparams['orderby']) ? $menuparams['orderby'] : (!empty($menuparams['orderby_sec']) ? $menuparams['orderby_sec'] : 'rdate' );
+ //$orderby = self::orderby_sec($orderby);
+ }
+
+ if ($params['include_archived']) {
+ $where = array('(a.state = 1 or a.state = 2)');
+ } else {
+ $where = array('a.state = 1');
+ }
+
+ if ($catid=='featured') {
+ $where[] = 'a.featured=1';
+ } elseif ($catid=='archived') {
+ $where = array('a.state=2');
+ } elseif(is_numeric($catid)) {
+ $where[] = 'a.catid='.(int) $catid;
+ }
+
+ if ($params['max_art_age'] || $xmap->isNews) {
+ $days = (($xmap->isNews && ($params['max_art_age'] > 3 || !$params['max_art_age'])) ? 3 : $params['max_art_age']);
+ $where[] = "( a.created >= '"
+ . date('Y-m-d H:i:s', time() - $days * 86400) . "' ) ";
+ }
+
+ if ($params['language_filter'] ) {
+ $where[] = 'a.language in ('.$db->quote(JFactory::getLanguage()->getTag()).','.$db->quote('*').')';
+ }
+
+ if (!$params['show_unauth'] ){
+ $where[] = 'a.access IN (' . $params['groups'] . ') ';
+ }
+
+ $query = 'SELECT a.id, a.title, a.alias, a.catid, '
+ . 'a.created created, a.modified modified'
+ . ',a.language'
+ . (($params['add_images'] || $params['add_pagebreaks']) ? ',a.introtext, a.fulltext ' : ' ')
+ . 'FROM #__content AS a '
+ . ($catid =='featured'? 'LEFT JOIN #__content_frontpage AS fp ON a.id = fp.content_id ' : ' ')
+ . 'WHERE ' . implode(' AND ',$where) . ' AND '
+ . ' (a.publish_up = ' . $params['nullDate']
+ . ' OR a.publish_up <= ' . $params['nowDate'] . ') AND '
+ . ' (a.publish_down = ' . $params['nullDate']
+ . ' OR a.publish_down >= ' . $params['nowDate'] . ') '
+ . ( $xmap->view != 'xml' ? "\n ORDER BY $orderby " : '' )
+ . ( $params['max_art'] ? "\n LIMIT {$params['max_art']}" : '');
+
+ $db->setQuery($query);
+ //echo nl2br(str_replace('#__','mgbj2_',$db->getQuery()));
+ $items = $db->loadObjectList();
+
+ if (count($items) > 0) {
+ $xmap->changeLevel(1);
+ foreach ($items as $item) {
+ $node = new stdclass();
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'a' . $item->id;
+ $node->browserNav = $parent->browserNav;
+ $node->priority = $params['art_priority'];
+ $node->changefreq = $params['art_changefreq'];
+ $node->name = $item->title;
+ $node->modified = $item->modified;
+ $node->expandible = false;
+ $node->secure = $parent->secure;
+ // TODO: Should we include category name or metakey here?
+ // $node->keywords = $item->metakey;
+ $node->newsItem = 1;
+ $node->language = $item->language;
+
+ // For the google news we should use te publication date instead
+ // the last modification date. See
+ if ($xmap->isNews || !$node->modified)
+ $node->modified = $item->created;
+
+ $node->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id;
+ //$node->catslug = $item->category_route ? ($catid . ':' . $item->category_route) : $catid;
+ $node->catslug = $item->catid;
+ $node->link = ContentHelperRoute::getArticleRoute($node->slug, $node->catslug);
+
+ // Add images to the article
+ $text = @$item->introtext . @$item->fulltext;
+ if ($params['add_images']) {
+ $node->images = XmapHelper::getImages($text,$params['max_images']);
+ }
+
+ if ($params['add_pagebreaks']) {
+ $subnodes = XmapHelper::getPagebreaks($text,$node->link);
+ $node->expandible = (count($subnodes) > 0); // This article has children
+ }
+
+ if ($xmap->printNode($node) && $node->expandible) {
+ self::printNodes($xmap, $parent, $params, $subnodes);
+ }
+ }
+ $xmap->changeLevel(-1);
+ }
+ return true;
+ }
+
+ static private function printNodes($xmap, $parent, &$params, &$subnodes)
+ {
+ $xmap->changeLevel(1);
+ $i=0;
+ foreach ($subnodes as $subnode) {
+ $i++;
+ $subnode->id = $parent->id;
+ $subnode->uid = $parent->uid.'p'.$i;
+ $subnode->browserNav = $parent->browserNav;
+ $subnode->priority = $params['art_priority'];
+ $subnode->changefreq = $params['art_changefreq'];
+ $subnode->secure = $parent->secure;
+ $xmap->printNode($subnode);
+ }
+ $xmap->changeLevel(-1);
+ }
+
+ /**
+ * Generates the order by part of the query according to the
+ * menu/component/user settings. It checks if the current user
+ * has already changed the article's ordering column in the frontend
+ *
+ * @param JRegistry $params
+ * @param int $parentId
+ * @param int $itemid
+ * @return string
+ */
+ static function buildContentOrderBy(&$params,$parentId,$itemid)
+ {
+ $app = JFactory::getApplication('site');
+
+ // Case when the child gets a different menu itemid than it's parent
+ if ($parentId != $itemid) {
+ $menu = $app->getMenu();
+ $item = $menu->getItem($itemid);
+ $menuParams = clone($params);
+ $itemParams = new JRegistry($item->params);
+ $menuParams->merge($itemParams);
+ } else {
+ $menuParams =& $params;
+ }
+
+ $filter_order = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order', 'filter_order', '', 'string');
+ $filter_order_Dir = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order_Dir', 'filter_order_Dir', '', 'cmd');
+ $orderby = ' ';
+
+ if ($filter_order && $filter_order_Dir) {
+ $orderby .= $filter_order . ' ' . $filter_order_Dir . ', ';
+ }
+
+ $articleOrderby = $menuParams->get('orderby_sec', 'rdate');
+ $articleOrderDate = $menuParams->get('order_date');
+ //$categoryOrderby = $menuParams->def('orderby_pri', '');
+ $secondary = ContentHelperQuery::orderbySecondary($articleOrderby, $articleOrderDate) . ', ';
+ //$primary = ContentHelperQuery::orderbyPrimary($categoryOrderby);
+
+ //$orderby .= $primary . ' ' . $secondary . ' a.created ';
+ $orderby .= $secondary . ' a.created ';
+
+ return $orderby;
+ }
+}
\ No newline at end of file
diff --git a/plugins/xmap/com_content/com_content.xml b/plugins/xmap/com_content/com_content.xml
new file mode 100644
index 0000000..8b7289e
--- /dev/null
+++ b/plugins/xmap/com_content/com_content.xml
@@ -0,0 +1,128 @@
+
+
+
+ Xmap - Content Plugin
+ Guillermo Vargas
+ 01/26/2011
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 2.0.4
+ XMAP_CONTENT_PLUGIN_DESCRIPTION
+
+ com_content.php
+ index.html
+
+
+
+ en-GB.plg_xmap_com_content.ini
+ es-ES.plg_xmap_com_content.ini
+ fa-IR.plg_xmap_com_content.ini
+ cs-CZ.plg_xmap_com_content.ini
+ nl-NL.plg_xmap_com_content.ini
+ ru-RU.plg_xmap_com_content.ini
+
+
+
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+
+
+
+
+ JYES
+ JNO
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+ XMAP_SETTING_NEWS_KEYWORDS_METAKEYS
+ XMAP_SETTING_NEWS_KEYWORDS_CATTITLE
+ XMAP_SETTING_NEWS_KEYWORDS_METAKEYS_CATTITLE
+ XMAP_SETTING_NEWS_KEYWORDS_NONE
+
+
+
+
+
diff --git a/plugins/xmap/com_content/index.html b/plugins/xmap/com_content/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_content/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/xmap/com_k2/com_k2.php b/plugins/xmap/com_k2/com_k2.php
new file mode 100644
index 0000000..0db72ca
--- /dev/null
+++ b/plugins/xmap/com_k2/com_k2.php
@@ -0,0 +1,343 @@
+link );
+ parse_str( html_entity_decode($link_query['query']), $link_vars);
+ $parm_vars = $parent->params->toArray();
+
+ $option = xmap_com_k2::getParam($link_vars,'option',"");
+ if ($option != "com_k2")
+ return;
+
+ $view = xmap_com_k2::getParam($link_vars,'view',"");
+ $showMode = xmap_com_k2::getParam($params, 'showk2items', "always");
+
+ if ($showMode == "never" || ($showMode == "xml" && $xmap->view == "html") || ($showMode == "html" && $xmap->view == "xml"))
+ return;
+ self::$suppressDups = (xmap_com_k2::getParam($params,'suppressdups', 'yes') == "yes");
+ self::$suppressSub = (xmap_com_k2::getParam($params,'subcategories',"yes") != "yes");
+
+ if ($view == "item") // for Items the sitemap already contains the correct reference
+ {
+ if (!isset($xmap->IDS))
+ $xmap->IDS = "";
+ $xmap->IDS = $xmap->IDS."|".xmap_com_k2::getParam($link_vars, 'id', $id);
+ return;
+ }
+
+ if ($xmap->view == "xml")
+ self::$maxAccess = 1; // XML sitemaps will only see content for guests
+ else
+ self::$maxAccess = implode(",", JFactory::getUser()->getAuthorisedViewLevels());
+
+ switch(xmap_com_k2::getParam($link_vars,'task',""))
+ {
+ case "user":
+ $tag = xmap_com_k2::getParam($link_vars, 'id', $id);
+ $ids = array_key_exists('userCategoriesFilter',$parm_vars) ? $parm_vars['userCategoriesFilter'] : array("");
+ $mode = "single user";
+ break;
+ case "tag":
+ $tag = xmap_com_k2::getParam($link_vars, 'tag',"");
+ $ids = array_key_exists('categoriesFilter',$parm_vars) ? $parm_vars['categoriesFilter'] : array("");
+ $mode = "tag";
+ break;
+ case "category":
+ $ids = explode("|", xmap_com_k2::getParam($link_vars, 'id',""));
+ $mode = "category";
+ break;
+ case "":
+ switch(xmap_com_k2::getParam($link_vars,'layout',""))
+ {
+ case "category":
+ if(array_key_exists('categories', $parm_vars)) $ids = $parm_vars["categories"];
+ else $ids = '';
+ $mode = "categories";
+ break;
+ case "latest":
+ $limit = xmap_com_k2::getParam($parm_vars, 'latestItemsLimit', "");
+ if (xmap_com_k2::getParam($parm_vars, 'source', "") == "0")
+ {
+ $ids = array_key_exists("userIDs",$parm_vars) ? $parm_vars["userIDs"] : '';
+ $mode = "latest user";
+ }
+ else
+ {
+ $ids = array_key_exists("categoryIDs",$parm_vars) ? $parm_vars["categoryIDs"] : '';
+ $mode = "latest category";
+ }
+ break;
+ default:
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ $priority = xmap_com_k2::getParam($params,'priority',$parent->priority);
+ $changefreq = xmap_com_k2::getParam($params,'changefreq',$parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['priority'] = $priority;
+ $params['changefreq'] = $changefreq;
+
+ $db = JFactory::getDBO();
+ xmap_com_k2::processTree($db, $xmap, $parent, $params, $mode, $ids, $tag, $limit);
+
+ return;
+ }
+
+ static function collectByCat($db, $catid, &$allrows)
+ {
+ if (trim($catid) == "") // in this case something strange went wrong
+ return;
+ $query = "select id,title,alias,UNIX_TIMESTAMP(created) as created, UNIX_TIMESTAMP(modified) as modified, metakey from #__k2_items where "
+ ."published = 1 and trash = 0 and (publish_down = \"0000-00-00\" OR publish_down > NOW()) "
+ ."and catid = ".$catid. " order by 1 desc";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ if ($rows != null)
+ $allrows = array_merge($allrows, $rows);
+ $query = "select id, name, alias from #__k2_categories where published = 1 and trash = 0 and parent = ".$catid." order by id";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ if ($rows == null)
+ $rows = array();
+
+ foreach ($rows as $row)
+ {
+ xmap_com_k2::collectByCat($db, $row->id, $allrows);
+ }
+ }
+
+ static function processTree($db, &$xmap, &$parent, &$params, $mode, $ids, $tag, $limit)
+ {
+ $baseQuery = "select id,title,alias,UNIX_TIMESTAMP(created) as created, UNIX_TIMESTAMP(modified) as modified, metakey from #__k2_items where "
+ ."published = 1 and trash = 0 and (publish_down = \"0000-00-00\" OR publish_down > NOW()) and "
+ ."access in (".self::$maxAccess.") and ";
+
+ switch($mode)
+ {
+ case "single user":
+ $query = $baseQuery."created_by = ".$tag." ";
+ if ($ids[0] != "")
+ $query .= " and catid in (".implode(",", $ids).")";
+ $query .= " order by 1 DESC ";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ break;
+ case "tag":
+ $query = "SELECT c.id, title, alias, UNIX_TIMESTAMP(c.created) as created, UNIX_TIMESTAMP(c.modified) as modified FROM #__k2_tags a, #__k2_tags_xref b, #__k2_items c where "."c.published = 1 and c.trash = 0 and (c.publish_down = \"0000-00-00\" OR c.publish_down > NOW()) "
+ ."and a.Name = '".$tag."' and a.id = b.tagId and c.id = b.itemID and c.access in (".self::$maxAccess.")";
+ if ($ids[0] != "")
+ $query .= " and c.catid in (".implode(",", $ids).")";
+ $query .= " order by 1 DESC ";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ break;
+ case "category":
+ $query = $baseQuery."catid = ".$ids[0]." order by 1 DESC ";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ break;
+ case "categories":
+ if (!self::$suppressSub)
+ {
+ if($ids) $query = $baseQuery."catid in (".implode(",", $ids).") order by 1 DESC ";
+ else $query = $baseQuery."1 order by 1 DESC ";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList ();
+ }
+ else
+ {
+ $rows = array();
+ if (is_array($ids))
+ {
+ foreach($ids as $id)
+ {
+ $allrows = array();
+ xmap_com_k2::collectByCat($db, $id, $allrows);
+ $rows = array_merge($rows, $allrows);
+ }
+ }
+ }
+ break;
+ case "latest user":
+ $rows = array();
+ if (is_array($ids))
+ {
+ foreach ($ids as $id)
+ {
+ $query = $baseQuery."created_by = ".$id." order by 1 DESC LIMIT ".$limit;
+ $db->setQuery($query);
+ $res = $db->loadObjectList();
+ if ($res != null)
+ $rows = array_merge($rows, $res);
+ }
+ }
+ break;
+ case "latest category":
+ $rows = array();
+ if (is_array($ids))
+ {
+ foreach ($ids as $id)
+ {
+ $query = $baseQuery."catid = ".$id." order by 1 DESC LIMIT ".$limit;
+ $db->setQuery($query);
+ $res = $db->loadObjectList();
+ if ($res != null)
+ $rows = array_merge($rows, $res);
+ }
+ }
+ break;
+ default:
+ return;
+ }
+
+ $xmap->changeLevel(1);
+ $node = new stdclass ();
+ $node->id = $parent->id;
+
+ if ($rows == null)
+ {
+ $rows = array();
+ }
+ foreach ($rows as $row )
+ {
+ if (!(self::$suppressDups && isset($xmap->IDS) && strstr($xmap->IDS, "|".$row->id)))
+ xmap_com_k2::addNode($xmap, $node, $row, false, $parent, $params);
+ }
+
+ if ($mode == "category" && !self::$suppressSub)
+ {
+ $query = "select id, name, alias from #__k2_categories where published = 1 and trash = 0 and parent = ".$ids[0]
+ ." and access in (".self::$maxAccess.") order by id";
+ $db->setQuery($query);
+ $rows = $db->loadObjectList();
+ if ($rows == null)
+ {
+ $rows = array();
+ }
+
+ foreach ($rows as $row)
+ {
+ if (!isset($xmap->IDS))
+ $xmap->IDS = "";
+ if (!(self::$suppressDups && strstr($xmap->IDS, "|c".$row->id)))
+ {
+ xmap_com_k2::addNode($xmap, $node, $row, true, $parent, $params);
+ $newID = array();
+ $newID[0] = $row->id;
+ xmap_com_k2::processTree($db, $xmap, $parent, $params, $mode, $newID, "", "");
+ }
+ }
+ }
+ $xmap->changeLevel (-1);
+ }
+
+ static function addNode($xmap, $node, $row, $iscat, &$parent, &$params)
+ {
+ $sef = ($_REQUEST['option'] == "com_sefservicemap"); // verallgemeinern
+
+ if ($xmap->isNews && ($row->modified ? $row->modified : $row->created) > ($xmap->now - (2 * 86400)))
+ {
+ $node->newsItem = 1;
+ $node->keywords = $row->metakey;
+ }
+ else
+ {
+ $node->newsItem = 0;
+ $node->keywords = "";
+ }
+ if (!isset($xmap->IDS))
+ $xmap->IDS = "";
+
+ $node->browserNav = $parent->browserNav;
+ $node->pid = $row->id;
+ $node->uid = $parent->uid . 'item' . $row->id;
+ if (isset($row->modified) || isset($row->created))
+ $node->modified = (isset($row->modified) ? $row->modified : $row->created);
+
+ if ($sef)
+ $node->modified = date('Y-m-d',$node->modified);
+
+ $node->name = ($iscat ? $row->name : $row->title);
+
+ $node->priority = $params['priority'];
+ $node->changefreq = $params['changefreq'];
+
+ if ($iscat)
+ {
+ $xmap->IDS .= "|c".$row->id;
+ $node->link = 'index.php?option=com_k2&view=itemlist&task=category&id='.$row->id.':'.$row->alias.'&Itemid='.$parent->id;
+ $node->expandible = true;
+ }
+ else
+ {
+ $xmap->IDS .= "|".$row->id;
+ $node->link = 'index.php?option=com_k2&view=item&id='.$row->id.':'.$row->alias.'&Itemid='.$parent->id;
+ $node->expandible = false;
+ }
+ $node->tree = array ();
+ $xmap->printNode($node);
+
+ }
+
+ static function &getParam($arr, $name, $def)
+ {
+ $var = JArrayHelper::getValue( $arr, $name, $def, '' );
+ return $var;
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/plugins/xmap/com_k2/com_k2.xml b/plugins/xmap/com_k2/com_k2.xml
new file mode 100644
index 0000000..65f2202
--- /dev/null
+++ b/plugins/xmap/com_k2/com_k2.xml
@@ -0,0 +1,70 @@
+
+
+ XMAP_PLUGIN_K2
+ Mohammad Hasani Eghtedar
+ November 2011
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ m.h.eghtedar@gmail.com
+ https://github.com/mhehm/Xmap
+ 1.3
+ XMAP_PLUGIN_K2_DESC
+
+ com_k2.php
+ index.html
+
+
+ en-GB/en-GB.plg_xmap_com_k2.ini
+ en-GB/en-GB.plg_xmap_com_k2.sys.ini
+ fr-FR/fr-FR.plg_xmap_com_k2.ini
+ fr-FR/fr-FR.plg_xmap_com_k2.sys.ini
+ fa-IR/fa-IR.plg_xmap_com_k2.ini
+ fa-IR/fa-IR.plg_xmap_com_k2.sys.ini
+
+
+
+
+
+ JYES
+ JNO
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ JYES
+ JNO
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_k2/index.html b/plugins/xmap/com_k2/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_k2/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/xmap/com_kunena/com_kunena.php b/plugins/xmap/com_kunena/com_kunena.php
new file mode 100644
index 0000000..009614d
--- /dev/null
+++ b/plugins/xmap/com_kunena/com_kunena.php
@@ -0,0 +1,302 @@
+link);
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $catid = intval(JArrayHelper::getValue($link_vars, 'catid', 0));
+ $id = intval(JArrayHelper::getValue($link_vars, 'id', 0));
+ $func = JArrayHelper::getValue($link_vars, 'func', '', '');
+ if ($func = 'showcat' && $catid) {
+ $node->uid = 'com_kunenac' . $catid;
+ $node->expandible = false;
+ } elseif ($func = 'view' && $id) {
+ $node->uid = 'com_kunenaf' . $id;
+ $node->expandible = false;
+ }
+ }
+
+ static function getTree($xmap, $parent, &$params)
+ {
+ if ($xmap->isNews) // This component does not provide news content. don't waste time/resources
+ return false;
+
+ // Make sure that we can load the kunena api
+ if (!xmap_com_kunena::loadKunenaApi()) {
+ return false;
+ }
+
+ if (!self::$profile) {
+ self::$config = KunenaFactory::getConfig ();;
+ self::$profile = KunenaFactory::getUser ();
+ }
+
+ $user = JFactory::getUser();
+ $catid = 0;
+
+ $link_query = parse_url($parent->link);
+ if (!isset($link_query['query'])) {
+ return;
+ }
+
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $view = JArrayHelper::getValue($link_vars, 'view', '');
+
+ switch ($view){
+ case 'showcat': case 'category':
+ $link_query = parse_url($parent->link);
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $catid = JArrayHelper::getValue($link_vars, 'catid', 0);
+ break;
+ case 'listcat':
+ case 'entrypage':
+ $catid = 0;
+ break;
+ default:
+ return true; // Do not expand links to posts
+ }
+
+ $include_topics = JArrayHelper::getValue($params, 'include_topics', 1);
+ $include_topics = ( $include_topics == 1
+ || ( $include_topics == 2 && $xmap->view == 'xml')
+ || ( $include_topics == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['include_topics'] = $include_topics;
+
+ $priority = JArrayHelper::getValue($params, 'cat_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'cat_changefreq', $parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+ $params['groups'] = implode(',', $user->getAuthorisedViewLevels());
+
+ $priority = JArrayHelper::getValue($params, 'topic_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'topic_changefreq', $parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['topic_priority'] = $priority;
+ $params['topic_changefreq'] = $changefreq;
+
+ if ($include_topics) {
+ $ordering = JArrayHelper::getValue($params, 'topics_order', 'ordering');
+ if ( !in_array($ordering,array('id', 'ordering','time','subject','hits')) )
+ $ordering = 'ordering';
+ $params['topics_order'] = 't.`'.$ordering.'`';
+ $params['include_pagination'] = ($xmap->view == 'xml');
+
+ $params['limit'] = '';
+ $params['days'] = '';
+ $limit = JArrayHelper::getValue($params, 'max_topics', '');
+ if (intval($limit))
+ $params['limit'] = ' LIMIT ' . $limit;
+
+ $days = JArrayHelper::getValue($params, 'max_age', '');
+ $params['days'] = false;
+ if (intval($days))
+ $params['days'] = ($xmap->now - (intval($days) * 86400));
+ }
+
+ $params['table_prefix'] = xmap_com_kunena::getTablePrefix();
+
+ xmap_com_kunena::getCategoryTree($xmap, $parent, $params, $catid);
+ }
+
+ /*
+ * Builds the Kunena's tree
+ */
+ static function getCategoryTree($xmap, $parent, &$params, $parentCat)
+ {
+ $db = JFactory::getDBO();
+
+ // Load categories
+ if (self::getKunenaMajorVersion() >= '2.0') {
+ // Kunena 2.0+
+ $catlink = 'index.php?option=com_kunena&view=category&catid=%s&Itemid='.$parent->id;
+ $toplink = 'index.php?option=com_kunena&view=topic&catid=%s&id=%s&Itemid='.$parent->id;
+
+ // kimport('kunena.forum.category.helper');
+ $categories = KunenaForumCategoryHelper::getChildren($parentCat);
+ } else {
+ $catlink = 'index.php?option=com_kunena&func=showcat&catid=%s&Itemid='.$parent->id;
+ $toplink = 'index.php?option=com_kunena&func=view&catid=%s&id=%s&Itemid='.$parent->id;
+
+ if (self::getKunenaMajorVersion() >= '1.6') {
+ // Kunena 1.6+
+ kimport('session');
+ $session = KunenaFactory::getSession();
+ $session->updateAllowedForums();
+ $allowed = $session->allowed;
+ $query = "SELECT id, name FROM `#__kunena_categories` WHERE parent={$parentCat} AND id IN ({$allowed}) ORDER BY ordering";
+ } else {
+ // Kunena 1.0+
+ $query = "SELECT id, name FROM `{$params['table_prefix']}_categories` WHERE parent={$parentCat} AND published=1 AND pub_access=0 ORDER BY ordering";
+ }
+ $db->setQuery($query);
+ $categories = $db->loadObjectList();
+ }
+
+ /* get list of categories */
+ $xmap->changeLevel(1);
+ foreach ($categories as $cat) {
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->browserNav = $parent->browserNav;
+ $node->uid = 'com_kunenac' . $cat->id;
+ $node->name = $cat->name;
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->link = sprintf($catlink, $cat->id);
+ $node->expandible = true;
+ $node->secure = $parent->secure;
+ if ($xmap->printNode($node) !== FALSE) {
+ xmap_com_kunena::getCategoryTree($xmap, $parent, $params, $cat->id);
+ }
+ }
+
+ if ($params['include_topics']) {
+ if (self::getKunenaMajorVersion() >= '2.0') {
+ // Kunena 2.0+
+ // kimport('kunena.forum.topic.helper');
+ // TODO: orderby parameter is missing:
+ $topics = KunenaForumTopicHelper::getLatestTopics($parentCat, 0, $params['limit'], array('starttime', $params['days']));
+ if (count($topics)==2 && is_numeric($topics[0])){
+ $topics = $topics[1];
+ }
+ } else {
+ $access = KunenaFactory::getAccessControl();
+ $hold = $access->getAllowedHold(self::$profile, $parentCat);
+ // Kunena 1.0+
+ $query = "SELECT t.id, t.catid, t.subject, max(m.time) as time, count(m.id) as msgcount
+ FROM {$params['table_prefix']}_messages t
+ INNER JOIN {$params['table_prefix']}_messages AS m ON t.id = m.thread
+ WHERE t.catid=$parentCat AND t.parent=0
+ AND t.hold in ({$hold})
+ GROUP BY m.`thread`
+ ORDER BY {$params['topics_order']} DESC";
+
+ if ($params['days']) {
+ $query = "SELECT * FROM ($query) as topics WHERE time >= {$params['days']}";
+ }
+ #echo str_replace('#__','mgbj2_',$query);
+ $db->setQuery($query, 0, $params['limit']);
+ $topics = $db->loadObjectList();
+ }
+
+ //get list of topics
+ foreach ($topics as $topic) {
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->browserNav = $parent->browserNav;
+ $node->uid = 'com_kunenat' . $topic->id;
+ $node->name = $topic->subject;
+ $node->priority = $params['topic_priority'];
+ $node->changefreq = $params['topic_changefreq'];
+ $node->modified = intval(@$topic->last_post_time? $topic->last_post_time : $topic->time);
+ $node->link = sprintf($toplink, (@$topic->category_id? $topic->category_id : $topic->catid), $topic->id);
+ $node->expandible = false;
+ $node->secure = $parent->secure;
+ if ($xmap->printNode($node) !== FALSE) {
+ // Pagination will not work with K2.0, revisit this when that version is out and stable
+ if ($params['include_pagination'] && isset($topic->msgcount) && $topic->msgcount > self::$config->messages_per_page ){
+ $msgPerPage = self::$config->messages_per_page;
+ $threadPages = ceil ( $topic->msgcount / $msgPerPage );
+ for ($i=2;$i<=$threadPages;$i++) {
+ $subnode = new stdclass;
+ $subnode->id = $node->id;
+ $subnode->uid = $node->uid.'p'.$i;
+ $subnode->name = "[$i]";
+ $subnode->seq = $i;
+ $subnode->link = $node->link.'&limit='.$msgPerPage.'&limitstart='.(($i-1)*$msgPerPage);
+ $subnode->browserNav = $node->browserNav;
+ $subnode->priority = $node->priority;
+ $subnode->changefreq = $node->changefreq;
+ $subnode->modified = $node->modified;
+ $subnode->secure = $node->secure;
+ $xmap->printNode($subnode);
+ }
+ }
+ }
+ }
+ }
+ $xmap->changeLevel(-1);
+ }
+
+ private static function loadKunenaApi()
+ {
+ if (!defined('KUNENA_LOADED')) {
+ jimport ( 'joomla.application.component.helper' );
+ // Check if Kunena component is installed/enabled
+ if (! JComponentHelper::isEnabled ( 'com_kunena', true )) {
+ return false;
+ }
+
+ // Check if Kunena API exists
+ $kunena_api = JPATH_ADMINISTRATOR . '/components/com_kunena/api.php';
+ if (! is_file ( $kunena_api ))
+ return false;
+
+ // Load Kunena API
+ require_once ($kunena_api);
+ }
+ return true;
+ }
+
+
+ /**
+ * Based on Matias' version (Thanks)
+ * See: http://docs.kunena.org/index.php/Developing_Kunena_Router
+ */
+ static function getKunenaMajorVersion() {
+ static $version;
+ if (!$version) {
+ if (class_exists('KunenaForum')) {
+ $version = KunenaForum::versionMajor();
+ } elseif (class_exists('Kunena')) {
+ $version = substr(Kunena::version(), 0, 3);
+ } elseif (is_file(JPATH_ROOT.'/components/com_kunena/lib/kunena.defines.php')) {
+ $version = '1.5';
+ } elseif (is_file(JPATH_ROOT.'/components/com_kunena/lib/kunena.version.php')) {
+ $version = '1.0';
+ }
+ }
+ return $version;
+ }
+
+ static function getTablePrefix() {
+ $version = self::getKunenaMajorVersion();
+ if ($version <= 1.5) {
+ return '#__fb';
+ }
+ return '#__kunena';
+ }
+
+}
diff --git a/plugins/xmap/com_kunena/com_kunena.xml b/plugins/xmap/com_kunena/com_kunena.xml
new file mode 100644
index 0000000..240d690
--- /dev/null
+++ b/plugins/xmap/com_kunena/com_kunena.xml
@@ -0,0 +1,92 @@
+
+
+
+ Xmap - Kunena Plugin
+ Guillermo Vargas
+ September 2007
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 3.0.0
+ Xmap Plugin for Kunena component
+
+ com_kunena.php
+ index.html
+
+
+
+ en-GB.plg_xmap_com_kunena.ini
+ es-ES.plg_xmap_com_kunena.ini
+ fa-IR.plg_xmap_com_kunena.ini
+ cs-CZ.plg_xmap_com_kunena.ini
+ nl-NL.plg_xmap_com_kunena.ini
+ ru-RU.plg_xmap_com_kunena.ini
+
+
+
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_kunena/index.html b/plugins/xmap/com_kunena/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_kunena/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/xmap/com_mtree/com_mtree.php b/plugins/xmap/com_mtree/com_mtree.php
new file mode 100644
index 0000000..c8f71a4
--- /dev/null
+++ b/plugins/xmap/com_mtree/com_mtree.php
@@ -0,0 +1,161 @@
+isNews) // This component does not provide news content. don't waste time/resources
+ return false;
+
+ $db = JFactory::getDbo();
+
+ $catid=0;
+ if ( strpos($parent->link, 'task=listcats') ) {
+ $link_query = parse_url( $parent->link );
+ parse_str( html_entity_decode($link_query['query']), $link_vars);
+ $catid = JArrayHelper::getValue($link_vars,'cat_id',0);
+ }
+
+ $include_links = JArrayHelper::getValue($params,'include_links',1);
+ $include_links = ( $include_links == 1
+ || ( $include_links == 2 && $xmap->view == 'xml')
+ || ( $include_links == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['include_links'] = $include_links;
+
+ $priority = JArrayHelper::getValue($params,'cat_priority',$parent->priority);
+ $changefreq = JArrayHelper::getValue($params,'cat_changefreq',$parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+
+ $priority = JArrayHelper::getValue($params,'link_priority',$parent->priority);
+ $changefreq = JArrayHelper::getValue($params,'link_changefreq',$parent->changefreq);
+ if ($priority == '-1')
+ $priority = $parent->priority;
+
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['link_priority'] = $priority;
+ $params['link_changefreq'] = $changefreq;
+
+ $ordering = JArrayHelper::getValue($params,'cats_order','cat_name');
+ $orderdir = JArrayHelper::getValue($params,'cats_orderdir','ASC');
+ if ( !in_array($ordering,array('ordering','cat_name','cat_created')) )
+ $ordering = 'cat_name';
+
+ if ( !in_array($orderdir,array('ASC','DESC')) ){
+ $orderdir = 'ASC';
+ }
+
+ $params['cats_order'] = $db->quoteName($ordering)." $orderdir";
+
+ if ( $include_links ) {
+ $ordering = JArrayHelper::getValue($params,'links_order','ordering');
+ $orderdir = JArrayHelper::getValue($params,'links_orderdir','ASC');
+ if ( !in_array($ordering,array('ordering','link_name','link_modified','link_created','link_hits')) )
+ $ordering = 'ordering';
+
+ if ( !in_array($orderdir,array('ASC','DESC')) ){
+ $orderdir = 'ASC';
+ }
+
+ $params['links_order'] = $db->quoteName($ordering)." $orderdir";
+
+ $params['limit'] = '';
+ $params['days'] = '';
+ $limit = JArrayHelper::getValue($params,'max_links',0);
+ if ( intval($limit) )
+ $params['limit'] = ' LIMIT '.intval($limit);
+
+ $days = JArrayHelper::getValue($params,'max_age','');
+ if ( intval($days) )
+ $params['days'] = ' AND a.link_created >=\''.date('Y-m-d H:i:s',($xmap->now - ($days*86400))) ."' ";
+ }
+
+ xmap_com_mtree::getMtreeCategory($xmap,$parent,$params,$catid);
+ }
+
+ /* Returns URLs of all Categories and links in of one category using recursion */
+ static function getMtreeCategory ($xmap, $parent, &$params, $catid )
+ {
+ $database =& JFactory::getDbo();
+
+ $query = "SELECT cat_name, cat_id ".
+ "FROM #__mt_cats WHERE cat_published='1' AND cat_approved='1' AND cat_parent = $catid " .
+ "ORDER BY " . $params['cats_order'];
+
+ $database->setQuery($query);
+ $rows = $database->loadObjectList();
+
+ $xmap->changeLevel(1);
+ foreach($rows as $row) {
+ $node = new stdclass;
+ $node->name = $row->cat_name;
+ $node->link = 'index.php?option=com_mtree&task=listcats&cat_id='.$row->cat_id.'&Itemid='.$parent->id;
+ $node->id = $parent->id;
+ $node->uid = $parent->uid .'c'.$row->cat_id;
+ $node->browserNav = $parent->browserNav;
+ $node->modified = NULL;
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->expandible = true;
+ $node->secure = $parent->secure;
+
+ if ( $xmap->printNode($node) !== FALSE) {
+ xmap_com_mtree::getMtreeCategory($xmap,$parent,$params,$row->cat_id);
+ }
+ }
+
+ /* Returns URLs of all listings in the current category */
+ if ($params['include_links']) {
+ $query = " SELECT a.link_name, a.link_id, a.link_created as created, a.link_modified as modified \n".
+ " FROM #__mt_links AS a, #__mt_cl as b \n".
+ " WHERE a.link_id = b.link_id \n".
+ " AND b.cat_id = $catid " .
+ " AND ( link_published='1' AND link_approved='1' ) " .
+ $params['days'] .
+ " ORDER BY " . $params['links_order'] .
+ $params['limit'];
+
+ $database->setQuery($query);
+
+ $rows = $database->loadObjectList();
+
+ foreach($rows as $row) {
+ if ( !$row->modified || ($row->modified == $database->getNullDate())) {
+ $row->modified = $row->created;
+ }
+
+ $node = new stdclass;
+ $node->name = $row->link_name;
+ $node->link = 'index.php?option=com_mtree&task=viewlink&link_id='.$row->link_id.'&Itemid='.$parent->id;
+ $node->id = $parent->id;
+ $node->uid = $parent->uid.'l'.$row->link_id;
+ $node->browserNav = $parent->browserNav;
+ $node->modified = $row->modified;
+ $node->priority = $params['link_priority'];
+ $node->changefreq = $params['link_changefreq'];
+ $node->expandible = false;
+ $node->secure = $parent->secure;
+ $xmap->printNode($node);
+ }
+ }
+ $xmap->changeLevel(-1);
+
+ }
+}
diff --git a/plugins/xmap/com_mtree/com_mtree.xml b/plugins/xmap/com_mtree/com_mtree.xml
new file mode 100644
index 0000000..74abe56
--- /dev/null
+++ b/plugins/xmap/com_mtree/com_mtree.xml
@@ -0,0 +1,112 @@
+
+
+
+ Xmap - Mosets Tree Plugin
+ Guillermo Vargas
+ 07/20/2011
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 2.0.2
+ XMAP_MTREE_PLUGIN_DESCRIPTION
+
+ com_mtree.php
+ index.html
+
+
+
+ en-GB.plg_xmap_com_mtree.ini
+ es-ES.plg_xmap_com_mtree.ini
+ fa-IR.plg_xmap_com_mtree.ini
+ cs-CZ.plg_xmap_com_mtree.ini
+ nl-NL.plg_xmap_com_mtree.ini
+ ru-RU.plg_xmap_com_mtree.ini
+
+
+
+
+
+ XMAP_SETTING_OPTION_ORDERING_DEFAULT
+ XMAP_SETTING_OPTION_ORDERING_NAME
+ XMAP_SETTING_OPTION_ORDERING_CREATED
+
+
+ XMAP_SETTING_OPTION_ORDERING_DIR_ASC
+ XMAP_SETTING_OPTION_ORDERING_DIR_DESC
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+ XMAP_SETTING_OPTION_ORDERING_DEFAULT
+ XMAP_SETTING_OPTION_ORDERING_NAME
+ XMAP_SETTING_OPTION_ORDERING_CREATED
+ XMAP_SETTING_OPTION_ORDERING_MODIFIED
+ XMAP_SETTING_OPTION_ORDERING_HITS
+
+
+ XMAP_SETTING_OPTION_ORDERING_DIR_ASC
+ XMAP_SETTING_OPTION_ORDERING_DIR_DESC
+
+
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_mtree/index.html b/plugins/xmap/com_mtree/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_mtree/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/xmap/com_sobipro/com_sobipro.php b/plugins/xmap/com_sobipro/com_sobipro.php
new file mode 100644
index 0000000..aa6e0d1
--- /dev/null
+++ b/plugins/xmap/com_sobipro/com_sobipro.php
@@ -0,0 +1,257 @@
+link );
+ parse_str( html_entity_decode($link_query['query']), $link_vars);
+ $sid = JArrayHelper::getValue($link_vars,'sid',0);
+
+ $db = JFactory::getDbo();
+ $db->setQuery('SELECT * FROM `#__sobipro_object` where id='.(int)$sid);
+ $row = $db->loadObject();
+
+ $node->uid = 'com_sobiproo'.$sid;
+ if ( $row->oType == 'section' || $row->oType == 'category' ) {
+ $node->expandible = true;
+ } else {
+ $node->expandible = false;
+ }
+ }
+
+ /** Get the content tree for this kind of content */
+ function getTree( $xmap, $parent, &$params ) {
+
+ if ($xmap->isNews) // This component does not provide news content. don't waste time/resources
+ return false;
+
+ if (!self::loadSobi()){
+ return;
+ }
+
+ $link_query = parse_url( $parent->link );
+ parse_str( html_entity_decode($link_query['query']), $link_vars);
+ $sid =JArrayHelper::getValue($link_vars,'sid',1);
+ $task =JArrayHelper::getValue($link_vars,'task', null);
+
+ if (in_array($task, array('search', 'entry.add'))) {
+ return;
+ }
+
+ $db = JFactory::getDbo();
+ $db->setQuery('SELECT * FROM `#__sobipro_object` where id='.(int)$sid);
+ $object = $db->loadObject();
+
+ if ($object->oType == 'entry') {
+ return;
+ } elseif ( $object->oType == 'category' ) {
+ $sectionId = self::findCategorySection($object->parent);
+ } else {
+ $sectionId = $sid;
+ }
+ self::$sectionConfig = self::getSectionConfig($sectionId);
+
+
+ $include_entries =JArrayHelper::getValue($params,'include_entries',1);
+ $include_entries = ( $include_entries == 1
+ || ( $include_entries == 2 && $xmap->view == 'xml')
+ || ( $include_entries == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['include_entries'] = $include_entries;
+
+ $priority =JArrayHelper::getValue($params,'cat_priority',$parent->priority);
+ $changefreq =JArrayHelper::getValue($params,'cat_changefreq',$parent->changefreq);
+
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+
+ $priority =JArrayHelper::getValue($params,'entry_priority',$parent->priority);
+ $changefreq =JArrayHelper::getValue($params,'entry_changefreq',$parent->changefreq);
+
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['entry_priority'] = $priority;
+ $params['entry_changefreq'] = $changefreq;
+
+ $date = JFactory::getDate();
+ $params['now'] = $date->toMySql();
+
+ if ( $include_entries ) {
+ $ordering = JArrayHelper::getValue($params,'entries_order','b.position');
+ $orderdir = JArrayHelper::getValue($params,'entries_orderdir','ASC');
+ if ( !in_array($ordering,array('b.position','a.counter','b.validSince','a.updatedTime')) ){
+ $ordering = 'b.position';
+ }
+ if ( !in_array($orderdir,array('ASC','DESC')) ){
+ $orderdir = 'ASC';
+ }
+ $params['ordering'] = $ordering. ' '. $orderdir;
+
+ $params['limit'] = '';
+ $params['days'] = '';
+ $limit = JArrayHelper::getValue($params,'max_entries','');
+ if ( intval($limit) )
+ $params['limit'] = ' LIMIT '.$limit;
+
+ $days = JArrayHelper::getValue($params,'max_age','');
+ if ( intval($days) )
+ $params['days'] = ' AND a.publish_up >=\''.strftime("%Y-%m-%d %H:%M:%S",$xmap->now - ($days*86400)) ."' ";
+ }
+
+ xmap_com_sobipro::getCategoryTree($xmap, $parent, $sid, $params);
+ }
+
+ /** SobiPro support */
+ function getCategoryTree( $xmap, $parent, $sid, &$params ) {
+ $database =& JFactory::getDBO();
+
+ $query =
+ "SELECT a.id,a.nid, a.name, b.pid as pid "
+ ."\n FROM #__sobipro_object AS a, #__sobipro_relations AS b "
+ ."\n WHERE a.parent=$sid"
+ ." AND a.oType='category'"
+ ." AND b.oType=a.oType"
+ ." AND a.state=1 "
+ ." AND a.approved=1 "
+ ."\n AND a.id=b.id "
+ ."\n ORDER BY b.position ASC";
+
+ $database->setQuery( $query );
+ $rows = $database->loadObjectList();
+
+ $modified = time();
+ $xmap->changeLevel(1);
+ foreach($rows as $row) {
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->uid = 'com_sobiproc'.$row->id; // Unique ID
+ $node->browserNav = $parent->browserNav;
+ $node->name = html_entity_decode($row->name);
+ $node->modified = $modified;
+ #$node->link = 'index.php?option=com_sobipro&sid='.$row->id.':'.trim( SPLang::urlSafe( $row->name ) ).'&Itemid='.$parent->id;
+ $node->link = SPJoomlaMainFrame::url( array('sid' => $row->id, 'title' => $row->name), false, false );
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->expandible = true;
+ $node->secure = $parent->secure;
+ if ( $xmap->printNode($node) !== FALSE ) {
+ xmap_com_sobipro::getCategoryTree($xmap, $parent, $row->id, $params);
+ }
+ }
+
+ if ( $params['include_entries'] ) {
+ $query =
+ "SELECT a.id, c.baseData as name,a.updatedTime as modified,b.validSince as publish_up, b.pid as catid "
+ ."\n FROM #__sobipro_object AS a, #__sobipro_relations AS b, #__sobipro_field_data c"
+ ."\n WHERE a.state=1 "
+ ."\n AND a.id=b.id "
+ ."\n AND b.oType = 'entry'"
+ ."\n AND b.pid = $sid"
+ ."\n AND a.approved=1 "
+ ."\n AND (a.validUntil>='{$params['now']}' or a.validUntil='0000-00-00 00:00:00' ) "
+ ."\n AND (a.validSince<='{$params['now']}' or a.validSince='0000-00-00 00:00:00' ) "
+ ."\n AND a.id=c.sid AND c.fid=".self::$sectionConfig['name_field']->sValue
+ ."\n AND c.section=".self::$sectionConfig['name_field']->section
+ . $params['days']
+ ."\n ORDER BY " . $params['ordering']
+ . $params['limit'];
+
+ $database->setQuery( $query );
+ $rows = $database->loadObjectList();
+ foreach($rows as $row) {
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->uid = 'com_sobiproe'.$row->id; // Unique ID
+ $node->browserNav = $parent->browserNav;
+ $node->name = html_entity_decode($row->name);
+ $node->modified = $row->modified? $row->modified : $row->publish_up;
+ $node->priority = $params['entry_priority'];
+ $node->changefreq = $params['entry_changefreq'];
+ $node->expandible = false;
+ $node->secure = $parent->secure;
+ # $node->link = 'index.php?option=com_sobipro&pid='.$row->catid . '&sid=' . $row->id.':'.trim( SPLang::urlSafe( $row->name )).'&Itemid='.$parent->id;
+ $node->link = SPJoomlaMainFrame::url( array('sid' => $row->id, 'pid' => $row->catid, 'title' => $row->name), false, false );
+ $xmap->printNode($node);
+ }
+
+ }
+ $xmap->changeLevel(-1);
+ }
+
+ static protected function getSectionConfig($sectionId)
+ {
+ $db = JFactory::getDbo();
+ $db->setQuery('SELECT * FROM `#__sobipro_config` where section='.(int)$sectionId);
+ return $db->loadObjectList('sKey');
+ }
+
+ static protected function loadSobi()
+ {
+ if (defined('SOBI_TESTS')) {
+ return true;
+ }
+ define( 'SOBI_TESTS', false );
+ $ver = new JVersion();
+ $ver = str_replace( '.', null, $ver->RELEASE );
+ // added by Pierre Burri-Wittke globeall.de
+ if ($ver > '15') { $ver = '16'; }
+ define( 'SOBI_CMS', 'joomla'. $ver );
+ define( 'SOBIPRO', true );
+ define( 'SOBI_TASK', 'task' );
+ define( 'SOBI_DEFLANG', JFactory::getLanguage()->getDefault() );
+ define( 'SOBI_ACL', 'front' );
+ define( 'SOBI_ROOT', JPATH_ROOT );
+ define( 'SOBI_MEDIA', implode( '/', array( JPATH_ROOT, 'media', 'sobipro' ) ) );
+ define( 'SOBI_MEDIA_LIVE', JURI::root().'/media/sobipro' );
+ define( 'SOBI_PATH', SOBI_ROOT.'/components/com_sobipro' );
+ if (!file_exists(SOBI_PATH.'/lib/base/fs/loader.php')) {
+ return false;
+ }
+ require_once SOBI_PATH.'/lib/base/fs/loader.php';
+ SPLoader::loadClass( 'sobi' );
+ SPLoader::loadClass( 'base.request' );
+ SPLoader::loadClass( 'base.object' );
+ SPLoader::loadClass( 'base.factory' );
+ SPLoader::loadClass( 'base.mainframe' );
+ // added by Pierre Burri-Wittke globeall.de
+ SPLoader::loadClass( 'base.const' );
+ SPLoader::loadClass( 'cms.base.mainframe' );
+ SPLoader::loadClass( 'cms.base.lang' );
+ return true;
+ }
+
+ static protected function findCategorySection($sid)
+ {
+ $db = JFactory::getDbo();
+ $db->setQuery('SELECT id,parent,oType FROM `#__sobipro_object` where id='.(int)$sid);
+ $row = $db->loadObject();
+ if ($row->oType == 'section') {
+ return $row->id;
+ } else {
+ return self::findCategorySection($row->parent);
+ }
+ }
+}
diff --git a/plugins/xmap/com_sobipro/com_sobipro.xml b/plugins/xmap/com_sobipro/com_sobipro.xml
new file mode 100644
index 0000000..1608438
--- /dev/null
+++ b/plugins/xmap/com_sobipro/com_sobipro.xml
@@ -0,0 +1,100 @@
+
+
+ Xmap - SobiPro Plugin
+ Guillermo Vargas
+ 07/15/2011
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 2.0.2
+ Xmap Plugin for SobiPro component
+
+ com_sobipro.php
+
+
+
+ en-GB.plg_xmap_com_sobipro.ini
+ es-ES.plg_xmap_com_sobipro.ini
+ fa-IR.plg_xmap_com_sobipro.ini
+ cs-CZ.plg_xmap_com_sobipro.ini
+ nl-NL.plg_xmap_com_sobipro.ini
+ ru-RU.plg_xmap_com_sobipro.ini
+
+
+
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+
+
+ XMAP_OPTION_DEFAULT
+ XMAP_OPTION_VISITS
+ XMAP_OPTION_PUBLISH
+ XMAP_OPTION_MOD
+
+
+ XMAP_SETTING_OPTION_ORDERING_DIR_ASC
+ XMAP_SETTING_OPTION_ORDERING_DIR_DESC
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_virtuemart/com_virtuemart.php b/plugins/xmap/com_virtuemart/com_virtuemart.php
new file mode 100644
index 0000000..ecf6821
--- /dev/null
+++ b/plugins/xmap/com_virtuemart/com_virtuemart.php
@@ -0,0 +1,244 @@
+link);
+
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+
+ $catid = JArrayHelper::getValue($link_vars, 'virtuemart_category_id', 0);
+ $prodid = JArrayHelper::getValue($link_vars, 'virtuemart_product_id', 0);
+
+ if (!$catid)
+ {
+ $menu = $app->getMenu();
+ $menuParams = $menu->getParams($node->id);
+ $catid = $menuParams->get('virtuemart_category_id', 0);
+ }
+
+ if (!$prodid)
+ {
+ $menu = $app->getMenu();
+ $menuParams = $menu->getParams($node->id);
+ $prodid = $menuParams->get('virtuemart_product_id', 0);
+ }
+
+ if ($prodid && $catid)
+ {
+ $node->uid = 'com_virtuemartc' . $catid . 'p' . $prodid;
+ $node->expandible = false;
+ }
+ elseif($catid)
+ {
+ $node->uid = 'com_virtuemartc' . $catid;
+ $node->expandible = true;
+ }
+ }
+
+ /** Get the content tree for this kind of content */
+ static function getTree($xmap, $parent, &$params)
+ {
+ self::initialize();
+
+ $app = JFactory::getApplication();
+ $menu = $app->getMenu();
+
+ $link_query = parse_url($parent->link);
+
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+
+ $catid = intval(JArrayHelper::getValue($link_vars, 'virtuemart_category_id', 0));
+ $params['Itemid'] = intval(JArrayHelper::getValue($link_vars, 'Itemid', $parent->id));
+
+ $view = JArrayHelper::getValue($link_vars, 'view', '');
+
+ // we currently support only categories
+ if (!in_array($view, array('categories','category')))
+ {
+ return true;
+ }
+
+ $include_products = JArrayHelper::getValue($params, 'include_products', 1);
+ $include_products = ( $include_products == 1
+ || ( $include_products == 2 && $xmap->view == 'xml')
+ || ( $include_products == 3 && $xmap->view == 'html'));
+
+ $params['include_products'] = $include_products;
+ $params['include_product_images'] = (JArrayHelper::getValue($params, 'include_product_images', 1) && $xmap->view == 'xml');
+ $params['product_image_license_url'] = trim(JArrayHelper::getValue($params, 'product_image_license_url', ''));
+
+ $priority = JArrayHelper::getValue($params, 'cat_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'cat_changefreq', $parent->changefreq);
+
+ if ($priority == '-1')
+ {
+ $priority = $parent->priority;
+ }
+
+ if ($changefreq == '-1')
+ {
+ $changefreq = $parent->changefreq;
+ }
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+
+ $priority = JArrayHelper::getValue($params, 'prod_priority', $parent->priority);
+ $changefreq = JArrayHelper::getValue($params, 'prod_changefreq', $parent->changefreq);
+
+ if ($priority == '-1')
+ {
+ $priority = $parent->priority;
+ }
+
+ if ($changefreq == '-1')
+ {
+ $changefreq = $parent->changefreq;
+ }
+
+ $params['prod_priority'] = $priority;
+ $params['prod_changefreq'] = $changefreq;
+
+ xmap_com_virtuemart::getCategoryTree($xmap, $parent, $params, $catid);
+
+ return true;
+ }
+
+ /** Virtuemart support */
+ static function getCategoryTree($xmap, $parent, &$params, $catid=0)
+ {
+ $database = JFactory::getDBO();
+
+ if (!isset($urlBase))
+ {
+ $urlBase = JURI::base();
+ }
+
+ $vendorId = 1;
+ $cache = JFactory::getCache('com_virtuemart','callback');
+ $children = $cache->call( array( 'VirtueMartModelCategory', 'getChildCategoryList' ),$vendorId, $catid );
+
+ $xmap->changeLevel(1);
+
+ foreach ($children as $row)
+ {
+ $node = new stdclass;
+
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'c' . $row->virtuemart_category_id;
+ $node->browserNav = $parent->browserNav;
+ $node->name = stripslashes($row->category_name);
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->expandible = true;
+ $node->link = 'index.php?option=com_virtuemart&view=category&virtuemart_category_id=' . $row->virtuemart_category_id . '&Itemid='.$parent->id;
+
+ if ($xmap->printNode($node) !== FALSE)
+ {
+ xmap_com_virtuemart::getCategoryTree($xmap, $parent, $params, $row->virtuemart_category_id);
+ }
+ }
+
+ $xmap->changeLevel(-1);
+
+ if ($params['include_products'] && $catid != 0)
+ {
+ $products = self::$productModel->getProductsInCategory($catid);
+
+ if ($params['include_product_images'])
+ {
+ self::$categoryModel->addImages($products,1);
+ }
+
+ $xmap->changeLevel(1);
+
+ foreach ($products as $row)
+ {
+ $node = new stdclass;
+
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'c' . $row->virtuemart_category_id . 'p' . $row->virtuemart_product_id;
+ $node->browserNav = $parent->browserNav;
+ $node->priority = $params['prod_priority'];
+ $node->changefreq = $params['prod_changefreq'];
+ $node->name = $row->product_name;
+ $node->modified = strtotime($row->modified_on);
+ $node->expandible = false;
+ $node->link = 'index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $row->virtuemart_product_id . '&virtuemart_category_id=' . $row->virtuemart_category_id . '&Itemid=' . $parent->id;
+
+ if ($params['include_product_images'])
+ {
+ foreach ($row->images as $image)
+ {
+ if (isset($image->file_url))
+ {
+ $imagenode = new stdClass;
+
+ $imagenode->src = $urlBase . $image->file_url_thumb;
+ $imagenode->title = $row->product_name;
+ $imagenode->license = $params['product_image_license_url'];
+
+ $node->images[] = $imagenode;
+ }
+ }
+ }
+
+ $xmap->printNode($node);
+ }
+
+ $xmap->changeLevel(-1);
+ }
+ }
+
+ static protected function initialize()
+ {
+ if (self::$initialized) return;
+
+ $app = JFactory::getApplication ();
+
+ if (!class_exists( 'VmConfig' ))
+ {
+ require(JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/config.php');
+ VmConfig::loadConfig();
+ }
+
+ JTable::addIncludePath(JPATH_VM_ADMINISTRATOR . '/tables');
+
+ VmConfig::set ('llimit_init_FE', 9000);
+
+ $app->setUserState('com_virtuemart.htmlc-1.limit',9000);
+ $app->setUserState('com_virtuemart.htmlc0.limit',9000);
+ $app->setUserState('com_virtuemart.xmlc0.limit' ,9000);
+
+ if (!class_exists('VirtueMartModelCategory')) require(JPATH_VM_ADMINISTRATOR . '/models/category.php');
+ self::$categoryModel = new VirtueMartModelCategory();
+
+ if (!class_exists('VirtueMartModelProduct')) require(JPATH_VM_ADMINISTRATOR . '/models/product.php');
+ self::$productModel = new VirtueMartModelProduct();
+ }
+}
diff --git a/plugins/xmap/com_virtuemart/com_virtuemart.xml b/plugins/xmap/com_virtuemart/com_virtuemart.xml
new file mode 100644
index 0000000..65bf04e
--- /dev/null
+++ b/plugins/xmap/com_virtuemart/com_virtuemart.xml
@@ -0,0 +1,96 @@
+
+
+ Xmap - Virtuemart Plugin
+ Guillermo Vargas
+ January 2012
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 2.0.3
+ XMAP_VM_PLUGIN_DESCRIPTION
+
+ com_virtuemart.php
+ index.html
+
+
+
+ en-GB.plg_xmap_com_virtuemart.ini
+ es-ES.plg_xmap_com_virtuemart.ini
+ fa-IR.plg_xmap_com_virtuemart.ini
+ cs-CZ.plg_xmap_com_virtuemart.ini
+ nl-NL.plg_xmap_com_virtuemart.ini
+ ru-RU.plg_xmap_com_virtuemart.ini
+
+
+
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_virtuemart/index.html b/plugins/xmap/com_virtuemart/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_virtuemart/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/xmap/com_weblinks/com_weblinks.php b/plugins/xmap/com_weblinks/com_weblinks.php
new file mode 100644
index 0000000..60c4d56
--- /dev/null
+++ b/plugins/xmap/com_weblinks/com_weblinks.php
@@ -0,0 +1,172 @@
+link);
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $view = JArrayHelper::getValue($link_vars, 'view', '');
+ if ($view == 'weblink') {
+ $id = intval(JArrayHelper::getValue($link_vars, 'id', 0));
+ if ($id) {
+ $node->uid = 'com_weblinksi' . $id;
+ $node->expandible = false;
+ }
+ } elseif ($view == 'categories') {
+ $node->uid = 'com_weblinkscategories';
+ $node->expandible = true;
+ } elseif ($view == 'category') {
+ $catid = intval(JArrayHelper::getValue($link_vars, 'id', 0));
+ $node->uid = 'com_weblinksc' . $catid;
+ $node->expandible = true;
+ }
+ }
+
+ static function getTree($xmap, $parent, &$params)
+ {
+ self::initialize($params);
+
+ $app = JFactory::getApplication();
+ $weblinks_params = $app->getParams('com_weblinks');
+
+ $link_query = parse_url($parent->link);
+ parse_str(html_entity_decode($link_query['query']), $link_vars);
+ $view = JArrayHelper::getValue($link_vars, 'view', 0);
+
+ $app = JFactory::getApplication();
+ $menu = $app->getMenu();
+ $menuparams = $menu->getParams($parent->id);
+
+ if ($view == 'category') {
+ $catid = intval(JArrayHelper::getValue($link_vars, 'id', 0));
+ } elseif ($view == 'categories') {
+ $catid = 0;
+ } else { // Only expand category menu items
+ return;
+ }
+
+ $include_links = JArrayHelper::getValue($params, 'include_links', 1, '');
+ $include_links = ( $include_links == 1
+ || ( $include_links == 2 && $xmap->view == 'xml')
+ || ( $include_links == 3 && $xmap->view == 'html')
+ || $xmap->view == 'navigator');
+ $params['include_links'] = $include_links;
+
+ $priority = JArrayHelper::getValue($params, 'cat_priority', $parent->priority, '');
+ $changefreq = JArrayHelper::getValue($params, 'cat_changefreq', $parent->changefreq, '');
+ if ($priority == '-1')
+ $priority = $parent->priority;
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['cat_priority'] = $priority;
+ $params['cat_changefreq'] = $changefreq;
+
+ $priority = JArrayHelper::getValue($params, 'link_priority', $parent->priority, '');
+ $changefreq = JArrayHelper::getValue($params, 'link_changefreq', $parent->changefreq, '');
+ if ($priority == '-1')
+ $priority = $parent->priority;
+
+ if ($changefreq == '-1')
+ $changefreq = $parent->changefreq;
+
+ $params['link_priority'] = $priority;
+ $params['link_changefreq'] = $changefreq;
+
+ $options = array();
+ $options['countItems'] = false;
+ $options['catid'] = rand();
+ $categories = JCategories::getInstance('Weblinks', $options);
+ $category = $categories->get($catid? $catid : 'root', true);
+
+ $params['count_clicks'] = $weblinks_params->get('count_clicks');
+
+ xmap_com_weblinks::getCategoryTree($xmap, $parent, $params, $category);
+ }
+
+ static function getCategoryTree($xmap, $parent, &$params, $category)
+ {
+ $db = JFactory::getDBO();
+
+ $children = $category->getChildren();
+ $xmap->changeLevel(1);
+ foreach ($children as $cat) {
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'c' . $cat->id;
+ $node->name = $cat->title;
+ $node->link = WeblinksHelperRoute::getCategoryRoute($cat);
+ $node->priority = $params['cat_priority'];
+ $node->changefreq = $params['cat_changefreq'];
+ $node->expandible = true;
+ if ($xmap->printNode($node) !== FALSE) {
+ xmap_com_weblinks::getCategoryTree($xmap, $parent, $params, $cat);
+ }
+ }
+ $xmap->changeLevel(-1);
+
+ if ($params['include_links']) { //view=category&catid=...
+ $linksModel = new WeblinksModelCategory();
+ $linksModel->getState(); // To force the populate state
+ $linksModel->setState('list.limit', JArrayHelper::getValue($params, 'max_links', NULL));
+ $linksModel->setState('list.start', 0);
+ $linksModel->setState('list.ordering', 'ordering');
+ $linksModel->setState('list.direction', 'ASC');
+ $linksModel->setState('category.id', $category->id);
+ $links = $linksModel->getItems();
+ $xmap->changeLevel(1);
+ foreach ($links as $link) {
+ $item_params = new JRegistry;
+ $item_params->loadString($link->params);
+
+ $node = new stdclass;
+ $node->id = $parent->id;
+ $node->uid = $parent->uid . 'i' . $link->id;
+ $node->name = $link->title;
+
+ // Find the Itemid
+ $Itemid = intval(preg_replace('/.*Itemid=([0-9]+).*/','$1',WeblinksHelperRoute::getWeblinkRoute($link->id, $category->id)));
+
+ if ($item_params->get('count_clicks', $params['count_clicks']) == 1) {
+ $node->link = 'index.php?option=com_weblinks&task=weblink.go&id='. $link->id.'&Itemid='.($Itemid ? $Itemid : $parent->id);
+ } else {
+ $node->link = $link->url;
+ }
+ $node->priority = $params['link_priority'];
+ $node->changefreq = $params['link_changefreq'];
+ $node->expandible = false;
+ $xmap->printNode($node);
+ }
+ $xmap->changeLevel(-1);
+ }
+ }
+
+ static public function initialize(&$params)
+ {
+ if (self::$_initialized) {
+ return;
+ }
+
+ self::$_initialized = true;
+ require_once JPATH_SITE.'/components/com_weblinks/models/category.php';
+ require_once JPATH_SITE.'/components/com_weblinks/helpers/route.php';
+ }
+}
\ No newline at end of file
diff --git a/plugins/xmap/com_weblinks/com_weblinks.xml b/plugins/xmap/com_weblinks/com_weblinks.xml
new file mode 100644
index 0000000..526d381
--- /dev/null
+++ b/plugins/xmap/com_weblinks/com_weblinks.xml
@@ -0,0 +1,89 @@
+
+
+ Xmap - WebLinks Plugin
+ Guillermo Vargas
+ Apr 2004
+ GNU GPL
+ http://www.gnu.org/copyleft/gpl.html GNU/GPL
+ guille@vargas.co.cr
+ joomla.vargas.co.cr
+ 2.0.1
+ XMAP_WL_PLUGIN_DESCRIPTION
+
+ com_weblinks.php
+ index.html
+
+
+
+ en-GB.plg_xmap_com_weblinks.ini
+ es-ES.plg_xmap_com_weblinks.ini
+ fa-IR.plg_xmap_com_weblinks.ini
+ cs-CZ.plg_xmap_com_weblinks.ini
+ nl-NL.plg_xmap_com_weblinks.ini
+ ru-RU.plg_xmap_com_weblinks.ini
+
+
+
+
+
+ XMAP_OPTION_NEVER
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_XML_ONLY
+ XMAP_OPTION_HTML_ONLY
+
+
+
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.1
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ 0.0
+ 0.2
+ 0.3
+ 0.4
+ 0.5
+ 0.6
+ 0.7
+ 0.8
+ 0.9
+ 1
+
+
+ XMAP_OPTION_USE_PARENT_MENU
+ XMAP_OPTION_ALWAYS
+ XMAP_OPTION_HOURLY
+ XMAP_OPTION_DAILY
+ XMAP_OPTION_WEEKLY
+ XMAP_OPTION_MONTHLY
+ XMAP_OPTION_YEARLY
+ XMAP_OPTION_NEVER
+
+
+
+
+
diff --git a/plugins/xmap/com_weblinks/index.html b/plugins/xmap/com_weblinks/index.html
new file mode 100644
index 0000000..3af6301
--- /dev/null
+++ b/plugins/xmap/com_weblinks/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file