diff --git a/ajax/ajax_getContent.php b/ajax/ajax_getContent.php index 1e07974e..70e2250d 100644 --- a/ajax/ajax_getContent.php +++ b/ajax/ajax_getContent.php @@ -37,7 +37,7 @@ SP_Util::checkReload(); if (SP_Common::parseParams('p', 'action', '', true)) { $action = $tplvars['action'] = SP_Common::parseParams('p', 'action'); $itemId = $tplvars['id'] = SP_Common::parseParams('p', 'id', 0); - $tplvars['lastaction'] = SP_Common::parseParams('p', 'lastAction', 'accsearch'); + $tplvars['lastaction'] = filter_var(SP_Common::parseParams('p', 'lastAction', 'accsearch', false, false, false), FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); } else { die('
' . _('Parámetros incorrectos') . '
'); } diff --git a/css/css.php b/css/css.php new file mode 100644 index 00000000..6dc57630 --- /dev/null +++ b/css/css.php @@ -0,0 +1,46 @@ +. + * + */ + +define('APP_ROOT', '..'); +require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'init.php'; + +$cssFiles = array( + array('href' => 'css/reset.css', 'min' => true), + array('href' => 'css/smoothness/jquery-ui.css', 'min' => true), + array('href' => 'css/jquery.powertip.css', 'min' => true), + array('href' => 'css/jquery.powertip-yellow.min.css', 'min' => true), + array('href' => 'css/chosen.css', 'min' => true), + array('href' => 'css/alertify.core.css', 'min' => true), + array('href' => 'css/alertify.default.css', 'min' => true), + array('href' => 'css/jquery.tagsinput.css', 'min' => true), + array('href' => 'js/fancybox/jquery.fancybox.css', 'min' => true), + array('href' => 'css/styles.css', 'min' => true) +); + +if (!SP_Util::resultsCardsIsEnabled()) { + array_push($cssFiles, array('href' => 'css/search-grid.css', 'min' => true)); +} + +SP_Util::getMinified('css', $cssFiles); \ No newline at end of file diff --git a/css/smoothness/jquery-ui.css b/css/smoothness/jquery-ui.css index db0302c8..4e52196d 100644 --- a/css/smoothness/jquery-ui.css +++ b/css/smoothness/jquery-ui.css @@ -4,4 +4,4 @@ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("smoothness/images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(smoothness/images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(smoothness/images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(smoothness/images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(smoothness/images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(smoothness/images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(smoothness/images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(smoothness/images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(smoothness/images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(smoothness/images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(smoothness/images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(smoothness/images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/inc/ext/cssmin/class.cssmin.php b/inc/ext/cssmin/class.cssmin.php new file mode 100644 index 00000000..a27d1690 --- /dev/null +++ b/inc/ext/cssmin/class.cssmin.php @@ -0,0 +1,4819 @@ + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * -- + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ + +/** + * Abstract definition of a CSS token class. + * + * Every token has to extend this class. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssToken +{ + /** + * Returns the token as string. + * + * @return string + */ + abstract public function __toString(); +} + +/** + * Abstract definition of a for a ruleset start token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssRulesetStartToken extends aCssToken +{ + +} + +/** + * Abstract definition of a for ruleset end token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssRulesetEndToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} + +/** + * Abstract definition of a parser plugin. + * + * Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a + * stylesheet. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssParserPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssParser of the plugin. + * + * @var CssParser + */ + protected $parser = null; + /** + * Plugin buffer. + * + * @var string + */ + protected $buffer = ""; + + /** + * Constructor. + * + * @param CssParser $parser The CssParser object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssParser $parser, array $configuration = null) + { + $this->configuration = $configuration; + $this->parser = $parser; + } + + /** + * Returns the array of chars triggering the parser plugin. + * + * @return array + */ + abstract public function getTriggerChars(); + + /** + * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin. + * + * @return array + */ + abstract public function getTriggerStates(); + + /** + * Parser routine of the plugin. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + abstract public function parse($index, $char, $previousChar, $state); +} + +/** + * Abstract definition of a minifier plugin class. + * + * Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to + * extend this class. + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssMinifierPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the plugin. + * + * @var CssMinifier + */ + protected $minifier = null; + + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + + /** + * Apply the plugin to the token. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + abstract public function apply(aCssToken &$token); + + /** + * -- + * + * @return array + */ + abstract public function getTriggerTokens(); +} + +/** + * Abstract definition of a minifier filter class. + * + * Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter + * has to extend this class. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssMinifierFilter +{ + /** + * Filter configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the filter. + * + * @var CssMinifier + */ + protected $minifier = null; + + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Filter configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + + /** + * Filter the tokens. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + abstract public function apply(array &$tokens); +} + +/** + * Abstract formatter definition. + * + * Every formatter have to extend this class. + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssFormatter +{ + /** + * Indent string. + * + * @var string + */ + protected $indent = " "; + /** + * Declaration padding. + * + * @var integer + */ + protected $padding = 0; + /** + * Tokens. + * + * @var array + */ + protected $tokens = array(); + + /** + * Constructor. + * + * @param array $tokens Array of CssToken + * @param string $indent Indent string [optional] + * @param integer $padding Declaration value padding [optional] + */ + public function __construct(array $tokens, $indent = null, $padding = null) + { + $this->tokens = $tokens; + $this->indent = !is_null($indent) ? $indent : $this->indent; + $this->padding = !is_null($padding) ? $padding : $this->padding; + } + + /** + * Returns the array of aCssToken as formatted string. + * + * @return string + */ + abstract public function __toString(); +} + +/** + * Abstract definition of a ruleset declaration token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssDeclarationToken extends aCssToken +{ + /** + * Is the declaration flagged as important? + * + * @var boolean + */ + public $IsImportant = false; + /** + * Is the declaration flagged as last one of the ruleset? + * + * @var boolean + */ + public $IsLast = false; + /** + * Property name of the declaration. + * + * @var string + */ + public $Property = ""; + /** + * Value of the declaration. + * + * @var string + */ + public $Value = ""; + + /** + * Set the properties of the @font-face declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param boolean $isImportant Is the !important flag is set? + * @param boolean $IsLast Is the declaration the last one of the block? + * @return void + */ + public function __construct($property, $value, $isImportant = false, $isLast = false) + { + $this->Property = $property; + $this->Value = $value; + $this->IsImportant = $isImportant; + $this->IsLast = $isLast; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Property . ":" . $this->Value . ($this->IsImportant ? " !important" : "") . ($this->IsLast ? "" : ";"); + } +} + +/** + * Abstract definition of a for at-rule block start token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssAtBlockStartToken extends aCssToken +{ + +} + +/** + * Abstract definition of a for at-rule block end token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssAtBlockEndToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} + +/** + * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}. + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssWhitesmithsFormatter extends aCssFormatter +{ + /** + * Implements {@link aCssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) { + $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; + } + } elseif ($class === "CssAtCharsetToken") { + $r[] = $indent . "@charset " . $token->Charset . ";"; + } elseif ($class === "CssAtFontFaceStartToken") { + $r[] = $indent . "@font-face"; + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class === "CssAtImportToken") { + $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; + } elseif ($class === "CssAtKeyframesStartToken") { + $r[] = $indent . "@keyframes \"" . $token->Name . "\""; + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class === "CssAtMediaStartToken") { + $r[] = $indent . "@media " . implode(", ", $token->MediaTypes); + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class === "CssAtPageStartToken") { + $r[] = $indent . "@page"; + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class === "CssAtVariablesStartToken") { + $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes); + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") { + $r[] = $indent . implode(", ", $token->Selectors); + $r[] = $this->indent . $indent . "{"; + $level++; + } elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) { + $declaration = $indent . $token->Property . ": "; + if ($this->padding) { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; + } elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) { + $r[] = $indent . "}"; + $level--; + } + } + return implode("\n", $r); + } +} + +/** + * This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value. + * + * This plugin only apply the variable values. The variable values itself will get parsed by the + * {@link CssVariablesMinifierFilter}. + * + * Example: + * + * @variables + * { + * defaultColor: black; + * } + * color: var(defaultColor); + * + * + * Will get converted to: + * + * color:black; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching a value. + * + * @var string + */ + private $reMatch = "/var\((.+)\)/iSU"; + /** + * Parsed variables. + * + * @var array + */ + private $variables = null; + + /** + * Returns the variables. + * + * @return array + */ + public function getVariables() + { + return $this->variables; + } + + /** + * Sets the variables. + * + * @param array $variables Variables to set + * @return void + */ + public function setVariables(array $variables) + { + $this->variables = $variables; + } + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m)) { + $mediaTypes = $token->MediaTypes; + if (!in_array("all", $mediaTypes)) { + $mediaTypes[] = "all"; + } + for ($i = 0, $l = count($m[0]); $i < $l; $i++) { + $variable = trim($m[1][$i]); + foreach ($mediaTypes as $mediaType) { + if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable])) { + // Variable value found => set the declaration value to the variable value and return + $token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value); + continue 2; + } + } + // If no value was found trigger an error and replace the token with a CssNullToken + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": No value found for variable " . $variable . " in media types " . implode(", ", $mediaTypes) . "", (string)$token)); + $token = new CssNullToken(); + return true; + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule + * blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to + * declaration. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $variables = array(); + $defaultMediaTypes = array("all"); + $mediaTypes = array(); + $remove = array(); + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + // @variables at-rule block found + if (get_class($tokens[$i]) === "CssAtVariablesStartToken") { + $remove[] = $i; + $mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes); + foreach ($mediaTypes as $mediaType) { + if (!isset($variables[$mediaType])) { + $variables[$mediaType] = array(); + } + } + // Read the variable declaration tokens + for ($i = $i; $i < $l; $i++) { + // Found a variable declaration => read the variable values + if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken") { + foreach ($mediaTypes as $mediaType) { + $variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value; + } + $remove[] = $i; + } // Found the variables end token => break; + elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken") { + $remove[] = $i; + break; + } + } + } + } + // Variables in @variables at-rule blocks + foreach ($variables as $mediaType => $null) { + foreach ($variables[$mediaType] as $variable => $value) { + // If a var() statement in a variable value found... + if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m)) { + // ... then replace the var() statement with the variable values. + for ($i = 0, $l = count($m[0]); $i < $l; $i++) { + $variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), $variables[$mediaType][$variable]); + } + } + } + } + // Remove the complete @variables at-rule block + foreach ($remove as $i) { + $tokens[$i] = null; + } + if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin"))) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin CssVariablesMinifierPlugin was not found but is required for " . __CLASS__ . "")); + } else { + $plugin->setVariables($variables); + } + return count($remove); + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing url() values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssUrlParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" && $state !== "T_URL") { + $this->parser->pushState("T_URL"); + $this->parser->setExclusive(__CLASS__); + } // Escaped LF in url => remove escape backslash and LF + elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL") { + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } // Parse error: Unescaped LF in string literal + elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL") { + $line = $this->parser->getBuffer(); + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . ")"); // Replace the LF with the url string delimiter + $this->parser->popState(); + $this->parser->unsetExclusive(); + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); + } // End of string + elseif ($char === ")" && $state === "T_URL") { + $this->parser->popState(); + $this->parser->unsetExclusive(); + } else { + return false; + } + return true; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing string values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssStringParserPlugin extends aCssParserPlugin +{ + /** + * Current string delimiter char. + * + * @var string + */ + private $delimiterChar = null; + + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("\"", "'", "\n"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if (($char === "\"" || $char === "'") && $state !== "T_STRING") { + $this->delimiterChar = $char; + $this->parser->pushState("T_STRING"); + $this->parser->setExclusive(__CLASS__); + } // Escaped LF in string => remove escape backslash and LF + elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING") { + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } // Parse error: Unescaped LF in string literal + elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING") { + $line = $this->parser->getBuffer(); + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); + $this->delimiterChar = null; + } // End of string + elseif ($char === $this->delimiterChar && $state === "T_STRING") { + // If the Previous char is a escape char count the amount of the previous escape chars. If the amount of + // escape chars is uneven do not end the string + if ($previousChar == "\\") { + $source = $this->parser->getSource(); + $c = 1; + $i = $index - 2; + while (substr($source, $i, 1) === "\\") { + $c++; + $i--; + } + if ($c % 2) { + return false; + } + } + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->delimiterChar = null; + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Rowan Beentje + * @copyright Rowan Beentje + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter +{ + /** + * User defined sort function. + * + * @return integer + */ + public static function userDefinedSort1($a, $b) + { + return strcmp($a->Property, $b->Property); + } + + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + // Only look for ruleset start rules + if (get_class($tokens[$i]) !== "CssRulesetStartToken") { + continue; + } + // Look for the corresponding ruleset end + $endIndex = false; + for ($ii = $i + 1; $ii < $l; $ii++) { + if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { + continue; + } + $endIndex = $ii; + break; + } + if (!$endIndex) { + break; + } + $startIndex = $i; + $i = $endIndex; + // Skip if there's only one token in this ruleset + if ($endIndex - $startIndex <= 2) { + continue; + } + // Ensure that everything between the start and end is a declaration token, for safety + for ($ii = $startIndex + 1; $ii < $endIndex; $ii++) { + if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { + continue(2); + } + } + $declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1); + // Check whether a sort is required + $sortRequired = $lastPropertyName = false; + foreach ($declarations as $declaration) { + if ($lastPropertyName) { + if (strcmp($lastPropertyName, $declaration->Property) > 0) { + $sortRequired = true; + break; + } + } + $lastPropertyName = $declaration->Property; + } + if (!$sortRequired) { + continue; + } + // Arrange the declarations alphabetically by name + usort($declarations, array(__CLASS__, "userDefinedSort1")); + // Update "IsLast" property + for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++) { + if ($ii == $ll) { + $declarations[$ii]->IsLast = true; + } else { + $declarations[$ii]->IsLast = false; + } + } + // Splice back into the array. + array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations); + $r += $endIndex - $startIndex - 1; + } + return $r; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a ruleset. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetStartToken extends aCssRulesetStartToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + * @return void + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors) . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations. + * + * Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the + * parser; including declarations as {@link CssRulesetDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetParserPlugin extends aCssParserPlugin +{ + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array(",", "{", "}", ":", ";"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of Ruleset and selectors + if ($char === "," && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) { + if ($state !== "T_RULESET::SELECTORS") { + $this->parser->pushState("T_RULESET::SELECTORS"); + } + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } // End of selectors and start of declarations + elseif ($char === "{" && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) { + if ($this->parser->getBuffer() !== "") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + if ($state == "T_RULESET::SELECTORS") { + $this->parser->popState(); + } + $this->parser->pushState("T_RULESET"); + $this->parser->appendToken(new CssRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } // Start of declaration + elseif ($char === ":" && $state === "T_RULESET") { + $this->parser->pushState("T_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } // Unterminated ruleset declaration + elseif ($char === ":" && $state === "T_RULESET_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant)); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") { + $this->parser->appendToken(new CssRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } // End of ruleset + elseif ($char === "}" && $state === "T_RULESET") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssRulesetEndToken()); + $this->buffer = ""; + $this->selectors = array(); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a ruleset. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetEndToken extends aCssRulesetEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a ruleset declaration. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetDeclarationToken extends aCssDeclarationToken +{ + /** + * Media types of the declaration. + * + * @var array + */ + public $MediaTypes = array("all"); + + /** + * Set the properties of a ddocument- or at-rule @media level declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param mixed $mediaTypes Media types of the declaration + * @param boolean $isImportant Is the !important flag is set + * @param boolean $isLast Is the declaration the last one of the ruleset + * @return void + */ + public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false) + { + parent::__construct($property, $value, $isImportant, $isLast); + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset, + * @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified + * without tailing semicolon. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken") + ) { + $tokens[$i]->IsLast = true; + } + } + return 0; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block + * rulesets). + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) + ) { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page + * at-rule blocks. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") || + ($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") || + ($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken") + ) { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssCommentToken") { + $tokens[$i] = null; + $r++; + } + } + return $r; + } +} + +/** + * CSS Parser. + * + * @package CssMin/Parser + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssParser +{ + /** + * Parse buffer. + * + * @var string + */ + public $buffer = ""; + /** + * {@link aCssParserPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Source to parse. + * + * @var string + */ + private $source = ""; + /** + * Current state. + * + * @var integer + */ + private $state = "T_DOCUMENT"; + /** + * Exclusive state. + * + * @var string + */ + private $stateExclusive = false; + /** + * Media types state. + * + * @var mixed + */ + private $stateMediaTypes = false; + /** + * State stack. + * + * @var array + */ + private $states = array("T_DOCUMENT"); + /** + * Parsed tokens. + * + * @var array + */ + private $tokens = array(); + + /** + * Constructer. + * + * Create instances of the used {@link aCssParserPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $plugins = null) + { + $plugins = array_merge(array + ( + "Comment" => true, + "String" => true, + "Url" => true, + "Expression" => true, + "Ruleset" => true, + "AtCharset" => true, + "AtFontFace" => true, + "AtImport" => true, + "AtKeyframes" => true, + "AtMedia" => true, + "AtPage" => true, + "AtVariables" => true + ), is_array($plugins) ? $plugins : array()); + // Create plugin instances + foreach ($plugins as $name => $config) { + if ($config !== false) { + $class = "Css" . $name . "ParserPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->plugins[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); + } + } + } + if (!is_null($source)) { + $this->parse($source); + } + } + + /** + * Parse the CSS source and return a array with parsed tokens. + * + * @param string $source CSS source + * @return array Array with tokens + */ + public function parse($source) + { + // Reset + $this->source = ""; + $this->tokens = array(); + // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create + // several helper variables for plugin handling + $globalTriggerChars = ""; + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerStates = array(); + $pluginTriggerChars = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars()); + $tPluginTriggerStates = $plugins[$i]->getTriggerStates(); + $pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|" . implode("|", $tPluginTriggerStates) . "|"; + $pluginIndex[$tPluginClassName] = $i; + for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++) { + $c = substr($pluginTriggerChars[$i], $ii, 1); + if (strpos($globalTriggerChars, $c) === false) { + $globalTriggerChars .= $c; + } + } + } + // Normalise line endings + $source = str_replace("\r\n", "\n", $source); // Windows to Unix line endings + $source = str_replace("\r", "\n", $source); // Mac to Unix line endings + $this->source = $source; + // Variables + $buffer = & $this->buffer; + $exclusive = & $this->stateExclusive; + $state = & $this->state; + $c = $p = null; + // -- + for ($i = 0, $l = strlen($source); $i < $l; $i++) { + // Set the current Char + $c = $source[$i]; // Is faster than: $c = substr($source, $i, 1); + // Normalize and filter double whitespace characters + if ($exclusive === false) { + if ($c === "\n" || $c === "\t") { + $c = " "; + } + if ($c === " " && $p === " ") { + continue; + } + } + $buffer .= $c; + // Extended processing only if the current char is a global trigger char + if (strpos($globalTriggerChars, $c) !== false) { + // Exclusive state is set; process with the exclusive plugin + if ($exclusive) { + $tPluginIndex = $pluginIndex[$exclusive]; + if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false)) { + $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state); + // Return value is TRUE => continue with next char + if ($r === true) { + continue; + } // Return value is numeric => set new index and continue with next char + elseif ($r !== false && $r != $i) { + $i = $r; + continue; + } + } + } // Else iterate through the plugins + else { + $triggerState = "|" . $state . "|"; + for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++) { + // Only process if the current char is one of the plugin trigger chars + if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false)) { + // Process with the plugin + $r = $plugins[$ii]->parse($i, $c, $p, $state); + // Return value is TRUE => break the plugin loop and and continue with next char + if ($r === true) { + break; + } // Return value is numeric => set new index, break the plugin loop and and continue with next char + elseif ($r !== false && $r != $i) { + $i = $r; + break; + } + } + } + } + } + $p = $c; // Set the parent char + } + return $this->tokens; + } + + /** + * Append a token to the array of tokens. + * + * @param aCssToken $token Token to append + * @return void + */ + public function appendToken(aCssToken $token) + { + $this->tokens[] = $token; + } + + /** + * Clears the current buffer. + * + * @return void + */ + public function clearBuffer() + { + $this->buffer = ""; + } + + /** + * Returns and clear the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getAndClearBuffer($trim = "", $tolower = false) + { + $r = $this->getBuffer($trim, $tolower); + $this->buffer = ""; + return $r; + } + + /** + * Returns the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getBuffer($trim = "", $tolower = false) + { + $r = $this->buffer; + if ($trim) { + $r = trim($r, " \t\n\r\0\x0B" . $trim); + } + if ($tolower) { + $r = strtolower($r); + } + return $r; + } + + /** + * Sets/restores the buffer. + * + * @param string $buffer Buffer to set + * @return void + */ + public function setBuffer($buffer) + { + $this->buffer = $buffer; + } + + /** + * Returns the current media types state. + * + * @return array + */ + public function getMediaTypes() + { + return $this->stateMediaTypes; + } + + /** + * Returns the CSS source. + * + * @return string + */ + public function getSource() + { + return $this->source; + } + + /** + * Returns the current state. + * + * @return integer The current state + */ + public function getState() + { + return $this->state; + } + + /** + * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}. + * + * @param integer $state State to set + * @return integer + */ + public function setState($state) + { + $r = array_pop($this->states); + array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return aCssParserPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } + + /** + * Returns the parsed tokens. + * + * @return array + */ + public function getTokens() + { + return $this->tokens; + } + + /** + * Returns if the current state equals the passed state. + * + * @param integer $state State to compare with the current state + * @return boolean TRUE is the state equals to the passed state; FALSE if not + */ + public function isState($state) + { + return ($this->state == $state); + } + + /** + * Remove the last state of the state stack and return the removed stack value. + * + * @return integer Removed state value + */ + public function popState() + { + $r = array_pop($this->states); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Adds a new state onto the state stack. + * + * @param integer $state State to add onto the state stack. + * @return integer The index of the added state in the state stacks + */ + public function pushState($state) + { + $r = array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Set the exclusive state. + * + * @param string $exclusive Exclusive state + * @return void + */ + public function setExclusive($exclusive) + { + $this->stateExclusive = $exclusive; + } + + /** + * Set the media types state. + * + * @param array $mediaTypes Media types state + * @return void + */ + public function setMediaTypes(array $mediaTypes) + { + $this->stateMediaTypes = $mediaTypes; + } + + /** + * Removes the exclusive state. + * + * @return void + */ + public function unsetExclusive() + { + $this->stateExclusive = false; + } + + /** + * Removes the media types state. + * + * @return void + */ + public function unsetMediaTypes() + { + $this->stateMediaTypes = false; + } +} + +/** + * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style). + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssOtbsFormatter extends aCssFormatter +{ + /** + * Implements {@link aCssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) { + $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; + } + } elseif ($class === "CssAtCharsetToken") { + $r[] = $indent . "@charset " . $token->Charset . ";"; + } elseif ($class === "CssAtFontFaceStartToken") { + $r[] = $indent . "@font-face {"; + $level++; + } elseif ($class === "CssAtImportToken") { + $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; + } elseif ($class === "CssAtKeyframesStartToken") { + $r[] = $indent . "@keyframes \"" . $token->Name . "\" {"; + $level++; + } elseif ($class === "CssAtMediaStartToken") { + $r[] = $indent . "@media " . implode(", ", $token->MediaTypes) . " {"; + $level++; + } elseif ($class === "CssAtPageStartToken") { + $r[] = $indent . "@page {"; + $level++; + } elseif ($class === "CssAtVariablesStartToken") { + $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes) . " {"; + $level++; + } elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") { + $r[] = $indent . implode(", ", $token->Selectors) . " {"; + $level++; + } elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) { + $declaration = $indent . $token->Property . ": "; + if ($this->padding) { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; + } elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) { + $level--; + $r[] = str_repeat($indent, $level) . "}"; + } + } + return implode("\n", $r); + } +} + +/** + * This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssNullToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * CSS Minifier. + * + * @package CssMin/Minifier + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssMinifier +{ + /** + * {@link aCssMinifierFilter Filters}. + * + * @var array + */ + private $filters = array(); + /** + * {@link aCssMinifierPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Minified source. + * + * @var string + */ + private $minified = ""; + + /** + * Constructer. + * + * Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $filters = null, array $plugins = null) + { + $filters = array_merge(array + ( + "ImportImports" => false, + "RemoveComments" => true, + "RemoveEmptyRulesets" => true, + "RemoveEmptyAtBlocks" => true, + "ConvertLevel3Properties" => false, + "ConvertLevel3AtKeyframes" => false, + "Variables" => true, + "RemoveLastDelarationSemiColon" => true + ), is_array($filters) ? $filters : array()); + $plugins = array_merge(array + ( + "Variables" => true, + "ConvertFontWeight" => false, + "ConvertHslColors" => false, + "ConvertRgbColors" => false, + "ConvertNamedColors" => false, + "CompressColorValues" => false, + "CompressUnitValues" => false, + "CompressExpressionValues" => false + ), is_array($plugins) ? $plugins : array()); + // Filters + foreach ($filters as $name => $config) { + if ($config !== false) { + $class = "Css" . $name . "MinifierFilter"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->filters[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The filter " . $name . " with the class name " . $class . " was not found")); + } + } + } + // Plugins + foreach ($plugins as $name => $config) { + if ($config !== false) { + $class = "Css" . $name . "MinifierPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->plugins[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); + } + } + } + // -- + if (!is_null($source)) { + $this->minify($source); + } + } + + /** + * Minifies the CSS source. + * + * @param string $source CSS source + * @return string + */ + public function minify($source) + { + // Variables + $r = ""; + $parser = new CssParser($source); + $tokens = $parser->getTokens(); + $filters = $this->filters; + $filterCount = count($this->filters); + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerTokens = array(); + $globalTriggerTokens = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens(); + foreach ($pluginTriggerTokens[$i] as $v) { + if (!in_array($v, $globalTriggerTokens)) { + $globalTriggerTokens[] = $v; + } + } + $pluginTriggerTokens[$i] = "|" . implode("|", $pluginTriggerTokens[$i]) . "|"; + $pluginIndex[$tPluginClassName] = $i; + } + $globalTriggerTokens = "|" . implode("|", $globalTriggerTokens) . "|"; + /* + * Apply filters + */ + for ($i = 0; $i < $filterCount; $i++) { + // Apply the filter; if the return value is larger than 0... + if ($filters[$i]->apply($tokens) > 0) { + // ...then filter null values and rebuild the token array + $tokens = array_values(array_filter($tokens)); + } + } + $tokenCount = count($tokens); + /* + * Apply plugins + */ + for ($i = 0; $i < $tokenCount; $i++) { + $triggerToken = "|" . get_class($tokens[$i]) . "|"; + if (strpos($globalTriggerTokens, $triggerToken) !== false) { + for ($ii = 0; $ii < $pluginCount; $ii++) { + if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false) { + // Apply the plugin; if the return value is TRUE continue to the next token + if ($plugins[$ii]->apply($tokens[$i]) === true) { + continue 2; + } + } + } + } + } + // Stringify the tokens + for ($i = 0; $i < $tokenCount; $i++) { + $r .= (string)$tokens[$i]; + } + $this->minified = $r; + return $r; + } + + /** + * Returns the minified Source. + * + * @return string + */ + public function getMinified() + { + return $this->minified; + } + + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return aCssMinifierPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } +} + +/** + * CssMin - A (simple) css minifier with benefits + * + * -- + * Copyright (c) 2011 Joe Scylla + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * -- + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssMin +{ + /** + * Index of classes + * + * @var array + */ + private static $classIndex = array(); + /** + * Parse/minify errors + * + * @var array + */ + private static $errors = array(); + /** + * Verbose output. + * + * @var boolean + */ + private static $isVerbose = false; + + /** + * {@link http://goo.gl/JrW54 Autoload} function of CssMin. + * + * @param string $class Name of the class + * @return void + */ + public static function autoload($class) + { + if (isset(self::$classIndex[$class])) { + require(self::$classIndex[$class]); + } + } + + /** + * Return errors + * + * @return array of {CssError}. + */ + public static function getErrors() + { + return self::$errors; + } + + /** + * Returns if there were errors. + * + * @return boolean + */ + public static function hasErrors() + { + return count(self::$errors) > 0; + } + + /** + * Initialises CssMin. + * + * @return void + */ + public static function initialise() + { + // Create the class index for autoloading or including + $paths = array(dirname(__FILE__)); + while (list($i, $path) = each($paths)) { + $subDirectorys = glob($path . "*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT); + if (is_array($subDirectorys)) { + foreach ($subDirectorys as $subDirectory) { + $paths[] = $subDirectory; + } + } + $files = glob($path . "*.php", 0); + if (is_array($files)) { + foreach ($files as $file) { + $class = substr(basename($file), 0, -4); + self::$classIndex[$class] = $file; + } + } + } + krsort(self::$classIndex); + // Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because + // __autoload() breaks if spl_autoload_register() is used. + if (function_exists("spl_autoload_register") && !is_callable("__autoload")) { + spl_autoload_register(array(__CLASS__, "autoload")); + } // Otherwise include all class files + else { + foreach (self::$classIndex as $class => $file) { + if (!class_exists($class)) { + require_once($file); + } + } + } + } + + /** + * Minifies CSS source. + * + * @param string $source CSS source + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return string Minified CSS + */ + public static function minify($source, array $filters = null, array $plugins = null) + { + self::$errors = array(); + $minifier = new CssMinifier($source, $filters, $plugins); + return $minifier->getMinified(); + } + + /** + * Parse the CSS source. + * + * @param string $source CSS source + * @param array $plugins Plugin configuration [optional] + * @return array Array of aCssToken + */ + public static function parse($source, array $plugins = null) + { + self::$errors = array(); + $parser = new CssParser($source, $plugins); + return $parser->getTokens(); + } + + /** + * -- + * + * @param boolean $to + * @return boolean + */ + public static function setVerbose($to) + { + self::$isVerbose = (boolean)$to; + return self::$isVerbose; + } + + /** + * -- + * + * @param CssError $error + * @return void + */ + public static function triggerError(CssError $error) + { + self::$errors[] = $error; + if (self::$isVerbose) { + trigger_error((string)$error, E_USER_WARNING); + } + } +} + +// Initialises CssMin +CssMin::initialise(); + +/** + * This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the + * current stylesheet. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssImportImportsMinifierFilter extends aCssMinifierFilter +{ + /** + * Array with already imported external stylesheets. + * + * @var array + */ + private $imported = array(); + + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"])) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Base path " . ($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null") . " is not a directory")); + return 0; + } + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssAtImportToken") { + $import = $this->configuration["BasePath"] . "/" . $tokens[$i]->Import; + // Import file was not found/is not a file + if (!is_file($import)) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import . " was not found.", (string)$tokens[$i])); + } // Import file already imported; remove this @import at-rule to prevent recursions + elseif (in_array($import, $this->imported)) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import . " was already imported.", (string)$tokens[$i])); + $tokens[$i] = null; + } else { + $this->imported[] = $import; + $parser = new CssParser(file_get_contents($import)); + $import = $parser->getTokens(); + // The @import at-rule has media types defined requiring special handling + if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all")) { + $blocks = array(); + /* + * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtImportToken") { + // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule + if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all")) { + $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes; + } // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule + elseif (count($import[$ii]->MediaTypes > 0)) { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) { + unset($import[$ii]->MediaTypes[$index]); + } + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + // If there are no media types left in the @import at-rule remove the @import at-rule + if (count($import[$ii]->MediaTypes) == 0) { + $import[$ii] = null; + } + } + } + } + /* + * Remove media types of @media at-rule block not defined in the @import at-rule + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken") { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) { + unset($import[$ii]->MediaTypes[$index]); + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + } + } + } + /* + * If no media types left of the @media at-rule block remove the complete block + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken") { + if (count($import[$ii]->MediaTypes) === 0) { + for ($iii = $ii; $iii < $ll; $iii++) { + if (get_class($import[$iii]) === "CssAtMediaEndToken") { + break; + } + } + if (get_class($import[$iii]) === "CssAtMediaEndToken") { + array_splice($import, $ii, $iii - $ii + 1, array()); + $ll = count($import); + } + } + } + } + /* + * If the media types of the @media at-rule equals the media types defined in the @import + * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0) { + for ($iii = $ii; $iii < $ll; $iii++) { + if (get_class($import[$iii]) == "CssAtMediaEndToken") { + break; + } + } + if (get_class($import[$iii]) == "CssAtMediaEndToken") { + unset($import[$ii]); + unset($import[$iii]); + $import = array_values($import); + $ll = count($import); + } + } + } + /** + * Extract CssAtImportToken and CssAtCharsetToken tokens + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + $class = get_class($import[$ii]); + if ($class === "CssAtImportToken" || $class === "CssAtCharsetToken") { + $blocks = array_merge($blocks, array_splice($import, $ii, 1, array())); + $ll = count($import); + } + } + /* + * Extract the @font-face, @media and @page at-rule block + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + $class = get_class($import[$ii]); + if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken") { + for ($iii = $ii; $iii < $ll; $iii++) { + $class = get_class($import[$iii]); + if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken") { + break; + } + } + $class = get_class($import[$iii]); + if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")) { + $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array())); + $ll = count($import); + } + } + } + // Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block + $import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken())); + } + // Insert the imported tokens + array_splice($tokens, $i, 1, $import); + // Modify parameters of the for-loop + $i--; + $l = count($tokens); + } + } + } + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing expression() declaration values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that expression() declaration values will get parsed + * properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssExpressionParserPlugin extends aCssParserPlugin +{ + /** + * Count of left braces. + * + * @var integer + */ + private $leftBraces = 0; + /** + * Count of right braces. + * + * @var integer + */ + private $rightBraces = 0; + + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")", ";", "}"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of expression + if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION") { + $this->parser->pushState("T_EXPRESSION"); + $this->leftBraces++; + } // Count left braces + elseif ($char === "(" && $state === "T_EXPRESSION") { + $this->leftBraces++; + } // Count right braces + elseif ($char === ")" && $state === "T_EXPRESSION") { + $this->rightBraces++; + } // Possible end of expression; if left and right braces are equal the expressen ends + elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces) { + $this->leftBraces = $this->rightBraces = 0; + $this->parser->popState(); + return $index - 1; + } else { + return false; + } + return true; + } +} + +/** + * CSS Error. + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssError +{ + /** + * File. + * + * @var string + */ + public $File = ""; + /** + * Line. + * + * @var integer + */ + public $Line = 0; + /** + * Error message. + * + * @var string + */ + public $Message = ""; + /** + * Source. + * + * @var string + */ + public $Source = ""; + + /** + * Constructor triggering the error. + * + * @param string $message Error message + * @param string $source Corresponding line [optional] + * @return void + */ + public function __construct($file, $line, $message, $source = "") + { + $this->File = $file; + $this->Line = $line; + $this->Message = $message; + $this->Source = $source; + } + + /** + * Returns the error as formatted string. + * + * @return string + */ + public function __toString() + { + return $this->Message . ($this->Source ? ":
" . $this->Source . "" : "") . "
in file " . $this->File . " at line " . $this->Line; + } +} + +/** + * This {@link aCssMinifierPlugin} will convert a color value in rgb notation to hexadecimal notation. + * + * Example: + * + * color: rgb(200,60%,5); + * + * + * Will get converted to: + * + * color:#c89905; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS"; + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "rgb") !== false && preg_match($this->reMatch, $token->Value, $m)) { + for ($i = 1, $l = count($m); $i < $l; $i++) { + if (strpos("%", $m[$i]) !== false) { + $m[$i] = substr($m[$i], 0, -1); + $m[$i] = (int)(256 * ($m[$i] / 100)); + } + $m[$i] = str_pad(dechex($m[$i]), 2, "0", STR_PAD_LEFT); + } + $token->Value = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will convert named color values to hexadecimal notation. + * + * Example: + * + * color: black; + * border: 1px solid indigo; + * + * + * Will get converted to: + * + * color:#000; + * border:1px solid #4b0082; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin +{ + + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Regular expression replacing the value. + * + * @var string + */ + private $reReplace = "\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\""; + /** + * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}. + * + * @var array + */ + private $transformation = array + ( + "aliceblue" => "#f0f8ff", + "antiquewhite" => "#faebd7", + "aqua" => "#0ff", + "aquamarine" => "#7fffd4", + "azure" => "#f0ffff", + "beige" => "#f5f5dc", + "black" => "#000", + "blue" => "#00f", + "blueviolet" => "#8a2be2", + "brown" => "#a52a2a", + "burlywood" => "#deb887", + "cadetblue" => "#5f9ea0", + "chartreuse" => "#7fff00", + "chocolate" => "#d2691e", + "coral" => "#ff7f50", + "cornflowerblue" => "#6495ed", + "cornsilk" => "#fff8dc", + "crimson" => "#dc143c", + "darkblue" => "#00008b", + "darkcyan" => "#008b8b", + "darkgoldenrod" => "#b8860b", + "darkgray" => "#a9a9a9", + "darkgreen" => "#006400", + "darkkhaki" => "#bdb76b", + "darkmagenta" => "#8b008b", + "darkolivegreen" => "#556b2f", + "darkorange" => "#ff8c00", + "darkorchid" => "#9932cc", + "darkred" => "#8b0000", + "darksalmon" => "#e9967a", + "darkseagreen" => "#8fbc8f", + "darkslateblue" => "#483d8b", + "darkslategray" => "#2f4f4f", + "darkturquoise" => "#00ced1", + "darkviolet" => "#9400d3", + "deeppink" => "#ff1493", + "deepskyblue" => "#00bfff", + "dimgray" => "#696969", + "dodgerblue" => "#1e90ff", + "firebrick" => "#b22222", + "floralwhite" => "#fffaf0", + "forestgreen" => "#228b22", + "fuchsia" => "#f0f", + "gainsboro" => "#dcdcdc", + "ghostwhite" => "#f8f8ff", + "gold" => "#ffd700", + "goldenrod" => "#daa520", + "gray" => "#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", + "lightgreen" => "#90ee90", + "lightgrey" => "#d3d3d3", + "lightpink" => "#ffb6c1", + "lightsalmon" => "#ffa07a", + "lightseagreen" => "#20b2aa", + "lightskyblue" => "#87cefa", + "lightslategray" => "#789", + "lightsteelblue" => "#b0c4de", + "lightyellow" => "#ffffe0", + "lime" => "#0f0", + "limegreen" => "#32cd32", + "linen" => "#faf0e6", + "maroon" => "#800000", + "mediumaquamarine" => "#66cdaa", + "mediumblue" => "#0000cd", + "mediumorchid" => "#ba55d3", + "mediumpurple" => "#9370db", + "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" => "#db7093", + "papayawhip" => "#ffefd5", + "peachpuff" => "#ffdab9", + "peru" => "#cd853f", + "pink" => "#ffc0cb", + "plum" => "#dda0dd", + "powderblue" => "#b0e0e6", + "purple" => "#800080", + "red" => "#f00", + "rosybrown" => "#bc8f8f", + "royalblue" => "#4169e1", + "saddlebrown" => "#8b4513", + "salmon" => "#fa8072", + "sandybrown" => "#f4a460", + "seagreen" => "#2e8b57", + "seashell" => "#fff5ee", + "sienna" => "#a0522d", + "silver" => "#c0c0c0", + "skyblue" => "#87ceeb", + "slateblue" => "#6a5acd", + "slategray" => "#708090", + "snow" => "#fffafa", + "springgreen" => "#00ff7f", + "steelblue" => "#4682b4", + "tan" => "#d2b48c", + "teal" => "#008080", + "thistle" => "#d8bfd8", + "tomato" => "#ff6347", + "turquoise" => "#40e0d0", + "violet" => "#ee82ee", + "wheat" => "#f5deb3", + "white" => "#fff", + "whitesmoke" => "#f5f5f5", + "yellow" => "#ff0", + "yellowgreen" => "#9acd32" + ); + + /** + * Overwrites {@link aCssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression} + * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)) . ")(\s|$)+/eiS"; + parent::__construct($minifier, $configuration); + } + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + $lcValue = strtolower($token->Value); + // Declaration value equals a value in the transformation table => simple replace + if (isset($this->transformation[$lcValue])) { + $token->Value = $this->transformation[$lcValue]; + } // Declaration value contains a value in the transformation table => regular expression replace + elseif (preg_match($this->reMatch, $token->Value)) { + $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} triggers on CSS Level 3 properties and will add declaration tokens + * with browser-specific properties. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter +{ + /** + * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific + * counterparts. + * + * @var array + */ + private $transformations = array + ( + // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored + "animation" => array(null, "-webkit-animation", null, null), + "animation-delay" => array(null, "-webkit-animation-delay", null, null), + "animation-direction" => array(null, "-webkit-animation-direction", null, null), + "animation-duration" => array(null, "-webkit-animation-duration", null, null), + "animation-fill-mode" => array(null, "-webkit-animation-fill-mode", null, null), + "animation-iteration-count" => array(null, "-webkit-animation-iteration-count", null, null), + "animation-name" => array(null, "-webkit-animation-name", null, null), + "animation-play-state" => array(null, "-webkit-animation-play-state", null, null), + "animation-timing-function" => array(null, "-webkit-animation-timing-function", null, null), + "appearance" => array("-moz-appearance", "-webkit-appearance", null, null), + "backface-visibility" => array(null, "-webkit-backface-visibility", null, null), + "background-clip" => array(null, "-webkit-background-clip", null, null), + "background-composite" => array(null, "-webkit-background-composite", null, null), + "background-inline-policy" => array("-moz-background-inline-policy", null, null, null), + "background-origin" => array(null, "-webkit-background-origin", null, null), + "background-position-x" => array(null, null, null, "-ms-background-position-x"), + "background-position-y" => array(null, null, null, "-ms-background-position-y"), + "background-size" => array(null, "-webkit-background-size", null, null), + "behavior" => array(null, null, null, "-ms-behavior"), + "binding" => array("-moz-binding", null, null, null), + "border-after" => array(null, "-webkit-border-after", null, null), + "border-after-color" => array(null, "-webkit-border-after-color", null, null), + "border-after-style" => array(null, "-webkit-border-after-style", null, null), + "border-after-width" => array(null, "-webkit-border-after-width", null, null), + "border-before" => array(null, "-webkit-border-before", null, null), + "border-before-color" => array(null, "-webkit-border-before-color", null, null), + "border-before-style" => array(null, "-webkit-border-before-style", null, null), + "border-before-width" => array(null, "-webkit-border-before-width", null, null), + "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null), + "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null), + "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null), + "border-end" => array("-moz-border-end", "-webkit-border-end", null, null), + "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null), + "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null), + "border-end-width" => array("-moz-border-end-width", "-webkit-border-end-width", null, null), + "border-fit" => array(null, "-webkit-border-fit", null, null), + "border-horizontal-spacing" => array(null, "-webkit-border-horizontal-spacing", null, null), + "border-image" => array("-moz-border-image", "-webkit-border-image", null, null), + "border-left-colors" => array("-moz-border-left-colors", null, null, null), + "border-radius" => array("-moz-border-radius", "-webkit-border-radius", null, null), + "border-border-right-colors" => array("-moz-border-right-colors", null, null, null), + "border-start" => array("-moz-border-start", "-webkit-border-start", null, null), + "border-start-color" => array("-moz-border-start-color", "-webkit-border-start-color", null, null), + "border-start-style" => array("-moz-border-start-style", "-webkit-border-start-style", null, null), + "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null), + "border-top-colors" => array("-moz-border-top-colors", null, null, null), + "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null), + "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null), + "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null), + "box-align" => array("-moz-box-align", "-webkit-box-align", null, null), + "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null), + "box-flex" => array("-moz-box-flex", "-webkit-box-flex", null, null), + "box-flex-group" => array(null, "-webkit-box-flex-group", null, null), + "box-flex-lines" => array(null, "-webkit-box-flex-lines", null, null), + "box-ordinal-group" => array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null), + "box-orient" => array("-moz-box-orient", "-webkit-box-orient", null, null), + "box-pack" => array("-moz-box-pack", "-webkit-box-pack", null, null), + "box-reflect" => array(null, "-webkit-box-reflect", null, null), + "box-shadow" => array("-moz-box-shadow", "-webkit-box-shadow", null, null), + "box-sizing" => array("-moz-box-sizing", null, null, null), + "color-correction" => array(null, "-webkit-color-correction", null, null), + "column-break-after" => array(null, "-webkit-column-break-after", null, null), + "column-break-before" => array(null, "-webkit-column-break-before", null, null), + "column-break-inside" => array(null, "-webkit-column-break-inside", null, null), + "column-count" => array("-moz-column-count", "-webkit-column-count", null, null), + "column-gap" => array("-moz-column-gap", "-webkit-column-gap", null, null), + "column-rule" => array("-moz-column-rule", "-webkit-column-rule", null, null), + "column-rule-color" => array("-moz-column-rule-color", "-webkit-column-rule-color", null, null), + "column-rule-style" => array("-moz-column-rule-style", "-webkit-column-rule-style", null, null), + "column-rule-width" => array("-moz-column-rule-width", "-webkit-column-rule-width", null, null), + "column-span" => array(null, "-webkit-column-span", null, null), + "column-width" => array("-moz-column-width", "-webkit-column-width", null, null), + "columns" => array(null, "-webkit-columns", null, null), + "filter" => array(__CLASS__, "filter"), + "float-edge" => array("-moz-float-edge", null, null, null), + "font-feature-settings" => array("-moz-font-feature-settings", null, null, null), + "font-language-override" => array("-moz-font-language-override", null, null, null), + "font-size-delta" => array(null, "-webkit-font-size-delta", null, null), + "font-smoothing" => array(null, "-webkit-font-smoothing", null, null), + "force-broken-image-icon" => array("-moz-force-broken-image-icon", null, null, null), + "highlight" => array(null, "-webkit-highlight", null, null), + "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null), + "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null), + "hyphens" => array(null, "-webkit-hyphens", null, null), + "force-broken-image-icon" => array("-moz-image-region", null, null, null), + "ime-mode" => array(null, null, null, "-ms-ime-mode"), + "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"), + "layout-flow" => array(null, null, null, "-ms-layout-flow"), + "layout-grid" => array(null, null, null, "-ms-layout-grid"), + "layout-grid-char" => array(null, null, null, "-ms-layout-grid-char"), + "layout-grid-line" => array(null, null, null, "-ms-layout-grid-line"), + "layout-grid-mode" => array(null, null, null, "-ms-layout-grid-mode"), + "layout-grid-type" => array(null, null, null, "-ms-layout-grid-type"), + "line-break" => array(null, "-webkit-line-break", null, "-ms-line-break"), + "line-clamp" => array(null, "-webkit-line-clamp", null, null), + "line-grid-mode" => array(null, null, null, "-ms-line-grid-mode"), + "logical-height" => array(null, "-webkit-logical-height", null, null), + "logical-width" => array(null, "-webkit-logical-width", null, null), + "margin-after" => array(null, "-webkit-margin-after", null, null), + "margin-after-collapse" => array(null, "-webkit-margin-after-collapse", null, null), + "margin-before" => array(null, "-webkit-margin-before", null, null), + "margin-before-collapse" => array(null, "-webkit-margin-before-collapse", null, null), + "margin-bottom-collapse" => array(null, "-webkit-margin-bottom-collapse", null, null), + "margin-collapse" => array(null, "-webkit-margin-collapse", null, null), + "margin-end" => array("-moz-margin-end", "-webkit-margin-end", null, null), + "margin-start" => array("-moz-margin-start", "-webkit-margin-start", null, null), + "margin-top-collapse" => array(null, "-webkit-margin-top-collapse", null, null), + "marquee " => array(null, "-webkit-marquee", null, null), + "marquee-direction" => array(null, "-webkit-marquee-direction", null, null), + "marquee-increment" => array(null, "-webkit-marquee-increment", null, null), + "marquee-repetition" => array(null, "-webkit-marquee-repetition", null, null), + "marquee-speed" => array(null, "-webkit-marquee-speed", null, null), + "marquee-style" => array(null, "-webkit-marquee-style", null, null), + "mask" => array(null, "-webkit-mask", null, null), + "mask-attachment" => array(null, "-webkit-mask-attachment", null, null), + "mask-box-image" => array(null, "-webkit-mask-box-image", null, null), + "mask-clip" => array(null, "-webkit-mask-clip", null, null), + "mask-composite" => array(null, "-webkit-mask-composite", null, null), + "mask-image" => array(null, "-webkit-mask-image", null, null), + "mask-origin" => array(null, "-webkit-mask-origin", null, null), + "mask-position" => array(null, "-webkit-mask-position", null, null), + "mask-position-x" => array(null, "-webkit-mask-position-x", null, null), + "mask-position-y" => array(null, "-webkit-mask-position-y", null, null), + "mask-repeat" => array(null, "-webkit-mask-repeat", null, null), + "mask-repeat-x" => array(null, "-webkit-mask-repeat-x", null, null), + "mask-repeat-y" => array(null, "-webkit-mask-repeat-y", null, null), + "mask-size" => array(null, "-webkit-mask-size", null, null), + "match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null), + "max-logical-height" => array(null, "-webkit-max-logical-height", null, null), + "max-logical-width" => array(null, "-webkit-max-logical-width", null, null), + "min-logical-height" => array(null, "-webkit-min-logical-height", null, null), + "min-logical-width" => array(null, "-webkit-min-logical-width", null, null), + "object-fit" => array(null, null, "-o-object-fit", null), + "object-position" => array(null, null, "-o-object-position", null), + "opacity" => array(__CLASS__, "opacity"), + "outline-radius" => array("-moz-outline-radius", null, null, null), + "outline-bottom-left-radius" => array("-moz-outline-radius-bottomleft", null, null, null), + "outline-bottom-right-radius" => array("-moz-outline-radius-bottomright", null, null, null), + "outline-top-left-radius" => array("-moz-outline-radius-topleft", null, null, null), + "outline-top-right-radius" => array("-moz-outline-radius-topright", null, null, null), + "padding-after" => array(null, "-webkit-padding-after", null, null), + "padding-before" => array(null, "-webkit-padding-before", null, null), + "padding-end" => array("-moz-padding-end", "-webkit-padding-end", null, null), + "padding-start" => array("-moz-padding-start", "-webkit-padding-start", null, null), + "perspective" => array(null, "-webkit-perspective", null, null), + "perspective-origin" => array(null, "-webkit-perspective-origin", null, null), + "perspective-origin-x" => array(null, "-webkit-perspective-origin-x", null, null), + "perspective-origin-y" => array(null, "-webkit-perspective-origin-y", null, null), + "rtl-ordering" => array(null, "-webkit-rtl-ordering", null, null), + "scrollbar-3dlight-color" => array(null, null, null, "-ms-scrollbar-3dlight-color"), + "scrollbar-arrow-color" => array(null, null, null, "-ms-scrollbar-arrow-color"), + "scrollbar-base-color" => array(null, null, null, "-ms-scrollbar-base-color"), + "scrollbar-darkshadow-color" => array(null, null, null, "-ms-scrollbar-darkshadow-color"), + "scrollbar-face-color" => array(null, null, null, "-ms-scrollbar-face-color"), + "scrollbar-highlight-color" => array(null, null, null, "-ms-scrollbar-highlight-color"), + "scrollbar-shadow-color" => array(null, null, null, "-ms-scrollbar-shadow-color"), + "scrollbar-track-color" => array(null, null, null, "-ms-scrollbar-track-color"), + "stack-sizing" => array("-moz-stack-sizing", null, null, null), + "svg-shadow" => array(null, "-webkit-svg-shadow", null, null), + "tab-size" => array("-moz-tab-size", null, "-o-tab-size", null), + "table-baseline" => array(null, null, "-o-table-baseline", null), + "text-align-last" => array(null, null, null, "-ms-text-align-last"), + "text-autospace" => array(null, null, null, "-ms-text-autospace"), + "text-combine" => array(null, "-webkit-text-combine", null, null), + "text-decorations-in-effect" => array(null, "-webkit-text-decorations-in-effect", null, null), + "text-emphasis" => array(null, "-webkit-text-emphasis", null, null), + "text-emphasis-color" => array(null, "-webkit-text-emphasis-color", null, null), + "text-emphasis-position" => array(null, "-webkit-text-emphasis-position", null, null), + "text-emphasis-style" => array(null, "-webkit-text-emphasis-style", null, null), + "text-fill-color" => array(null, "-webkit-text-fill-color", null, null), + "text-justify" => array(null, null, null, "-ms-text-justify"), + "text-kashida-space" => array(null, null, null, "-ms-text-kashida-space"), + "text-overflow" => array(null, null, "-o-text-overflow", "-ms-text-overflow"), + "text-security" => array(null, "-webkit-text-security", null, null), + "text-size-adjust" => array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"), + "text-stroke" => array(null, "-webkit-text-stroke", null, null), + "text-stroke-color" => array(null, "-webkit-text-stroke-color", null, null), + "text-stroke-width" => array(null, "-webkit-text-stroke-width", null, null), + "text-underline-position" => array(null, null, null, "-ms-text-underline-position"), + "transform" => array("-moz-transform", "-webkit-transform", "-o-transform", null), + "transform-origin" => array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null), + "transform-origin-x" => array(null, "-webkit-transform-origin-x", null, null), + "transform-origin-y" => array(null, "-webkit-transform-origin-y", null, null), + "transform-origin-z" => array(null, "-webkit-transform-origin-z", null, null), + "transform-style" => array(null, "-webkit-transform-style", null, null), + "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null), + "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null), + "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null), + "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null), + "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null), + "user-drag" => array(null, "-webkit-user-drag", null, null), + "user-focus" => array("-moz-user-focus", null, null, null), + "user-input" => array("-moz-user-input", null, null, null), + "user-modify" => array("-moz-user-modify", "-webkit-user-modify", null, null), + "user-select" => array("-moz-user-select", "-webkit-user-select", null, null), + "white-space" => array(__CLASS__, "whiteSpace"), + "window-shadow" => array("-moz-window-shadow", null, null, null), + "word-break" => array(null, null, null, "-ms-word-break"), + "word-wrap" => array(null, null, null, "-ms-word-wrap"), + "writing-mode" => array(null, "-webkit-writing-mode", null, "-ms-writing-mode"), + "zoom" => array(null, null, null, "-ms-zoom") + ); + + /** + * Transforms the Internet Explorer specific declaration property "filter" to Internet Explorer 8+ compatible + * declaratiopn property "-ms-filter". + * + * @param aCssToken $token + * @return array + */ + private static function filter($token) + { + $r = array + ( + new CssRulesetDeclarationToken("-ms-filter", "\"" . $token->Value . "\"", $token->MediaTypes), + ); + return $r; + } + + /** + * Transforms "opacity: {value}" into browser specific counterparts. + * + * @param aCssToken $token + * @return array + */ + private static function opacity($token) + { + // Calculate the value for Internet Explorer filter statement + $ieValue = (int)((float)$token->Value * 100); + $r = array + ( + // Internet Explorer >= 8 + new CssRulesetDeclarationToken("-ms-filter", "\"alpha(opacity=" . $ieValue . ")\"", $token->MediaTypes), + // Internet Explorer >= 4 <= 7 + new CssRulesetDeclarationToken("filter", "alpha(opacity=" . $ieValue . ")", $token->MediaTypes), + new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes) + ); + return $r; + } + + /** + * Transforms "white-space: pre-wrap" into browser specific counterparts. + * + * @param aCssToken $token + * @return array + */ + private static function whiteSpace($token) + { + if (strtolower($token->Value) === "pre-wrap") { + $r = array + ( + // Firefox < 3 + new CssRulesetDeclarationToken("white-space", "-moz-pre-wrap", $token->MediaTypes), + // Webkit + new CssRulesetDeclarationToken("white-space", "-webkit-pre-wrap", $token->MediaTypes), + // Opera >= 4 <= 6 + new CssRulesetDeclarationToken("white-space", "-pre-wrap", $token->MediaTypes), + // Opera >= 7 + new CssRulesetDeclarationToken("white-space", "-o-pre-wrap", $token->MediaTypes), + // Internet Explorer >= 5.5 + new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes) + ); + return $r; + } else { + return array(); + } + } + + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = & $this->transformations; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssRulesetDeclarationToken") { + $tProperty = $tokens[$i]->Property; + if (isset($transformations[$tProperty])) { + $result = array(); + if (is_callable($transformations[$tProperty])) { + $result = call_user_func_array($transformations[$tProperty], array($tokens[$i])); + if (!is_array($result) && is_object($result)) { + $result = array($result); + } + } else { + $tValue = $tokens[$i]->Value; + $tMediaTypes = $tokens[$i]->MediaTypes; + foreach ($transformations[$tProperty] as $property) { + if ($property !== null) { + $result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes); + } + } + } + if (count($result) > 0) { + array_splice($tokens, $i + 1, 0, $result); + $i += count($result); + $l += count($result); + } + } + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = array("-moz-keyframes", "-webkit-keyframes"); + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssAtKeyframesStartToken") { + for ($ii = $i; $ii < $l; $ii++) { + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") { + break; + } + } + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") { + $add = array(); + $source = array(); + for ($iii = $i; $iii <= $ii; $iii++) { + $source[] = clone($tokens[$iii]); + } + foreach ($transformations as $transformation) { + $t = array(); + foreach ($source as $token) { + $t[] = clone($token); + } + $t[0]->AtRuleName = $transformation; + $add = array_merge($add, $t); + } + if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true) { + array_splice($tokens, $i, $ii - $i + 1, $add); + } else { + array_splice($tokens, $ii + 1, 0, $add); + } + $l = count($tokens); + $i = $ii + count($add); + $r += count($add); + } + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierPlugin} will convert a color value in hsl notation to hexadecimal notation. + * + * Example: + * + * color: hsl(232,36%,48%); + * + * + * Will get converted to: + * + * color:#4e5aa7; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS"; + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "hsl") !== false && preg_match($this->reMatch, $token->Value, $m)) { + $token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value); + } + return false; + } + + /** + * Convert a HSL value to hexadecimal notation. + * + * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}. + * + * @param integer $hue Hue + * @param integer $saturation Saturation + * @param integer $lightness Lightnesss + * @return string + */ + private function hsl2hex($hue, $saturation, $lightness) + { + $hue = $hue / 360; + $saturation = $saturation / 100; + $lightness = $lightness / 100; + if ($saturation == 0) { + $red = $lightness * 255; + $green = $lightness * 255; + $blue = $lightness * 255; + } else { + if ($lightness < 0.5) { + $v2 = $lightness * (1 + $saturation); + } else { + $v2 = ($lightness + $saturation) - ($saturation * $lightness); + } + $v1 = 2 * $lightness - $v2; + $red = 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3)); + $green = 255 * self::hue2rgb($v1, $v2, $hue); + $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3)); + } + return "#" . str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); + } + + /** + * Apply hue to a rgb color value. + * + * @param integer $v1 Value 1 + * @param integer $v2 Value 2 + * @param integer $hue Hue + * @return integer + */ + private function hue2rgb($v1, $v2, $hue) + { + if ($hue < 0) { + $hue += 1; + } + if ($hue > 1) { + $hue -= 1; + } + if ((6 * $hue) < 1) { + return ($v1 + ($v2 - $v1) * 6 * $hue); + } + if ((2 * $hue) < 1) { + return ($v2); + } + if ((3 * $hue) < 2) { + return ($v1 + ($v2 - $v1) * ((2 / 3) - $hue) * 6); + } + return $v1; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will convert the font-weight values normal and bold to their numeric notation. + * + * Example: + * + * font-weight: normal; + * font: bold 11px monospace; + * + * + * Will get converted to: + * + * font-weight:400; + * font:700 11px monospace; + * + * + * @package CssMin/Minifier/Pluginsn + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Array of included declaration properties this plugin will process; others declaration properties will get + * ignored. + * + * @var array + */ + private $include = array + ( + "font", + "font-weight" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Regular expression replace the value. + * + * @var string + */ + private $reReplace = "\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\""; + /** + * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}. + * + * @var array + */ + private $transformation = array + ( + "normal" => "400", + "bold" => "700" + ); + + /** + * Overwrites {@link aCssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression} + * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @return void + */ + public function __construct(CssMinifier $minifier) + { + $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)) . ")(\s|$)+/eiS"; + parent::__construct($minifier); + } + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m)) { + $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will compress several unit values to their short notations. Examples: + * + * + * padding: 0.5em; + * border: 0px; + * margin: 0 0 0 0; + * + * + * Will get compressed to: + * + * + * padding:.5px; + * border:0; + * margin:0; + * + * + * -- + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression used for matching and replacing unit values. + * + * @var array + */ + private $re = array + ( + "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}.\${2}\${4}", + "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}0", + "/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" => "0" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS"; + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (preg_match($this->reMatch, $token->Value)) { + foreach ($this->re as $reMatch => $reReplace) { + $token->Value = preg_replace($reMatch, $reReplace, $token->Value); + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} compress the content of expresssion() declaration values. + * + * For compression of expressions {@link https://github.com/rgrove/jsmin-php/ JSMin} will get used. JSMin have to be + * already included or loadable via {@link http://goo.gl/JrW54 PHP autoloading}. + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (class_exists("JSMin") && stripos($token->Value, "expression(") !== false) { + $value = $token->Value; + $value = substr($token->Value, stripos($token->Value, "expression(") + 10); + $value = trim(JSMin::minify($value)); + $token->Value = "expression(" . $value . ")"; + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will convert hexadecimal color value with 6 chars to their 3 char hexadecimal + * notation (if possible). + * + * Example: + * + * color: #aabbcc; + * + * + * Will get converted to: + * + * color:#abc; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching 6 char hexadecimal color values. + * + * @var string + */ + private $reMatch = "/\#([0-9a-f]{6})/iS"; + + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (strpos($token->Value, "#") !== false && preg_match($this->reMatch, $token->Value, $m)) { + $value = strtolower($m[1]); + if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5]) { + $token->Value = str_replace($m[0], "#" . $value[0] . $value[2] . $value[4], $token->Value); + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssToken CSS token} represents a CSS comment. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentToken extends aCssToken +{ + /** + * Comment as Text. + * + * @var string + */ + public $Comment = ""; + + /** + * Set the properties of a comment token. + * + * @param string $comment Comment including comment delimiters + * @return void + */ + public function __construct($comment) + { + $this->Comment = $comment; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Comment; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing comments. + * + * Adds a {@link CssCommentToken} to the parser if a comment was found. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentParserPlugin extends aCssParserPlugin +{ + /** + * Stored buffer for restore. + * + * @var string + */ + private $restoreBuffer = ""; + + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("*", "/"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "*" && $previousChar === "/" && $state !== "T_COMMENT") { + $this->parser->pushState("T_COMMENT"); + $this->parser->setExclusive(__CLASS__); + $this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2); + } elseif ($char === "/" && $previousChar === "*" && $state === "T_COMMENT") { + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->parser->appendToken(new CssCommentToken("/*" . $this->parser->getAndClearBuffer())); + $this->parser->setBuffer($this->restoreBuffer); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesStartToken extends aCssAtBlockStartToken +{ + /** + * Media types of the @variables at-rule block. + * + * @var array + */ + public $MediaTypes = array(); + + /** + * Set the properties of a @variables at-rule token. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($mediaTypes = null) + { + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @variables at-rule block with including declarations. + * + * Found @variables at-rule blocks will add a {@link CssAtVariablesStartToken} and {@link CssAtVariablesEndToken} to the + * parser; including declarations as {@link CssAtVariablesDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_VARIABLES::PREPARE", "T_AT_VARIABLES", "T_AT_VARIABLES_DECLARATION"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @variables at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables") { + $this->parser->pushState("T_AT_VARIABLES::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @variables declarations + elseif ($char === "{" && $state === "T_AT_VARIABLES::PREPARE") { + $this->parser->setState("T_AT_VARIABLES"); + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes)); + } + // Start of @variables declaration + if ($char === ":" && $state === "T_AT_VARIABLES") { + $this->buffer = $this->parser->getAndClearBuffer(":"); + $this->parser->pushState("T_AT_VARIABLES_DECLARATION"); + } // Unterminated @variables declaration + elseif ($char === ":" && $state === "T_AT_VARIABLES_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @variables declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } // End of @variables declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + } // End of @variables at-rule block + elseif ($char === "}" && $state === "T_AT_VARIABLES") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtVariablesEndToken()); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesEndToken extends aCssAtBlockEndToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesDeclarationToken extends aCssDeclarationToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageStartToken extends aCssAtBlockStartToken +{ + /** + * Selector. + * + * @var string + */ + public $Selector = ""; + + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($selector = "") + { + $this->Selector = $selector; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@page" . ($this->Selector ? " " . $this->Selector : "") . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @page at-rule block with including declarations. + * + * Found @page at-rule blocks will add a {@link CssAtPageStartToken} and {@link CssAtPageEndToken} to the + * parser; including declarations as {@link CssAtPageDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_PAGE::SELECTOR", "T_AT_PAGE", "T_AT_PAGE_DECLARATION"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @page at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page") { + $this->parser->pushState("T_AT_PAGE::SELECTOR"); + $this->parser->clearBuffer(); + return $index + 5; + } // Start of @page declarations + elseif ($char === "{" && $state === "T_AT_PAGE::SELECTOR") { + $selector = $this->parser->getAndClearBuffer("{"); + $this->parser->setState("T_AT_PAGE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageStartToken($selector)); + } // Start of @page declaration + elseif ($char === ":" && $state === "T_AT_PAGE") { + $this->parser->pushState("T_AT_PAGE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_PAGE_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @page declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } // End of @page declaration + elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) == "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant)); + // -- + if ($char === "}") { + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageEndToken()); + } + $this->buffer = ""; + } // End of @page at-rule block + elseif ($char === "}" && $state === "T_AT_PAGE") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageEndToken()); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents the start of a @media at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaStartToken extends aCssAtBlockStartToken +{ + /** + * Sets the properties of the @media at-rule. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct(array $mediaTypes = array()) + { + $this->MediaTypes = $mediaTypes; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@media " . implode(",", $this->MediaTypes) . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @media at-rule block. + * + * Found @media at-rule blocks will add a {@link CssAtMediaStartToken} and {@link CssAtMediaEndToken} to the parser. + * This plugin will also set the the current media types using {@link CssParser::setMediaTypes()} and + * {@link CssParser::unsetMediaTypes()}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA::PREPARE", "T_AT_MEDIA"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media") { + $this->parser->pushState("T_AT_MEDIA::PREPARE"); + $this->parser->clearBuffer(); + return $index + 6; + } elseif ($char === "{" && $state === "T_AT_MEDIA::PREPARE") { + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->setMediaTypes($mediaTypes); + $this->parser->setState("T_AT_MEDIA"); + $this->parser->appendToken(new CssAtMediaStartToken($mediaTypes)); + } elseif ($char === "}" && $state === "T_AT_MEDIA") { + $this->parser->appendToken(new CssAtMediaEndToken()); + $this->parser->clearBuffer(); + $this->parser->unsetMediaTypes(); + $this->parser->popState(); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @media at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents the start of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesStartToken extends aCssAtBlockStartToken +{ + /** + * Name of the at-rule. + * + * @var string + */ + public $AtRuleName = "keyframes"; + /** + * Name + * + * @var string + */ + public $Name = ""; + + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($name, $atRuleName = null) + { + $this->Name = $name; + if (!is_null($atRuleName)) { + $this->AtRuleName = $atRuleName; + } + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@" . $this->AtRuleName . " \"" . $this->Name . "\"{"; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a ruleset of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + * @return void + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors) . "{"; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a ruleset of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a ruleset declaration of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @keyframes at-rule blocks, rulesets and declarations. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesParserPlugin extends aCssParserPlugin +{ + /** + * @var string Keyword + */ + private $atRuleName = ""; + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ",", ";"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @keyframes at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") { + $this->atRuleName = "keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @keyframes at-rule block (@-moz-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes") { + $this->atRuleName = "-moz-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 15; + } // Start of @keyframes at-rule block (@-webkit-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes") { + $this->atRuleName = "-webkit-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 18; + } // Start of @keyframes rulesets + elseif ($char === "{" && $state === "T_AT_KEYFRAMES::NAME") { + $name = $this->parser->getAndClearBuffer("{\"'"); + $this->parser->setState("T_AT_KEYFRAMES_RULESETS"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName)); + } + // Start of @keyframe ruleset and selectors + if ($char === "," && $state === "T_AT_KEYFRAMES_RULESETS") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } // Start of a @keyframes ruleset + elseif ($char === "{" && $state === "T_AT_KEYFRAMES_RULESETS") { + if ($this->parser->getBuffer() !== "") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + $this->parser->pushState("T_AT_KEYFRAMES_RULESET"); + $this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } // Start of @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET") { + $this->parser->pushState("T_AT_KEYFRAMES_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } // Unterminated @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @keyframes ruleset declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant)); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") { + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } // End of @keyframes ruleset + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESET") { + $this->parser->clearBuffer(); + + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + } // End of @keyframes rulesets + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESETS") { + $this->parser->clearBuffer(); + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesEndToken()); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a @import at-rule. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1.b1 (2001-02-22) + */ +class CssAtImportToken extends aCssToken +{ + /** + * Import path of the @import at-rule. + * + * @var string + */ + public $Import = ""; + /** + * Media types of the @import at-rule. + * + * @var array + */ + public $MediaTypes = array(); + + /** + * Set the properties of a @import at-rule token. + * + * @param string $import Import path + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($import, $mediaTypes) + { + $this->Import = $import; + $this->MediaTypes = $mediaTypes ? $mediaTypes : array(); + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@import \"" . $this->Import . "\"" . (count($this->MediaTypes) > 0 ? " " . implode(",", $this->MediaTypes) : "") . ";"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @import at-rule. + * + * If a @import at-rule was found this plugin will add a {@link CssAtImportToken} to the parser. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtImportParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", ",", "\n"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_IMPORT"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 7)) === "@import") { + $this->parser->pushState("T_AT_IMPORT"); + $this->parser->clearBuffer(); + return $index + 7; + } elseif (($char === ";" || $char === "\n") && $state === "T_AT_IMPORT") { + $this->buffer = $this->parser->getAndClearBuffer(";"); + $pos = false; + foreach (array(")", "\"", "'") as $needle) { + if (($pos = strrpos($this->buffer, $needle)) !== false) { + break; + } + } + $import = substr($this->buffer, 0, $pos + 1); + if (stripos($import, "url(") === 0) { + $import = substr($import, 4, -1); + } + $import = trim($import, " \t\n\r\0\x0B'\""); + $mediaTypes = array_filter(array_map("trim", explode(",", trim(substr($this->buffer, $pos + 1), " \t\n\r\0\x0B{")))); + if ($pos) { + $this->parser->appendToken(new CssAtImportToken($import, $mediaTypes)); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Invalid @import at-rule syntax", $this->parser->buffer)); + } + $this->parser->popState(); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceStartToken extends aCssAtBlockStartToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@font-face{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @font-face at-rule block with including declarations. + * + * Found @font-face at-rule blocks will add a {@link CssAtFontFaceStartToken} and {@link CssAtFontFaceEndToken} to the + * parser; including declarations as {@link CssAtFontFaceDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_FONT_FACE::PREPARE", "T_AT_FONT_FACE", "T_AT_FONT_FACE_DECLARATION"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @font-face at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face") { + $this->parser->pushState("T_AT_FONT_FACE::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @font-face declarations + elseif ($char === "{" && $state === "T_AT_FONT_FACE::PREPARE") { + $this->parser->setState("T_AT_FONT_FACE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtFontFaceStartToken()); + } // Start of @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE") { + $this->parser->pushState("T_AT_FONT_FACE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @font-face declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } // End of @font-face declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + // -- + if ($char === "}") { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->popState(); + } + } // End of @font-face at-rule block + elseif ($char === "}" && $state === "T_AT_FONT_FACE") { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->clearBuffer(); + $this->parser->popState(); + } else { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a @charset at-rule. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetToken extends aCssToken +{ + /** + * Charset of the @charset at-rule. + * + * @var string + */ + public $Charset = ""; + + /** + * Set the properties of @charset at-rule token. + * + * @param string $charset Charset of the @charset at-rule token + * @return void + */ + public function __construct($charset) + { + $this->Charset = $charset; + } + + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@charset " . $this->Charset . ";"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @charset at-rule. + * + * If a @charset at-rule was found this plugin will add a {@link CssAtCharsetToken} to the parser. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", "\n"); + } + + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_CHARSET"); + } + + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset") { + $this->parser->pushState("T_AT_CHARSET"); + $this->parser->clearBuffer(); + return $index + 8; + } elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") { + $charset = $this->parser->getAndClearBuffer(";"); + $this->parser->popState(); + $this->parser->appendToken(new CssAtCharsetToken($charset)); + } else { + return false; + } + return true; + } +} + +?> \ No newline at end of file diff --git a/inc/html.class.php b/inc/html.class.php index 9a70c0c2..a0cf95a7 100644 --- a/inc/html.class.php +++ b/inc/html.class.php @@ -98,6 +98,10 @@ class SP_Html // UTF8 Headers header("Content-Type: text/html; charset=UTF-8"); + // Cache Control + header("Cache-Control: public, no-cache, max-age=0, must-revalidate"); + header("Pragma: public; max-age=0"); + if (!is_null($err) && is_array($err) && count($err) > 0) { $data['errors'] = $err; } @@ -169,27 +173,10 @@ class SP_Html */ public static function setCss() { - $versionParameter = '?v=' . md5(implode(SP_Util::getVersion())); + $visualStyle = SP_Util::resultsCardsIsEnabled(); + $versionParameter = md5(implode(SP_Util::getVersion()).$visualStyle); - $cssProp = array( - array("href" => "css/reset.css", "media" => ""), - array("href" => "css/smoothness/jquery-ui.css", "media" => "screen"), - array("href" => "css/jquery.powertip.css", "media" => "screen"), - array("href" => "css/jquery.powertip-yellow.min.css", "media" => "screen"), - array("href" => "css/chosen.css", "media" => "screen"), - array("href" => "css/alertify.core.css", "media" => "screen"), - array("href" => "css/alertify.default.css", "media" => "screen"), - array("href" => "css/jquery.tagsinput.css", "media" => "screen"), - array("href" => "js/fancybox/jquery.fancybox.css", "media" => "screen"), - array("href" => "css/styles.css", "media" => "")); - - if ( ! SP_Util::resultsCardsIsEnabled() ){ - array_push($cssProp,array("href" => "css/search-grid.css", "media" => "")); - } - - foreach ($cssProp as $css) { - self::$htmlPage[] = ''; - } + self::$htmlPage[] = ''; } /** @@ -200,36 +187,7 @@ class SP_Html { $versionParameter = md5(implode(SP_Util::getVersion())); - $js_files = self::getJs(); - - foreach ($js_files as $js) { - self::$htmlPage[] = ''; - } - } - - /** - * @brief Devuelve un array con los archivos JS a incluir - * @return array con los archivos js y parámetros - */ - public static function getJs() - { - - $jsProp = array( - array("src" => "js/jquery.js", "params" => ""), - array("src" => "js/jquery.placeholder.js", "params" => ""), - array("src" => "js/jquery-ui.js", "params" => ""), - array("src" => "js/fancybox/jquery.fancybox.pack.js", "params" => ""), - array("src" => "js/jquery.powertip.min.js", "params" => ""), - array("src" => "js/chosen.jquery.min.js", "params" => ""), - array("src" => "js/alertify.js", "params" => ""), - array("src" => "js/jquery.fileDownload.js", "params" => ""), - array("src" => "js/jquery.filedrop.js", "params" => ""), - array("src" => "js/jquery.tagsinput.js", "params" => ""), - array("src" => "js/ZeroClipboard.min.js", "params" => ""), - array("src" => "js/functions.php", "params" => "") - ); - - return $jsProp; + self::$htmlPage[] = ''; } /** diff --git a/inc/init.php b/inc/init.php index d452e6ba..d8668f7f 100644 --- a/inc/init.php +++ b/inc/init.php @@ -173,7 +173,7 @@ class SP_Init continue; } - $params[] = $param . '=' . $value; + $params[] = SP_Html::sanitize($param) . '=' . SP_Html::sanitize($value); } header("Location: " . self::$WEBROOT . '/index.php?' . implode('&', $params)); @@ -231,19 +231,25 @@ class SP_Init self::$SUBURI = str_replace("\\", '/', substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(self::$SERVERROOT))); $scriptName = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + if (substr($scriptName, -1) == '/') { $scriptName .= 'index.php'; // Asegurar que suburi sigue las mismas reglas que scriptName if (substr(self::$SUBURI, -9) != 'index.php') { if (substr(self::$SUBURI, -1) != '/') { - self::$SUBURI = self::$SUBURI . '/'; + self::$SUBURI .= '/'; } - self::$SUBURI = self::$SUBURI . 'index.php'; + self::$SUBURI .= 'index.php'; } } - //self::$WEBROOT = substr($scriptName, 0, strlen($scriptName) - strlen(self::$SUBURI) + 1); - self::$WEBROOT = substr($scriptName, 0, strpos($scriptName, self::$SUBURI)); + $pos = strpos($scriptName, self::$SUBURI); + + if ($pos === false) { + $pos = strpos($scriptName, '?'); + } + + self::$WEBROOT = substr($scriptName, 0, $pos); if (self::$WEBROOT != '' and self::$WEBROOT[0] !== '/') { self::$WEBROOT = '/' . self::$WEBROOT; @@ -292,7 +298,7 @@ class SP_Init private static function checkInitSourceInclude() { $srcScript = pathinfo($_SERVER["SCRIPT_NAME"], PATHINFO_BASENAME); - $skipInit = array('functions.php'); + $skipInit = array('js.php', 'css.php'); return (in_array($srcScript, $skipInit)); } @@ -515,7 +521,13 @@ class SP_Init */ private static function getSessionLifeTime() { - return SP_Config::getValue('session_timeout', 60 * 60 * 24); + $timeout = SP_Common::parseParams('s', 'session_timeout', 0); + + if ($timeout === 0) { + $timeout = $_SESSION['session_timeout'] = SP_Config::getValue('session_timeout', 60 * 5); + } + + return $timeout; } /** @@ -526,9 +538,10 @@ class SP_Init { $inactiveTime = round(((time() - $_SESSION['LAST_ACTIVITY']) / 60), 2); $totalTime = round(((time() - $_SESSION['START_ACTIVITY']) / 60), 2); + $ulogin = SP_Common::parseParams('s', 'ulogin'); $message['action'] = _('Finalizar sesión'); - $message['text'][] = _('Usuario') . ": " . $_SESSION['ulogin']; + $message['text'][] = _('Usuario') . ": " . $ulogin; $message['text'][] = _('Tiempo inactivo') . ": " . $inactiveTime . " min."; $message['text'][] = _('Tiempo total') . ": " . $totalTime . " min."; diff --git a/inc/util.class.php b/inc/util.class.php index faddbc1d..9db5a85a 100644 --- a/inc/util.class.php +++ b/inc/util.class.php @@ -168,22 +168,13 @@ class SP_Util return in_array("ldap", get_loaded_extensions()); } - /** - * @brief Comprobar si el módulo CURL está instalado - * @return bool - */ - public static function curlIsAvailable() - { - return (function_exists('curl_init')); - } - /** * @brief Devuelve la versión de sysPass * @return string con la versión */ public static function getVersionString() { - return '1.1b'; + return '1.1-rc1'; } /** @@ -194,7 +185,7 @@ class SP_Util */ public static function checkUpdates() { - if (! self::curlIsAvailable() || !SP_Config::getValue('checkupdates')) { + if (!self::curlIsAvailable() || !SP_Config::getValue('checkupdates')) { return false; } @@ -257,6 +248,15 @@ class SP_Util } } + /** + * @brief Comprobar si el módulo CURL está instalado + * @return bool + */ + public static function curlIsAvailable() + { + return (function_exists('curl_init')); + } + /** * @brief Devuelve la versión de sysPass * @param bool $retBuild devolver el número de compilación @@ -264,7 +264,7 @@ class SP_Util */ public static function getVersion($retBuild = false) { - $build = 13; + $build = 14; $version = array(1, 1, 2); if ($retBuild) { @@ -322,7 +322,14 @@ class SP_Util */ public static function demoIsEnabled() { - return SP_Config::getValue('demo_enabled', false); + $enabled = SP_Common::parseParams('s', 'demo_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['demo_enabled'] = SP_Config::getValue('demo_enabled', false); + } + + return self::boolval($enabled); } /** @@ -331,7 +338,14 @@ class SP_Util */ public static function fileIsEnabled() { - return SP_Config::getValue('files_enabled', false); + $enabled = SP_Common::parseParams('s', 'files_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['files_enabled'] = SP_Config::getValue('files_enabled', false); + } + + return self::boolval($enabled); } /** @@ -340,7 +354,14 @@ class SP_Util */ public static function mailIsEnabled() { - return SP_Config::getValue('mail_enabled', false); + $enabled = SP_Common::parseParams('s', 'mail_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['mail_enabled'] = SP_Config::getValue('mail_enabled', false); + } + + return self::boolval($enabled); } /** @@ -349,7 +370,14 @@ class SP_Util */ public static function wikiIsEnabled() { - return SP_Config::getValue('wiki_enabled', false); + $enabled = SP_Common::parseParams('s', 'wiki_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['wiki_enabled'] = SP_Config::getValue('wiki_enabled', false); + } + + return self::boolval($enabled); } /** @@ -358,7 +386,14 @@ class SP_Util */ public static function mailrequestIsEnabled() { - return SP_Config::getValue('mail_requestsenabled', false); + $enabled = SP_Common::parseParams('s', 'mail_requestsenabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['mail_requestsenabled'] = SP_Config::getValue('mail_requestsenabled', false); + } + + return self::boolval($enabled); } /** @@ -367,7 +402,14 @@ class SP_Util */ public static function ldapIsEnabled() { - return SP_Config::getValue('ldap_enabled', false); + $enabled = SP_Common::parseParams('s', 'ldap_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['ldap_enabled'] = SP_Config::getValue('ldap_enabled', false); + } + + return self::boolval($enabled); } /** @@ -376,7 +418,14 @@ class SP_Util */ public static function logIsEnabled() { - return SP_Config::getValue('log_enabled', false); + $enabled = SP_Common::parseParams('s', 'log_enabled', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['log_enabled'] = SP_Config::getValue('log_enabled', false); + } + + return self::boolval($enabled); } /** @@ -385,7 +434,14 @@ class SP_Util */ public static function resultsCardsIsEnabled() { - return SP_Config::getValue('resultsascards', false); + $enabled = SP_Common::parseParams('s', 'resultsascards', 0); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($enabled === 0 || $reload === 1) { + $enabled = $_SESSION['resultsascards'] = SP_Config::getValue('resultsascards', false); + } + + return self::boolval($enabled); } /** @@ -394,7 +450,9 @@ class SP_Util */ public static function reload() { - if (!isset($_SESSION["reload"]) || $_SESSION["reload"] === 0) { + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($reload === 0) { $_SESSION["reload"] = 1; } } @@ -405,9 +463,174 @@ class SP_Util */ public static function checkReload() { - if (isset($_SESSION["reload"]) && $_SESSION["reload"] === 1) { - $_SESSION["reload"] = 0; - exit(""); + $reload = SP_Common::parseParams('s', 'reload', 0); + + if ($reload === 1) { + $_SESSION['reload'] = 0; + //exit(""); + exit(""); } } + + /** + * @brief Devolver al navegador archivos CSS y JS comprimidos + * @param string $type tipo de recurso a devolver + * @param array $files archivos a parsear + * @return none + * + * Método que devuelve un recurso CSS o JS comprimido. Si coincide el ETAG se + * devuelve el código HTTP/304 + */ + public static function getMinified($type, &$files) + { + $offset = 3600 * 24 * 30; + $nextCheck = time() + $offset; + $expire = 'Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', $nextCheck); + //$etag = md5(implode(SP_Util::getVersion())); + $etag = self::getEtag($files); + $etagMatch = self::getRequestHeaders('If-None-Match'); + $cacheControl = self::getRequestHeaders('Cache-Control'); + $pragma = self::getRequestHeaders('Pragma'); + + header('Etag: ' . $etag); + header("Cache-Control: public, max-age={$offset}, must-revalidate"); + header("Pragma: public; maxage={$offset}"); + header($expire); + + // Devolver código 304 si la versión es la misma y no se solicita refrescar + if ($etag == $etagMatch && !($cacheControl == 'no-cache' || $pragma == 'no-cache')) { + header($_SERVER["SERVER_PROTOCOL"] . " 304 Not Modified"); + exit; + } + + $path = SP_Init::$SERVERROOT . DIRECTORY_SEPARATOR; + + if ($type == 'js') { + header("Content-type: application/x-javascript; charset: UTF-8"); + } elseif ($type == 'css') { + header("Content-type: text/css; charset: UTF-8"); + } + + flush(); + ob_start('ob_gzhandler'); + + foreach ($files as $file) { + $filePath = $path . $file['href']; + + if ($file['min'] === true) { + echo '/* MINIFIED FILE: ' . $file['href'] . ' */' . PHP_EOL; + if ($type == 'js') { + echo self::jsCompress(file_get_contents($filePath)); + } elseif ($type == 'css') { + require_once EXTENSIONS_DIR . DIRECTORY_SEPARATOR . 'cssmin' . DIRECTORY_SEPARATOR . 'class.cssmin.php'; + echo CssMin::minify(file_get_contents($filePath)); + } + } else { + echo '/* FILE: ' . $file['href'] . ' */' . PHP_EOL; + echo file_get_contents($filePath); + } + + echo PHP_EOL; + } + + ob_end_flush(); + } + + /** + * @brief Calcular el hash MD5 de varios archivos + * @param array $files archivos a calcular + * @return string + */ + private static function getEtag(&$files) + { + $md5Sum = ''; + $path = SP_Init::$SERVERROOT . DIRECTORY_SEPARATOR; + + foreach ($files as $file) { + $md5Sum .= md5_file($path . $file['href']); + } + + return md5($md5Sum); + } + + /** + * @brief Devolver las cabeceras enviadas desde el cliente + * @param string $header nombre de la cabecera a devolver + * @return array + */ + public static function getRequestHeaders($header = '') + { + if (!function_exists('apache_request_headers')) { + function apache_request_headers() + { + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) == "HTTP_") { + $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5))))); + $headers[$key] = $value; + } else { + $headers[$key] = $value; + } + } + } + } else { + $headers = apache_request_headers(); + } + + if (!empty($header) && array_key_exists($header, $headers)) { + return $headers[$header]; + } elseif (!empty($header)) { + return false; + } + + return $headers; + } + + /** + * @brief Comprimir código javascript + * @param string $buffer código a comprimir + * @return string + */ + private static function jsCompress($buffer) + { + $regexReplace = array( + '#/\*[^*]*\*+([^/][^*]*\*+)*/#', + '#^[\s\t]*//.*$#m', + '#[\s\t]+$#m', + '#^[\s\t]+#m', + '#\s*//\s.*$#m' + ); + $buffer = preg_replace($regexReplace, '', $buffer); + // remove tabs, spaces, newlines, etc. + $buffer = str_replace(array("\r\n", "\r", "\n", "\t"), '', $buffer); + return $buffer; + } + + /** Checks a variable to see if it should be considered a boolean true or false. + * Also takes into account some text-based representations of true of false, + * such as 'false','N','yes','on','off', etc. + * @author Samuel Levy + * @param mixed $in The variable to check + * @param bool $strict If set to false, consider everything that is not false to + * be true. + * @return bool The boolean equivalent or null (if strict, and no exact equivalent) + */ + public static function boolval($in, $strict = false) + { + $out = null; + $in = (is_string($in) ? strtolower($in) : $in); + // if not strict, we only have to check if something is false + if (in_array($in, array('false', 'no', 'n', '0', 'off', false, 0), true) || !$in) { + $out = false; + } else if ($strict) { + // if strict, check the equivalent true values + if (in_array($in, array('true', 'yes', 'y', '1', 'on', true, 1), true)) { + $out = true; + } + } else { + // not strict? let the regular php bool check figure it out (will + // largely default to true) + $out = ($in ? true : false); + } + return $out; + } } \ No newline at end of file diff --git a/js/fancybox/jquery.fancybox.css b/js/fancybox/jquery.fancybox.css index b1d4c020..043f8f90 100644 --- a/js/fancybox/jquery.fancybox.css +++ b/js/fancybox/jquery.fancybox.css @@ -76,7 +76,7 @@ } #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span { - background-image: url('fancybox_sprite.png'); + background-image: url('../js/fancybox/fancybox_sprite.png'); } #fancybox-loading { @@ -94,7 +94,7 @@ #fancybox-loading div { width: 44px; height: 44px; - background: url('fancybox_loading.gif') center center no-repeat; + background: url('../js/fancybox/fancybox_loading.gif') center center no-repeat; } .fancybox-close { @@ -114,7 +114,7 @@ height: 100%; cursor: pointer; text-decoration: none; - background: transparent url('blank.gif'); /* helps IE */ + background: transparent url('../js/fancybox/blank.gif'); /* helps IE */ -webkit-tap-highlight-color: rgba(0,0,0,0); z-index: 8040; } @@ -172,7 +172,7 @@ overflow: hidden; display: none; z-index: 8010; - background: url('fancybox_overlay.png'); + background: url('../js/fancybox/fancybox_overlay.png'); } .fancybox-overlay-fixed { diff --git a/js/functions.js b/js/functions.js index 4defbbfd..bd6c1df9 100644 --- a/js/functions.js +++ b/js/functions.js @@ -10,7 +10,6 @@ var passToClip = 0; var windowAdjustSize = 350; var strPassword; -var charPassword; var minPasswordLength = 8; var baseScore = 0, score = 0; @@ -39,22 +38,30 @@ jQuery.extend(jQuery.fancybox.defaults, { padding: 0, helpers: {overlay: { css: { 'background': 'rgba(0, 0, 0, 0.1)'}}}, afterShow: function () { + "use strict"; + $('#fancyContainer').find('input:visible:first').focus(); } }); $(document).ready(function () { + "use strict"; + $("[title]").powerTip(powertipOptions); $('input, textarea').placeholder(); setContentSize(); setWindowAdjustSize(); }).ajaxComplete(function () { + "use strict"; + $("[title]").powerTip(powertipOptions); $('input, textarea').placeholder(); }); // Función para cargar el contenido de la acción del menú seleccionada function doAction(action, lastAction, id) { + "use strict"; + var data = {'action': action, 'lastAction': lastAction, 'id': id, isAjax: 1}; $('#content').fadeOut(function () { @@ -81,6 +88,8 @@ function doAction(action, lastAction, id) { // Función para establecer la altura del contenedor ajax function setContentSize() { + "use strict"; + // Calculate total height for full body resize var totalHeight = $("#content").height() + 100; //var totalWidth = $("#wrap").width(); @@ -90,9 +99,11 @@ function setContentSize() { // Función para establecer la variable de ajuste óptimo de altura function setWindowAdjustSize() { + "use strict"; + var browser = getBrowser(); - if ( browser == "MSIE" ){ + if (browser === "MSIE") { windowAdjustSize = 150; } //console.log(windowAdjustSize); @@ -100,12 +111,16 @@ function setWindowAdjustSize() { // Función para retornar el scroll a la posición inicial function scrollUp() { + "use strict"; + $('html, body').animate({ scrollTop: 0 }, 'slow'); } // Función para limpiar un formulario function clearSearch(clearStart) { - if ( clearStart === 1 ){ + "use strict"; + + if (clearStart === 1) { $('#frmSearch').find('input[name="start"]').val(0); return; } @@ -123,6 +138,8 @@ function clearSearch(clearStart) { // Funcion para crear un desplegable con opciones function mkChosen(options) { + "use strict"; + $('#' + options.id).chosen({ allow_single_deselect: true, placeholder_text_single: options.placeholder, @@ -133,15 +150,17 @@ function mkChosen(options) { // Función para la búsqueda de cuentas mediante filtros function accSearch(continous, event) { + "use strict"; + var lenTxtSearch = $('#txtSearch').val().length; - if ( typeof (event) != 'undefined' - && ((event.keyCode < 48 && event.keyCode != 13) || (event.keyCode > 105 && event.keyCode < 123)) ) return; + if (typeof (event) !== 'undefined' && ((event.keyCode < 48 && event.keyCode !== 13) || (event.keyCode > 105 && event.keyCode < 123))) { + return; + } - if (lenTxtSearch < 3 - && continous === 1 - && lenTxtSearch > window.lastlen - && event.keyCode != 13) return; + if (lenTxtSearch < 3 && continous === 1 && lenTxtSearch > window.lastlen && event.keyCode != 13) { + return; + } window.lastlen = lenTxtSearch; @@ -150,6 +169,8 @@ function accSearch(continous, event) { // Función para la búsqueda de cuentas mediante ordenación function searchSort(skey, start, nav) { + "use strict"; + if (typeof(skey) === "undefined" || typeof(start) === "undefined") return false; if (order.key > 0 && order.key != skey) { @@ -173,7 +194,9 @@ function searchSort(skey, start, nav) { } // Función para la búsqueda de cuentas -function doSearch(){ +function doSearch() { + "use strict"; + var frmData = $("#frmSearch").serialize(); $.fancybox.showLoading(); @@ -187,9 +210,9 @@ function doSearch(){ $('#resBuscar').html(response); $('#resBuscar').css("max-height", $('html').height() - windowAdjustSize); - if ( order.key ){ + if (order.key) { $('#search-sort-' + order.key).addClass('filterOn'); - if (order.dir == 0) { + if (order.dir === 0) { $('#search-sort-' + order.key).append(''); } else { $('#search-sort-' + order.key).append(''); @@ -208,6 +231,8 @@ function doSearch(){ // Función para navegar por el log de eventos function navLog(start, current) { + "use strict"; + if (typeof(start) === "undefined") return false; $.fancybox.showLoading(); @@ -233,8 +258,10 @@ function navLog(start, current) { // Función para ver la clave de una cuenta function viewPass(id, full, history) { + "use strict"; + // Comprobamos si la clave ha sido ya obtenida para copiar - if ( passToClip === 1 && full === 0){ + if (passToClip === 1 && full === 0) { return; } @@ -243,11 +270,11 @@ function viewPass(id, full, history) { url: APP_ROOT + '/ajax/ajax_viewpass.php', async: false, data: {'accountid': id, 'full': full, 'isHistory': history, 'isAjax': 1}, - success: function(data){ - if (data == "-1") { + success: function (data) { + if (data === "-1") { doLogout(); } else { - if ( full === 0 ){ + if (full === 0) { // Copiamos la clave en el objeto que tiene acceso al portapapeles $('#clip_pass_text').html(data); passToClip = 1; @@ -261,6 +288,8 @@ function viewPass(id, full, history) { // Función para obtener las variables de la URL y parsearlas a un array. function getUrlVars() { + "use strict"; + var vars = [], hash; var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { @@ -273,6 +302,8 @@ function getUrlVars() { // Función para autentificar usuarios function doLogin() { + "use strict"; + $.fancybox.showLoading(); var data = $('#frmLogin').serialize(); @@ -318,6 +349,8 @@ function doLogin() { // Función para salir de la sesión function doLogout() { + "use strict"; + var url = window.location.search; if (url.length > 0) { @@ -329,15 +362,19 @@ function doLogout() { // Función para comprobar si se ha salido de la sesión function checkLogout() { + "use strict"; + var session = getUrlVars()["session"]; - if (session == 0) { + if (session === 0) { resMsg("warn", LANG[2], '', "location.search = ''"); } } // Función para añadir/editar una cuenta function saveAccount(frm) { + "use strict"; + var data = $("#" + frm).serialize(); var id = $('input[name="accountid"]').val(); var savetyp = $('input[name="savetyp"]').val(); @@ -358,7 +395,7 @@ function saveAccount(frm) { if (status === 0) { resMsg("ok", description); - if (savetyp == 1) { + if (savetyp === 1) { $('#btnSave').hide(); } else { $('#btnSave').attr('disabled', true); @@ -386,35 +423,43 @@ function saveAccount(frm) { // Función para eliminar una cuenta function delAccount(id, action, sk) { + "use strict"; + var data = {accountid: id, savetyp: action, sk: sk}; var atext = '

' + LANG[3] + '

'; var url = '/ajax/ajax_accountSave.php'; alertify.confirm(atext, function (e) { if (e) { - sendAjax(data,url); + sendAjax(data, url); } }); } // Función para enviar una solicitud de modificación de cuenta function sendRequest() { + "use strict"; + var url = '/ajax/ajax_sendRequest.php'; var data = $('#frmRequestModify').serialize(); - sendAjax(data,url); + sendAjax(data, url); } // Función para guardar la configuración function configMgmt(action) { + "use strict"; + + var frm, url; + switch (action) { case "saveconfig": frm = 'frmConfig'; - var url = '/ajax/ajax_configSave.php'; + url = '/ajax/ajax_configSave.php'; break; case "savempwd": frm = 'frmCrypt'; - var url = '/ajax/ajax_configSave.php'; + url = '/ajax/ajax_configSave.php'; break; case "backup": frm = 'frmBackup'; @@ -422,7 +467,7 @@ function configMgmt(action) { break; case "migrate": frm = 'frmMigrate'; - var url = '/ajax/ajax_migrate.php'; + url = '/ajax/ajax_migrate.php'; break; default: return; @@ -435,6 +480,8 @@ function configMgmt(action) { // Función para descargar/ver archivos de una cuenta function downFile(id, sk, action) { + "use strict"; + var data = {'fileId': id, 'sk': sk, 'action': action}; if (action === 'view') { @@ -468,6 +515,8 @@ function downFile(id, sk, action) { // Función para obtener la lista de archivos de una cuenta function getFiles(id, isDel, sk) { + "use strict"; + var data = {'id': id, 'del': isDel, 'sk': sk}; $.ajax({ @@ -486,6 +535,8 @@ function getFiles(id, isDel, sk) { // Función para eliminar archivos de una cuenta function delFile(id, sk, accid) { + "use strict"; + var atext = '

' + LANG[15] + '

'; alertify.confirm(atext, function (e) { @@ -507,14 +558,16 @@ function delFile(id, sk, accid) { // Función para activar el Drag&Drop de archivos en las cuentas function dropFile(accountId, sk, maxsize) { + "use strict"; + var dropfiles = $('#dropzone'); var file_exts_ok = dropfiles.attr('data-files-ext').toLowerCase().split(','); dropfiles.filedrop({ fallback_id: 'inFile', - paramname: 'inFile', // $_FILES name + paramname: 'inFile', maxfiles: 5, - maxfilesize: maxsize, // in mb + maxfilesize: maxsize, allowedfileextensions: file_exts_ok, url: APP_ROOT + '/ajax/ajax_files.php', data: { @@ -526,7 +579,7 @@ function dropFile(accountId, sk, maxsize) { uploadFinished: function (i, file, response) { $.fancybox.hideLoading(); - var sk = $('input:[name=sk]').val(); + var sk = $('input[name="sk"]').val(); $("#downFiles").load(APP_ROOT + "/ajax/ajax_getFiles.php?id=" + accountId + "&del=1&isAjax=1&sk=" + sk); resMsg("ok", response); @@ -557,14 +610,16 @@ function dropFile(accountId, sk, maxsize) { // Función para activar el Drag&Drop de archivos en la importación de cuentas function importFile(sk) { + "use strict"; + var dropfiles = $('#dropzone'); - var file_exts_ok = ['csv','xml']; + var file_exts_ok = ['csv', 'xml']; dropfiles.filedrop({ fallback_id: 'inFile', - paramname: 'inFile', // $_FILES name + paramname: 'inFile', maxfiles: 1, - maxfilesize: 1, // in mb + maxfilesize: 1, allowedfileextensions: file_exts_ok, url: APP_ROOT + '/ajax/ajax_import.php', data: { @@ -613,6 +668,8 @@ function importFile(sk) { // Función para realizar una petición ajax function sendAjax(data, url) { + "use strict"; + $.fancybox.showLoading(); $.ajax({ @@ -660,6 +717,8 @@ function sendAjax(data, url) { // Función para mostrar el formulario para cambio de clave de usuario function usrUpdPass(id, usrlogin) { + "use strict"; + var data = {'usrid': id, 'usrlogin': usrlogin, 'isAjax': 1}; $.fancybox.showLoading(); @@ -681,6 +740,8 @@ function usrUpdPass(id, usrlogin) { // Función para mostrar los datos de un registro function appMgmtData(id, type, sk, active, view) { + "use strict"; + var data = {'id': id, 'type': type, 'sk': sk, 'active': active, 'view': view, 'isAjax': 1}; var url = APP_ROOT + '/ajax/ajax_appMgmtData.php'; @@ -706,11 +767,13 @@ function appMgmtData(id, type, sk, active, view) { // Función para editar los datos de un registro function appMgmtSave(frmId, isDel, id, type, sk, nextaction) { + "use strict"; + var data; var url = '/ajax/ajax_appMgmtSave.php'; if (isDel === 1) { - var data = {'id': id, 'type': type, 'action': 4, 'sk': sk, 'activeTab': frmId, 'onCloseAction': nextaction }; + data = {'id': id, 'type': type, 'action': 4, 'sk': sk, 'activeTab': frmId, 'onCloseAction': nextaction }; var atext = '

' + LANG[12] + '

'; alertify.confirm(atext, function (e) { @@ -720,13 +783,14 @@ function appMgmtSave(frmId, isDel, id, type, sk, nextaction) { }); } else { data = $("#" + frmId).serialize(); - sendAjax(data, url); } } // Función para verificar si existen actualizaciones function checkUpds() { + "use strict"; + $.ajax({ type: 'GET', dataType: 'html', @@ -743,6 +807,8 @@ function checkUpds() { // Función para limpiar el log de eventos function clearEventlog(sk) { + "use strict"; + var atext = '

' + LANG[20] + '

'; alertify.confirm(atext, function (e) { @@ -750,13 +816,15 @@ function clearEventlog(sk) { var data = { 'clear': 1, 'sk': sk, 'isAjax': 1}; var url = '/ajax/ajax_eventlog.php'; - sendAjax(data,url); + sendAjax(data, url); } }); } // Función para mostrar los botones de acción en los resultados de búsqueda function showOptional(me) { + "use strict"; + $(me).hide(); //$(me).parent().css('width','15em'); //var actions = $(me).closest('.account-actions').children('.actions-optional'); @@ -766,19 +834,23 @@ function showOptional(me) { // Función para obtener el tiempo actual en milisegundos function getTime() { - t = new Date(); + "use strict"; + + var t = new Date(); return t.getTime(); } // Función para generar claves aleatorias. // By Uzbekjon from http://jquery-howto.blogspot.com.es function password(length, special, fancy, dstId) { + "use strict"; + var iteration = 0; - var password = ""; + var genPassword = ''; var randomNumber; - if (special == undefined) { - var special = false; + if (typeof special === 'undefined') { + special = false; } while (iteration < length) { @@ -798,33 +870,34 @@ function password(length, special, fancy, dstId) { } } iteration++; - password += String.fromCharCode(randomNumber); + genPassword += String.fromCharCode(randomNumber); } - if (fancy == true) { - $("#viewPass").attr("title", password); + if (fancy === true) { + $("#viewPass").attr("title", genPassword); //alertify.alert('

' + LANG[6] + '

' + password + '

'); } else { - alertify.alert('

' + LANG[6] + '

' + password + '

'); + alertify.alert('

' + LANG[6] + '

' + genPassword + '

'); } if (dstId) { - checkPassLevel(password); - $('#' + dstId + ' input:password').val(password); + checkPassLevel(genPassword); + $('#' + dstId + ' input:password').val(genPassword); $('#' + dstId + ' #passLevel').show(500); } else { - checkPassLevel(password); - $('input:password').val(password); + checkPassLevel(genPassword); + $('input:password').val(genPassword); $('#passLevel').show(500); } //return password; } -// Funciónes para analizar al fortaleza de una clave +// Funciones para analizar al fortaleza de una clave // From http://net.tutsplus.com/tutorials/javascript-ajax/build-a-simple-password-strength-checker/ function checkPassLevel(password, dstId) { + "use strict"; + strPassword = password; - charPassword = strPassword.split(""); num.Excess = 0; num.Upper = 0; @@ -836,7 +909,7 @@ function checkPassLevel(password, dstId) { baseScore = 0; score = 0; - if (charPassword.length >= minPasswordLength) { + if (password.length >= minPasswordLength) { baseScore = 50; analyzeString(); calcComplexity(); @@ -852,20 +925,23 @@ function checkPassLevel(password, dstId) { } function analyzeString() { - for (i = 0; i < charPassword.length; i++) { - if (charPassword[i].match(/[A-Z]/g)) { + "use strict"; + + var chars = strPassword.split(''); + + for (var i = 0; i < strPassword.length; i++) { + if (chars[i].match(/[A-Z]/g)) { num.Upper++; } - if (charPassword[i].match(/[0-9]/g)) { + if (chars[i].match(/[0-9]/g)) { num.Numbers++; } - //if (charPassword[i].match(/(.*[!,@,#,$,%,^,&,*,?,_,~])/)) { - if (charPassword[i].match(/(.*[!,@,#,$,%,&,*,?,%,_])/)) { + if (chars[i].match(/(.*[!,@,#,$,%,&,*,?,%,_])/)) { num.Symbols++; } } - num.Excess = charPassword.length - minPasswordLength; + num.Excess = strPassword.length - minPasswordLength; if (num.Upper && num.Numbers && num.Symbols) { bonus.Combo = 25; @@ -885,10 +961,14 @@ function analyzeString() { } function calcComplexity() { + "use strict"; + score = baseScore + (num.Excess * bonus.Excess) + (num.Upper * bonus.Upper) + (num.Numbers * bonus.Numbers) + (num.Symbols * bonus.Symbols) + bonus.Combo + bonus.FlatLower + bonus.FlatNumber; } function outputResult(dstId) { + "use strict"; + var complexity, selector = '.passLevel'; if (dstId) { @@ -898,23 +978,18 @@ function outputResult(dstId) { complexity = $(selector); complexity.removeClass("weak good strong strongest"); - if (charPassword.length == 0) { - complexity.attr('title','').empty(); - } else if (charPassword.length < minPasswordLength) { - //complexity.html(LANG[11]).removeClass("good strong strongest").addClass("weak"); - complexity.attr('title',LANG[11]).addClass("weak"); + if (strPassword.length === 0) { + complexity.attr('title', '').empty(); + } else if (strPassword.length < minPasswordLength) { + complexity.attr('title', LANG[11]).addClass("weak"); } else if (score < 50) { - //complexity.html(LANG[9]).removeClass("good strong strongest").addClass("weak"); - complexity.attr('title',LANG[9]).addClass("weak"); + complexity.attr('title', LANG[9]).addClass("weak"); } else if (score >= 50 && score < 75) { - //complexity.html(LANG[8]).removeClass("weak strong strongest").addClass("good"); - complexity.attr('title',LANG[8]).addClass("good"); + complexity.attr('title', LANG[8]).addClass("good"); } else if (score >= 75 && score < 100) { - //complexity.html(LANG[7]).removeClass("weak good strongest").addClass("strong"); - complexity.attr('title',LANG[7]).addClass("strong"); + complexity.attr('title', LANG[7]).addClass("strong"); } else if (score >= 100) { - //complexity.html(LANG[10]).removeClass("weak good strong").addClass("strongest"); - complexity.attr('title',LANG[10]).addClass("strongest"); + complexity.attr('title', LANG[10]).addClass("strongest"); } $('.passLevel').powerTip(powertipOptions); @@ -922,7 +997,9 @@ function outputResult(dstId) { // Función para mostrar mensaje con alertify function resMsg(type, txt, url, action) { - if (typeof(url) !== "undefined") { + "use strict"; + + if (typeof url !== "undefined") { $.ajax({ url: url, type: 'get', dataType: 'html', async: false, success: function (data) { txt = data; }}); @@ -951,7 +1028,6 @@ function resMsg(type, txt, url, action) { case "nofancyerror": html = '

Oops...
' + LANG[1] + '
' + txt + '

'; return html; - break; default: alertify.set({ beforeCloseAction: action }); return alertify.error(txt); @@ -960,12 +1036,16 @@ function resMsg(type, txt, url, action) { $.fancybox(html, {afterLoad: function () { $('.fancybox-skin,.fancybox-outer,.fancybox-inner').css({'border-radius': '25px', '-moz-border-radius': '25px', '-webkit-border-radius': '25px'}); }, afterClose: function () { - if (typeof(action) !== "undefined") eval(action); + if (typeof action !== "undefined") { + eval(action); + } } }); } // Función para comprobar la conexión con LDAP function checkLdapConn() { + "use strict"; + var ldapServer = $('#frmConfig').find('[name=ldap_server]').val(); var ldapBase = $('#frmConfig').find('[name=ldap_base]').val(); var ldapGroup = $('#frmConfig').find('[name=ldap_group]').val(); @@ -974,25 +1054,29 @@ function checkLdapConn() { var sk = $('#frmConfig').find('[name=sk]').val(); var data = {'ldap_server': ldapServer, 'ldap_base': ldapBase, 'ldap_group': ldapGroup, 'ldap_binduser': ldapBindUser, 'ldap_bindpass': ldapBindPass, 'isAjax': 1, 'sk': sk}; - sendAjax(data,'/ajax/ajax_checkLdap.php'); + sendAjax(data, '/ajax/ajax_checkLdap.php'); } // Función para volver al login function goLogin() { - setTimeout(function () { location.href = "index.php";}, 2000); + "use strict"; + + setTimeout(function () { + location.href = "index.php"; + }, 2000); } // Función para obtener el navegador usado -function getBrowser() -{ - var version = -1; // Return value assumes failure. +function getBrowser() { + "use strict"; + + var browser; var ua = navigator.userAgent; - var re = new RegExp("(MSIE|Firefox)[ /]?([0-9]{1,}[\.0-9]{0,})", "i"); - if (re.exec(ua) != null) { - var browser = RegExp.$1; + var re = new RegExp("(MSIE|Firefox)[ /]?([0-9]{1,}[\.0-9]{0,})", "i"); + if (re.exec(ua) !== null) { + browser = RegExp.$1; //version = parseFloat( RegExp.$2 ); } return browser; - //return version; } \ No newline at end of file diff --git a/js/functions.php b/js/functions.php deleted file mode 100644 index 983d0b45..00000000 --- a/js/functions.php +++ /dev/null @@ -1,61 +0,0 @@ -. -* -*/ - -define('APP_ROOT', '..'); -require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'init.php'; - -$offset = 3600 * 24; -$expire = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; - -header("content-type: application/x-javascript"); -header($expire); -header('Cache-Control: max-age=3600, must-revalidate'); - -$arrJsLang = array(_('Error en la consulta'), - _('Ha ocurrido un error'), - _('Sesión finalizada'), - _('Borrar la cuenta?'), - _('Borrar el usuario?'), - _('Guarde la configuración para que sea efectiva'), - _('Clave Generada'), - _('Nivel alto'), - _('Nivel medio'), - _('Nivel bajo'), - _('Nivel muy alto'), - _('Utilizar al menos 8 caracteres'), - _('Borrar elemento?'), - _('Página no encontrada'), - _('Archivo no soportado para visualizar'), - _('Eliminar archivo?'), - _('Su navegador no soporta subir archivos con HTML5'), - _('Demasiados archivos'), - _('No es posible guardar el archivo.
Tamaño máximo:'), - _('Extensión no permitida'), - _('Vaciar el registro de eventos?')); - -echo "// i18n language array from PHP. Detected language: ".SP_Init::$LANG."\n"; -echo "var LANG = ['".implode("','",$arrJsLang)."']; \n"; -echo "var APP_ROOT = '".SP_Init::$WEBROOT."';\n\n"; -include_once 'functions.js'; \ No newline at end of file diff --git a/js/jquery.fileDownload.js b/js/jquery.fileDownload.js index 38a9c6b3..b9c1d20a 100644 --- a/js/jquery.fileDownload.js +++ b/js/jquery.fileDownload.js @@ -1,427 +1,434 @@ -/* -* jQuery File Download Plugin v1.4.2 -* -* http://www.johnculviner.com -* -* Copyright (c) 2013 - John Culviner -* -* Licensed under the MIT license: -* http://www.opensource.org/licenses/mit-license.php -*/ +/* + * jQuery File Download Plugin v1.4.2 + * + * http://www.johnculviner.com + * + * Copyright (c) 2013 - John Culviner + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ -(function($, window){ - // i'll just put them here to get evaluated on script load - var htmlSpecialCharsRegEx = /[<>&\r\n"']/gm; - var htmlSpecialCharsPlaceHolders = { - '<': 'lt;', - '>': 'gt;', - '&': 'amp;', - '\r': "#13;", - '\n': "#10;", - '"': 'quot;', - "'": 'apos;' /*single quotes just to be safe*/ - }; +(function ($, window) { + // i'll just put them here to get evaluated on script load + var htmlSpecialCharsRegEx = /[<>&\r\n"']/gm; + var htmlSpecialCharsPlaceHolders = { + '<': 'lt;', + '>': 'gt;', + '&': 'amp;', + '\r': "#13;", + '\n': "#10;", + '"': 'quot;', + "'": 'apos;' /*single quotes just to be safe*/ + }; -$.extend({ - // - //$.fileDownload('/path/to/url/', options) - // see directly below for possible 'options' - fileDownload: function (fileUrl, options) { + $.extend({ + // + //$.fileDownload('/path/to/url/', options) + // see directly below for possible 'options' + fileDownload: function (fileUrl, options) { - //provide some reasonable defaults to any unspecified options below - var settings = $.extend({ + //provide some reasonable defaults to any unspecified options below + var settings = $.extend({ - // - //Requires jQuery UI: provide a message to display to the user when the file download is being prepared before the browser's dialog appears - // - preparingMessageHtml: null, + // + //Requires jQuery UI: provide a message to display to the user when the file download is being prepared before the browser's dialog appears + // + preparingMessageHtml: null, - // - //Requires jQuery UI: provide a message to display to the user when a file download fails - // - failMessageHtml: null, + // + //Requires jQuery UI: provide a message to display to the user when a file download fails + // + failMessageHtml: null, - // - //the stock android browser straight up doesn't support file downloads initiated by a non GET: http://code.google.com/p/android/issues/detail?id=1780 - //specify a message here to display if a user tries with an android browser - //if jQuery UI is installed this will be a dialog, otherwise it will be an alert - // - androidPostUnsupportedMessageHtml: "Unfortunately your Android browser doesn't support this type of file download. Please try again with a different browser.", + // + //the stock android browser straight up doesn't support file downloads initiated by a non GET: http://code.google.com/p/android/issues/detail?id=1780 + //specify a message here to display if a user tries with an android browser + //if jQuery UI is installed this will be a dialog, otherwise it will be an alert + // + androidPostUnsupportedMessageHtml: "Unfortunately your Android browser doesn't support this type of file download. Please try again with a different browser.", - // - //Requires jQuery UI: options to pass into jQuery UI Dialog - // - dialogOptions: { modal: true }, + // + //Requires jQuery UI: options to pass into jQuery UI Dialog + // + dialogOptions: { modal: true }, - // - //a function to call while the dowload is being prepared before the browser's dialog appears - //Args: - // url - the original url attempted - // - prepareCallback: function (url) { }, + // + //a function to call while the dowload is being prepared before the browser's dialog appears + //Args: + // url - the original url attempted + // + prepareCallback: function (url) { + }, - // - //a function to call after a file download dialog/ribbon has appeared - //Args: - // url - the original url attempted - // - successCallback: function (url) { }, + // + //a function to call after a file download dialog/ribbon has appeared + //Args: + // url - the original url attempted + // + successCallback: function (url) { + }, - // - //a function to call after a file download dialog/ribbon has appeared - //Args: - // responseHtml - the html that came back in response to the file download. this won't necessarily come back depending on the browser. - // in less than IE9 a cross domain error occurs because 500+ errors cause a cross domain issue due to IE subbing out the - // server's error message with a "helpful" IE built in message - // url - the original url attempted - // - failCallback: function (responseHtml, url) { }, + // + //a function to call after a file download dialog/ribbon has appeared + //Args: + // responseHtml - the html that came back in response to the file download. this won't necessarily come back depending on the browser. + // in less than IE9 a cross domain error occurs because 500+ errors cause a cross domain issue due to IE subbing out the + // server's error message with a "helpful" IE built in message + // url - the original url attempted + // + failCallback: function (responseHtml, url) { + }, - // - // the HTTP method to use. Defaults to "GET". - // - httpMethod: "GET", + // + // the HTTP method to use. Defaults to "GET". + // + httpMethod: "GET", - // - // if specified will perform a "httpMethod" request to the specified 'fileUrl' using the specified data. - // data must be an object (which will be $.param serialized) or already a key=value param string - // - data: null, + // + // if specified will perform a "httpMethod" request to the specified 'fileUrl' using the specified data. + // data must be an object (which will be $.param serialized) or already a key=value param string + // + data: null, - // - //a period in milliseconds to poll to determine if a successful file download has occured or not - // - checkInterval: 100, + // + //a period in milliseconds to poll to determine if a successful file download has occured or not + // + checkInterval: 100, - // - //the cookie name to indicate if a file download has occured - // - cookieName: "fileDownload", + // + //the cookie name to indicate if a file download has occured + // + cookieName: "fileDownload", - // - //the cookie value for the above name to indicate that a file download has occured - // - cookieValue: "true", + // + //the cookie value for the above name to indicate that a file download has occured + // + cookieValue: "true", - // - //the cookie path for above name value pair - // - cookiePath: "/", + // + //the cookie path for above name value pair + // + cookiePath: "/", - // - //the title for the popup second window as a download is processing in the case of a mobile browser - // - popupWindowTitle: "Initiating file download...", + // + //the title for the popup second window as a download is processing in the case of a mobile browser + // + popupWindowTitle: "Initiating file download...", - // - //Functionality to encode HTML entities for a POST, need this if data is an object with properties whose values contains strings with quotation marks. - //HTML entity encoding is done by replacing all &,<,>,',",\r,\n characters. - //Note that some browsers will POST the string htmlentity-encoded whilst others will decode it before POSTing. - //It is recommended that on the server, htmlentity decoding is done irrespective. - // - encodeHTMLEntities: true - - }, options); + // + //Functionality to encode HTML entities for a POST, need this if data is an object with properties whose values contains strings with quotation marks. + //HTML entity encoding is done by replacing all &,<,>,',",\r,\n characters. + //Note that some browsers will POST the string htmlentity-encoded whilst others will decode it before POSTing. + //It is recommended that on the server, htmlentity decoding is done irrespective. + // + encodeHTMLEntities: true - var deferred = new $.Deferred(); + }, options); - //Setup mobile browser detection: Partial credit: http://detectmobilebrowser.com/ - var userAgent = (navigator.userAgent || navigator.vendor || window.opera).toLowerCase(); + var deferred = new $.Deferred(); - var isIos; //has full support of features in iOS 4.0+, uses a new window to accomplish this. - var isAndroid; //has full support of GET features in 4.0+ by using a new window. Non-GET is completely unsupported by the browser. See above for specifying a message. - var isOtherMobileBrowser; //there is no way to reliably guess here so all other mobile devices will GET and POST to the current window. + //Setup mobile browser detection: Partial credit: http://detectmobilebrowser.com/ + var userAgent = (navigator.userAgent || navigator.vendor || window.opera).toLowerCase(); - if (/ip(ad|hone|od)/.test(userAgent)) { + //has full support of features in iOS 4.0+, uses a new window to accomplish this. + var isIos; + //has full support of GET features in 4.0+ by using a new window. Non-GET is completely unsupported by the browser. See above for specifying a message. + var isAndroid; + //there is no way to reliably guess here so all other mobile devices will GET and POST to the current window. + var isOtherMobileBrowser; - isIos = true; + if (/ip(ad|hone|od)/.test(userAgent)) { - } else if (userAgent.indexOf('android') !== -1) { + isIos = true; - isAndroid = true; + } else if (userAgent.indexOf('android') !== -1) { - } else { + isAndroid = true; - isOtherMobileBrowser = /avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|playbook|silk|iemobile|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)); - - } - - var httpMethodUpper = settings.httpMethod.toUpperCase(); - - if (isAndroid && httpMethodUpper !== "GET") { - //the stock android browser straight up doesn't support file downloads initiated by non GET requests: http://code.google.com/p/android/issues/detail?id=1780 - - if ($().dialog) { - $("
").html(settings.androidPostUnsupportedMessageHtml).dialog(settings.dialogOptions); } else { - alert(settings.androidPostUnsupportedMessageHtml); + + isOtherMobileBrowser = /avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|playbook|silk|iemobile|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)); + } - return deferred.reject(); - } + var httpMethodUpper = settings.httpMethod.toUpperCase(); - var $preparingDialog = null; + if (isAndroid && httpMethodUpper !== "GET") { + //the stock android browser straight up doesn't support file downloads initiated by non GET requests: http://code.google.com/p/android/issues/detail?id=1780 - var internalCallbacks = { - - onPrepare: function (url) { - - //wire up a jquery dialog to display the preparing message if specified - if (settings.preparingMessageHtml) { - - $preparingDialog = $("
").html(settings.preparingMessageHtml).dialog(settings.dialogOptions); - - } else if (settings.prepareCallback) { - - settings.prepareCallback(url); - - } - - }, - - onSuccess: function (url) { - - //remove the perparing message if it was specified - if ($preparingDialog) { - $preparingDialog.dialog('close'); - }; - - settings.successCallback(url); - - deferred.resolve(url); - }, - - onFail: function (responseHtml, url) { - - //remove the perparing message if it was specified - if ($preparingDialog) { - $preparingDialog.dialog('close'); - }; - - //wire up a jquery dialog to display the fail message if specified - if (settings.failMessageHtml) { - $("
").html(settings.failMessageHtml).dialog(settings.dialogOptions); - } - - settings.failCallback(responseHtml, url); - - deferred.reject(responseHtml, url); - } - }; - - internalCallbacks.onPrepare(fileUrl); - - //make settings.data a param string if it exists and isn't already - if (settings.data !== null && typeof settings.data !== "string") { - settings.data = $.param(settings.data); - } - - - var $iframe, - downloadWindow, - formDoc, - $form; - - if (httpMethodUpper === "GET") { - - if (settings.data !== null) { - //need to merge any fileUrl params with the data object - - var qsStart = fileUrl.indexOf('?'); - - if (qsStart !== -1) { - //we have a querystring in the url - - if (fileUrl.substring(fileUrl.length - 1) !== "&") { - fileUrl = fileUrl + "&"; - } + if ($().dialog) { + $("
").html(settings.androidPostUnsupportedMessageHtml).dialog(settings.dialogOptions); } else { - - fileUrl = fileUrl + "?"; + alert(settings.androidPostUnsupportedMessageHtml); } - fileUrl = fileUrl + settings.data; + return deferred.reject(); } - if (isIos || isAndroid) { + var $preparingDialog = null; - downloadWindow = window.open(fileUrl); - downloadWindow.document.title = settings.popupWindowTitle; - window.focus(); + var internalCallbacks = { - } else if (isOtherMobileBrowser) { + onPrepare: function (url) { - window.location(fileUrl); + //wire up a jquery dialog to display the preparing message if specified + if (settings.preparingMessageHtml) { - } else { + $preparingDialog = $("
").html(settings.preparingMessageHtml).dialog(settings.dialogOptions); - //create a temporary iframe that is used to request the fileUrl as a GET request - $iframe = $("").appendTo("body"); - formDoc = getiframeDocument($iframe); + //create a temporary iframe that is used to request the fileUrl as a GET request + $iframe = $("").appendTo("body"); + formDoc = getiframeDocument($iframe); } + + formDoc.write("
" + formInnerHtml + "
" + settings.popupWindowTitle + ""); + $form = $(formDoc).find('form'); } - catch (err) { - //500 error less than IE9 - internalCallbacks.onFail('', fileUrl); + $form.submit(); + } - cleanUp(true); + + //check if the file download has completed every checkInterval ms + setTimeout(checkFileDownloadComplete, settings.checkInterval); + + + function checkFileDownloadComplete() { + + //has the cookie been written due to a file download occuring? + if (document.cookie.indexOf(settings.cookieName + "=" + settings.cookieValue) != -1) { + + //execute specified callback + internalCallbacks.onSuccess(fileUrl); + + //remove the cookie and iframe + document.cookie = settings.cookieName + "=; expires=" + new Date(1000).toUTCString() + "; path=" + settings.cookiePath; + + cleanUp(false); return; } - } + //has an error occured? + //if neither containers exist below then the file download is occuring on the current window + if (downloadWindow || $iframe) { - //keep checking... - setTimeout(checkFileDownloadComplete, settings.checkInterval); - } + //has an error occured? + try { - //gets an iframes document in a cross browser compatible manner - function getiframeDocument($iframe) { - var iframeDoc = $iframe[0].contentWindow || $iframe[0].contentDocument; - if (iframeDoc.document) { - iframeDoc = iframeDoc.document; - } - return iframeDoc; - } + var formDoc = downloadWindow ? downloadWindow.document : getiframeDocument($iframe); - function cleanUp(isFailure) { + if (formDoc && formDoc.body != null && formDoc.body.innerHTML.length) { - setTimeout(function() { + var isFailure = true; - if (downloadWindow) { + if ($form && $form.length) { + var $contents = $(formDoc.body).contents().first(); - if (isAndroid) { - downloadWindow.close(); - } + if ($contents.length && $contents[0] === $form[0]) { + isFailure = false; + } + } - if (isIos) { - downloadWindow.focus(); //ios safari bug doesn't allow a window to be closed unless it is focused - if (isFailure) { - downloadWindow.close(); + if (isFailure) { + internalCallbacks.onFail(formDoc.body.innerHTML, fileUrl); + + cleanUp(true); + + return; + } } } + catch (err) { + + //500 error less than IE9 + internalCallbacks.onFail('', fileUrl); + + cleanUp(true); + + return; + } } - - //iframe cleanup appears to randomly cause the download to fail - //not doing it seems better than failure... - //if ($iframe) { - // $iframe.remove(); - //} - }, 0); + + //keep checking... + setTimeout(checkFileDownloadComplete, settings.checkInterval); + } + + //gets an iframes document in a cross browser compatible manner + function getiframeDocument($iframe) { + var iframeDoc = $iframe[0].contentWindow || $iframe[0].contentDocument; + if (iframeDoc.document) { + iframeDoc = iframeDoc.document; + } + return iframeDoc; + } + + function cleanUp(isFailure) { + + setTimeout(function () { + + if (downloadWindow) { + + if (isAndroid) { + downloadWindow.close(); + } + + if (isIos) { + //ios safari bug doesn't allow a window to be closed unless it is focused + downloadWindow.focus(); + if (isFailure) { + downloadWindow.close(); + } + } + } + + //iframe cleanup appears to randomly cause the download to fail + //not doing it seems better than failure... + //if ($iframe) { + // $iframe.remove(); + //} + + }, 0); + } + + + function htmlSpecialCharsEntityEncode(str) { + return str.replace(htmlSpecialCharsRegEx, function (match) { + return '&' + htmlSpecialCharsPlaceHolders[match]; + }); + } + + return deferred.promise(); } - - - function htmlSpecialCharsEntityEncode(str) { - return str.replace(htmlSpecialCharsRegEx, function(match) { - return '&' + htmlSpecialCharsPlaceHolders[match]; - }); - } - - return deferred.promise(); - } -}); + }); })(jQuery, this); diff --git a/js/jquery.filedrop.js b/js/jquery.filedrop.js index f1440142..c357e3d5 100644 --- a/js/jquery.filedrop.js +++ b/js/jquery.filedrop.js @@ -25,531 +25,545 @@ * See README at project homepage * */ -;(function($) { +(function ($) { - jQuery.event.props.push("dataTransfer"); + jQuery.event.props.push("dataTransfer"); - var default_opts = { - fallback_id: '', - url: '', - refresh: 1000, - paramname: 'userfile', - requestType: 'POST', // just in case you want to use another HTTP verb - allowedfileextensions:[], - allowedfiletypes:[], - maxfiles: 25, // Ignored if queuefiles is set > 0 - maxfilesize: 1, // MB file size limit - queuefiles: 0, // Max files before queueing (for large volume uploads) - queuewait: 200, // Queue wait time if full - data: {}, - headers: {}, - drop: empty, - dragStart: empty, - dragEnter: empty, - dragOver: empty, - dragLeave: empty, - docEnter: empty, - docOver: empty, - docLeave: empty, - beforeEach: empty, - afterAll: empty, - rename: empty, - error: function(err, file, i, status) { - alert(err); - }, - uploadStarted: empty, - uploadFinished: empty, - progressUpdated: empty, - globalProgressUpdated: empty, - speedUpdated: empty - }, - errors = ["BrowserNotSupported", "TooManyFiles", "FileTooLarge", "FileTypeNotAllowed", "NotFound", "NotReadable", "AbortError", "ReadError", "FileExtensionNotAllowed"]; + var default_opts = { + fallback_id: '', + url: '', + refresh: 1000, + paramname: 'userfile', + // just in case you want to use another HTTP verb + requestType: 'POST', + allowedfileextensions: [], + allowedfiletypes: [], + // Ignored if queuefiles is set > 0 + maxfiles: 25, + // MB file size limit + maxfilesize: 1, + // Max files before queueing (for large volume uploads) + queuefiles: 0, + // Queue wait time if full + queuewait: 200, + data: {}, + headers: {}, + drop: empty, + dragStart: empty, + dragEnter: empty, + dragOver: empty, + dragLeave: empty, + docEnter: empty, + docOver: empty, + docLeave: empty, + beforeEach: empty, + afterAll: empty, + rename: empty, + error: function (err, file, i, status) { + alert(err); + }, + uploadStarted: empty, + uploadFinished: empty, + progressUpdated: empty, + globalProgressUpdated: empty, + speedUpdated: empty + }, + errors = ["BrowserNotSupported", "TooManyFiles", "FileTooLarge", "FileTypeNotAllowed", "NotFound", "NotReadable", "AbortError", "ReadError", "FileExtensionNotAllowed"]; - $.fn.filedrop = function(options) { - var opts = $.extend({}, default_opts, options), - global_progress = [], - doc_leave_timer, stop_loop = false, - files_count = 0, - files; + $.fn.filedrop = function (options) { + var opts = $.extend({}, default_opts, options), + global_progress = [], + doc_leave_timer, stop_loop = false, + files_count = 0, + files; - $('#' + opts.fallback_id).css({ - display: 'none', - width: 0, - height: 0 - }); - - this.on('drop', drop).on('dragstart', opts.dragStart).on('dragenter', dragEnter).on('dragover', dragOver).on('dragleave', dragLeave); - $(document).on('drop', docDrop).on('dragenter', docEnter).on('dragover', docOver).on('dragleave', docLeave); - - this.on('click', function(e){ - $('#' + opts.fallback_id).trigger(e); - }); - - $('#' + opts.fallback_id).change(function(e) { - opts.drop(e); - files = e.target.files; - files_count = files.length; - upload(); - }); - - function drop(e) { - if( opts.drop.call(this, e) === false ) return false; - if(!e.dataTransfer) - return; - files = e.dataTransfer.files; - if (files === null || files === undefined || files.length === 0) { - opts.error(errors[0]); - return false; - } - files_count = files.length; - upload(); - e.preventDefault(); - return false; - } - - function getBuilder(filename, filedata, mime, boundary) { - var dashdash = '--', - crlf = '\r\n', - builder = '', - paramname = opts.paramname; - - if (opts.data) { - var params = $.param(opts.data).replace(/\+/g, '%20').split(/&/); - - $.each(params, function() { - var pair = this.split("=", 2), - name = decodeURIComponent(pair[0]), - val = decodeURIComponent(pair[1]); - - if (pair.length !== 2) { - return; - } - - builder += dashdash; - builder += boundary; - builder += crlf; - builder += 'Content-Disposition: form-data; name="' + name + '"'; - builder += crlf; - builder += crlf; - builder += val; - builder += crlf; + $('#' + opts.fallback_id).css({ + display: 'none', + width: 0, + height: 0 }); - } - if (jQuery.isFunction(paramname)){ - paramname = paramname(filename); - } + this.on('drop', drop).on('dragstart', opts.dragStart).on('dragenter', dragEnter).on('dragover', dragOver).on('dragleave', dragLeave); + $(document).on('drop', docDrop).on('dragenter', docEnter).on('dragover', docOver).on('dragleave', docLeave); - builder += dashdash; - builder += boundary; - builder += crlf; - builder += 'Content-Disposition: form-data; name="' + (paramname||"") + '"'; - builder += '; filename="' + filename + '"'; - builder += crlf; + this.on('click', function (e) { + $('#' + opts.fallback_id).trigger(e); + }); - builder += 'Content-Type: ' + mime; - builder += crlf; - builder += crlf; + $('#' + opts.fallback_id).change(function (e) { + opts.drop(e); + files = e.target.files; + files_count = files.length; + upload(); + }); - builder += filedata; - builder += crlf; - - builder += dashdash; - builder += boundary; - builder += dashdash; - builder += crlf; - return builder; - } - - function progress(e) { - if (e.lengthComputable) { - var percentage = Math.round((e.loaded * 100) / e.total); - if (this.currentProgress !== percentage) { - - this.currentProgress = percentage; - opts.progressUpdated(this.index, this.file, this.currentProgress); - - global_progress[this.global_progress_index] = this.currentProgress; - globalProgress(); - - var elapsed = new Date().getTime(); - var diffTime = elapsed - this.currentStart; - if (diffTime >= opts.refresh) { - var diffData = e.loaded - this.startData; - var speed = diffData / diffTime; // KB per second - opts.speedUpdated(this.index, this.file, speed); - this.startData = e.loaded; - this.currentStart = elapsed; - } - } - } - } - - function globalProgress() { - if (global_progress.length === 0) { - return; - } - - var total = 0, index; - for (index in global_progress) { - if(global_progress.hasOwnProperty(index)) { - total = total + global_progress[index]; - } - } - - opts.globalProgressUpdated(Math.round(total / global_progress.length)); - } - - // Respond to an upload - function upload() { - stop_loop = false; - - if (!files) { - opts.error(errors[0]); - return false; - } - - if (opts.allowedfiletypes.push && opts.allowedfiletypes.length) { - for(var fileIndex = files.length;fileIndex--;) { - if(!files[fileIndex].type || $.inArray(files[fileIndex].type, opts.allowedfiletypes) < 0) { - opts.error(errors[3], files[fileIndex]); - return false; - } - } - } - - if (opts.allowedfileextensions.push && opts.allowedfileextensions.length) { - for(var fileIndex = files.length;fileIndex--;) { - var allowedextension = false; - for (i=0;i opts.maxfiles && opts.queuefiles === 0) { - opts.error(errors[1]); - return false; - } - - // Define queues to manage upload process - var workQueue = []; - var processingQueue = []; - var doneQueue = []; - - // Add everything to the workQueue - for (var i = 0; i < files_count; i++) { - workQueue.push(i); - } - - // Helper function to enable pause of processing to wait - // for in process queue to complete - var pause = function(timeout) { - setTimeout(process, timeout); - return; - }; - - // Process an upload, recursive - var process = function() { - - var fileIndex; - - if (stop_loop) { - return false; - } - - // Check to see if are in queue mode - if (opts.queuefiles > 0 && processingQueue.length >= opts.queuefiles) { - return pause(opts.queuewait); - } else { - // Take first thing off work queue - fileIndex = workQueue[0]; - workQueue.splice(0, 1); - - // Add to processing queue - processingQueue.push(fileIndex); - } - - try { - if (beforeEach(files[fileIndex]) !== false) { - if (fileIndex === files_count) { - return; + if (!e.dataTransfer) { + return; } - var reader = new FileReader(), - max_file_size = 1048576 * opts.maxfilesize; + files = e.dataTransfer.files; + if (files === null || files === undefined || files.length === 0) { + opts.error(errors[0]); + return false; + } + files_count = files.length; + upload(); + e.preventDefault(); + return false; + } - reader.index = fileIndex; - if (files[fileIndex].size > max_file_size) { - opts.error(errors[2], files[fileIndex], fileIndex); - // Remove from queue - processingQueue.forEach(function(value, key) { - if (value === fileIndex) { - processingQueue.splice(key, 1); + function getBuilder(filename, filedata, mime, boundary) { + var dashdash = '--', + crlf = '\r\n', + builder = '', + paramname = opts.paramname; + + if (opts.data) { + var params = $.param(opts.data).replace(/\+/g, '%20').split(/&/); + + $.each(params, function () { + var pair = this.split("=", 2), + name = decodeURIComponent(pair[0]), + val = decodeURIComponent(pair[1]); + + if (pair.length !== 2) { + return; + } + + builder += dashdash; + builder += boundary; + builder += crlf; + builder += 'Content-Disposition: form-data; name="' + name + '"'; + builder += crlf; + builder += crlf; + builder += val; + builder += crlf; + }); + } + + if (jQuery.isFunction(paramname)) { + paramname = paramname(filename); + } + + builder += dashdash; + builder += boundary; + builder += crlf; + builder += 'Content-Disposition: form-data; name="' + (paramname || "") + '"'; + builder += '; filename="' + filename + '"'; + builder += crlf; + + builder += 'Content-Type: ' + mime; + builder += crlf; + builder += crlf; + + builder += filedata; + builder += crlf; + + builder += dashdash; + builder += boundary; + builder += dashdash; + builder += crlf; + return builder; + } + + function progress(e) { + if (e.lengthComputable) { + var percentage = Math.round((e.loaded * 100) / e.total); + if (this.currentProgress !== percentage) { + + this.currentProgress = percentage; + opts.progressUpdated(this.index, this.file, this.currentProgress); + + global_progress[this.global_progress_index] = this.currentProgress; + globalProgress(); + + var elapsed = new Date().getTime(); + var diffTime = elapsed - this.currentStart; + if (diffTime >= opts.refresh) { + var diffData = e.loaded - this.startData; + var speed = diffData / diffTime; // KB per second + opts.speedUpdated(this.index, this.file, speed); + this.startData = e.loaded; + this.currentStart = elapsed; + } } - }); - filesRejected++; - return true; + } + } + + function globalProgress() { + if (global_progress.length === 0) { + return; } - reader.onerror = function(e) { - switch(e.target.error.code) { - case e.target.error.NOT_FOUND_ERR: - opts.error(errors[4]); + var total = 0, index; + for (index in global_progress) { + if (global_progress.hasOwnProperty(index)) { + total = total + global_progress[index]; + } + } + + opts.globalProgressUpdated(Math.round(total / global_progress.length)); + } + + // Respond to an upload + function upload() { + stop_loop = false; + + if (!files) { + opts.error(errors[0]); + return false; + } + + if (opts.allowedfiletypes.push && opts.allowedfiletypes.length) { + for (var fileIndex = files.length; fileIndex--;) { + if (!files[fileIndex].type || $.inArray(files[fileIndex].type, opts.allowedfiletypes) < 0) { + opts.error(errors[3], files[fileIndex]); return false; - case e.target.error.NOT_READABLE_ERR: - opts.error(errors[5]); - return false; - case e.target.error.ABORT_ERR: - opts.error(errors[6]); - return false; - default: - opts.error(errors[7]); + } + } + } + + if (opts.allowedfileextensions.push && opts.allowedfileextensions.length) { + for (var fileIndex = files.length; fileIndex--;) { + var allowedextension = false; + for (i = 0; i < opts.allowedfileextensions.length; i++) { + if (files[fileIndex].name.substr(files[fileIndex].name.length - opts.allowedfileextensions[i].length) == opts.allowedfileextensions[i]) { + allowedextension = true; + } + } + if (!allowedextension) { + opts.error(errors[8], files[fileIndex]); return false; + } + } + } + + var filesDone = 0, + filesRejected = 0; + + if (files_count > opts.maxfiles && opts.queuefiles === 0) { + opts.error(errors[1]); + return false; + } + + // Define queues to manage upload process + var workQueue = []; + var processingQueue = []; + var doneQueue = []; + + // Add everything to the workQueue + for (var i = 0; i < files_count; i++) { + workQueue.push(i); + } + + // Helper function to enable pause of processing to wait + // for in process queue to complete + var pause = function (timeout) { + setTimeout(process, timeout); + return; + }; + + // Process an upload, recursive + var process = function () { + + var fileIndex; + + if (stop_loop) { + return false; + } + + // Check to see if are in queue mode + if (opts.queuefiles > 0 && processingQueue.length >= opts.queuefiles) { + return pause(opts.queuewait); + } else { + // Take first thing off work queue + fileIndex = workQueue[0]; + workQueue.splice(0, 1); + + // Add to processing queue + processingQueue.push(fileIndex); + } + + try { + if (beforeEach(files[fileIndex]) !== false) { + if (fileIndex === files_count) { + return; + } + var reader = new FileReader(), + max_file_size = 1048576 * opts.maxfilesize; + + reader.index = fileIndex; + if (files[fileIndex].size > max_file_size) { + opts.error(errors[2], files[fileIndex], fileIndex); + // Remove from queue + processingQueue.forEach(function (value, key) { + if (value === fileIndex) { + processingQueue.splice(key, 1); + } + }); + filesRejected++; + return true; + } + + reader.onerror = function (e) { + switch (e.target.error.code) { + case e.target.error.NOT_FOUND_ERR: + opts.error(errors[4]); + return false; + case e.target.error.NOT_READABLE_ERR: + opts.error(errors[5]); + return false; + case e.target.error.ABORT_ERR: + opts.error(errors[6]); + return false; + default: + opts.error(errors[7]); + return false; + } + }; + + reader.onloadend = !opts.beforeSend ? send : function (e) { + opts.beforeSend(files[fileIndex], fileIndex, function () { + send(e); + }); + }; + + reader.readAsDataURL(files[fileIndex]); + + } else { + filesRejected++; + } + } catch (err) { + // Remove from queue + processingQueue.forEach(function (value, key) { + if (value === fileIndex) { + processingQueue.splice(key, 1); + } + }); + opts.error(errors[0]); + return false; + } + + // If we still have work to do, + if (workQueue.length > 0) { + process(); + } + }; + + var send = function (e) { + + var fileIndex = (e.srcElement || e.target).index; + + // Sometimes the index is not attached to the + // event object. Find it by size. Hack for sure. + if (e.target.index === undefined) { + e.target.index = getIndexBySize(e.total); + } + + var xhr = new XMLHttpRequest(), + upload = xhr.upload, + file = files[e.target.index], + index = e.target.index, + start_time = new Date().getTime(), + boundary = '------multipartformboundary' + (new Date()).getTime(), + global_progress_index = global_progress.length, + builder, + newName = rename(file.name), + mime = file.type; + + if (opts.withCredentials) { + xhr.withCredentials = opts.withCredentials; + } + + var data = atob(e.target.result.split(',')[1]); + if (typeof newName === "string") { + builder = getBuilder(newName, data, mime, boundary); + } else { + builder = getBuilder(file.name, data, mime, boundary); + } + + upload.index = index; + upload.file = file; + upload.downloadStartTime = start_time; + upload.currentStart = start_time; + upload.currentProgress = 0; + upload.global_progress_index = global_progress_index; + upload.startData = 0; + upload.addEventListener("progress", progress, false); + + // Allow url to be a method + if (jQuery.isFunction(opts.url)) { + xhr.open(opts.requestType, opts.url(), true); + } else { + xhr.open(opts.requestType, opts.url, true); + } + + xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // Add headers + $.each(opts.headers, function (k, v) { + xhr.setRequestHeader(k, v); + }); + + xhr.sendAsBinary(builder); + + global_progress[global_progress_index] = 0; + globalProgress(); + + opts.uploadStarted(index, file, files_count); + + xhr.onload = function () { + var serverResponse = null; + + if (xhr.responseText) { + try { + serverResponse = jQuery.parseJSON(xhr.responseText); + } + catch (e) { + serverResponse = xhr.responseText; + } + } + + var now = new Date().getTime(), + timeDiff = now - start_time, + result = opts.uploadFinished(index, file, serverResponse, timeDiff, xhr); + filesDone++; + + // Remove from processing queue + processingQueue.forEach(function (value, key) { + if (value === fileIndex) { + processingQueue.splice(key, 1); + } + }); + + // Add to donequeue + doneQueue.push(fileIndex); + + // Make sure the global progress is updated + global_progress[global_progress_index] = 100; + globalProgress(); + + if (filesDone === (files_count - filesRejected)) { + afterAll(); + } + if (result === false) { + stop_loop = true; + } + + + // Pass any errors to the error option + if (xhr.status < 200 || xhr.status > 299) { + opts.error(xhr.statusText, file, fileIndex, xhr.status); + } }; }; - reader.onloadend = !opts.beforeSend ? send : function (e) { - opts.beforeSend(files[fileIndex], fileIndex, function () { send(e); }); - }; - - reader.readAsDataURL(files[fileIndex]); - - } else { - filesRejected++; - } - } catch (err) { - // Remove from queue - processingQueue.forEach(function(value, key) { - if (value === fileIndex) { - processingQueue.splice(key, 1); - } - }); - opts.error(errors[0]); - return false; + // Initiate the processing loop + process(); } - // If we still have work to do, - if (workQueue.length > 0) { - process(); - } - }; - - var send = function(e) { - - var fileIndex = (e.srcElement || e.target).index; - - // Sometimes the index is not attached to the - // event object. Find it by size. Hack for sure. - if (e.target.index === undefined) { - e.target.index = getIndexBySize(e.total); - } - - var xhr = new XMLHttpRequest(), - upload = xhr.upload, - file = files[e.target.index], - index = e.target.index, - start_time = new Date().getTime(), - boundary = '------multipartformboundary' + (new Date()).getTime(), - global_progress_index = global_progress.length, - builder, - newName = rename(file.name), - mime = file.type; - - if (opts.withCredentials) { - xhr.withCredentials = opts.withCredentials; - } - - var data = atob(e.target.result.split(',')[1]); - if (typeof newName === "string") { - builder = getBuilder(newName, data, mime, boundary); - } else { - builder = getBuilder(file.name, data, mime, boundary); - } - - upload.index = index; - upload.file = file; - upload.downloadStartTime = start_time; - upload.currentStart = start_time; - upload.currentProgress = 0; - upload.global_progress_index = global_progress_index; - upload.startData = 0; - upload.addEventListener("progress", progress, false); - - // Allow url to be a method - if (jQuery.isFunction(opts.url)) { - xhr.open(opts.requestType, opts.url(), true); - } else { - xhr.open(opts.requestType, opts.url, true); - } - - xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary); - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - - // Add headers - $.each(opts.headers, function(k, v) { - xhr.setRequestHeader(k, v); - }); - - xhr.sendAsBinary(builder); - - global_progress[global_progress_index] = 0; - globalProgress(); - - opts.uploadStarted(index, file, files_count); - - xhr.onload = function() { - var serverResponse = null; - - if (xhr.responseText) { - try { - serverResponse = jQuery.parseJSON(xhr.responseText); - } - catch (e) { - serverResponse = xhr.responseText; - } + function getIndexBySize(size) { + for (var i = 0; i < files_count; i++) { + if (files[i].size === size) { + return i; + } } - var now = new Date().getTime(), - timeDiff = now - start_time, - result = opts.uploadFinished(index, file, serverResponse, timeDiff, xhr); - filesDone++; - - // Remove from processing queue - processingQueue.forEach(function(value, key) { - if (value === fileIndex) { - processingQueue.splice(key, 1); - } - }); - - // Add to donequeue - doneQueue.push(fileIndex); - - // Make sure the global progress is updated - global_progress[global_progress_index] = 100; - globalProgress(); - - if (filesDone === (files_count - filesRejected)) { - afterAll(); - } - if (result === false) { - stop_loop = true; - } - - - // Pass any errors to the error option - if (xhr.status < 200 || xhr.status > 299) { - opts.error(xhr.statusText, file, fileIndex, xhr.status); - } - }; - }; - - // Initiate the processing loop - process(); - } - - function getIndexBySize(size) { - for (var i = 0; i < files_count; i++) { - if (files[i].size === size) { - return i; + return undefined; } - } - return undefined; - } + function rename(name) { + return opts.rename(name); + } - function rename(name) { - return opts.rename(name); - } + function beforeEach(file) { + return opts.beforeEach(file); + } - function beforeEach(file) { - return opts.beforeEach(file); - } + function afterAll() { + return opts.afterAll(); + } - function afterAll() { - return opts.afterAll(); - } + function dragEnter(e) { + clearTimeout(doc_leave_timer); + e.preventDefault(); + opts.dragEnter.call(this, e); + } - function dragEnter(e) { - clearTimeout(doc_leave_timer); - e.preventDefault(); - opts.dragEnter.call(this, e); - } + function dragOver(e) { + clearTimeout(doc_leave_timer); + e.preventDefault(); + opts.docOver.call(this, e); + opts.dragOver.call(this, e); + } - function dragOver(e) { - clearTimeout(doc_leave_timer); - e.preventDefault(); - opts.docOver.call(this, e); - opts.dragOver.call(this, e); - } + function dragLeave(e) { + clearTimeout(doc_leave_timer); + opts.dragLeave.call(this, e); + e.stopPropagation(); + } - function dragLeave(e) { - clearTimeout(doc_leave_timer); - opts.dragLeave.call(this, e); - e.stopPropagation(); - } + function docDrop(e) { + e.preventDefault(); + opts.docLeave.call(this, e); + return false; + } - function docDrop(e) { - e.preventDefault(); - opts.docLeave.call(this, e); - return false; - } + function docEnter(e) { + clearTimeout(doc_leave_timer); + e.preventDefault(); + opts.docEnter.call(this, e); + return false; + } - function docEnter(e) { - clearTimeout(doc_leave_timer); - e.preventDefault(); - opts.docEnter.call(this, e); - return false; - } + function docOver(e) { + clearTimeout(doc_leave_timer); + e.preventDefault(); + opts.docOver.call(this, e); + return false; + } - function docOver(e) { - clearTimeout(doc_leave_timer); - e.preventDefault(); - opts.docOver.call(this, e); - return false; - } + function docLeave(e) { + doc_leave_timer = setTimeout((function (_this) { + return function () { + opts.docLeave.call(_this, e); + }; + })(this), 200); + } - function docLeave(e) { - doc_leave_timer = setTimeout((function(_this) { - return function() { - opts.docLeave.call(_this, e); - }; - })(this), 200); - } - - return this; - }; - - function empty() {} - - try { - if (XMLHttpRequest.prototype.sendAsBinary) { - return; - } - XMLHttpRequest.prototype.sendAsBinary = function(datastr) { - function byteValue(x) { - return x.charCodeAt(0) & 0xff; - } - var ords = Array.prototype.map.call(datastr, byteValue); - var ui8a = new Uint8Array(ords); - - // Not pretty: Chrome 22 deprecated sending ArrayBuffer, moving instead - // to sending ArrayBufferView. Sadly, no proper way to detect this - // functionality has been discovered. Happily, Chrome 22 also introduced - // the base ArrayBufferView class, not present in Chrome 21. - if ('ArrayBufferView' in window) - this.send(ui8a); - else - this.send(ui8a.buffer); + return this; }; - } catch (e) {} + + function empty() { + } + + try { + if (XMLHttpRequest.prototype.sendAsBinary) { + return; + } + XMLHttpRequest.prototype.sendAsBinary = function (datastr) { + function byteValue(x) { + return x.charCodeAt(0) & 0xff; + } + + var ords = Array.prototype.map.call(datastr, byteValue); + var ui8a = new Uint8Array(ords); + + // Not pretty: Chrome 22 deprecated sending ArrayBuffer, moving instead + // to sending ArrayBufferView. Sadly, no proper way to detect this + // functionality has been discovered. Happily, Chrome 22 also introduced + // the base ArrayBufferView class, not present in Chrome 21. + if ('ArrayBufferView' in window) { + this.send(ui8a); + } else { + this.send(ui8a.buffer); + } + }; + } catch (e) { + } })(jQuery); diff --git a/js/jquery.tagsinput.js b/js/jquery.tagsinput.js index bff12016..9cda7094 100644 --- a/js/jquery.tagsinput.js +++ b/js/jquery.tagsinput.js @@ -170,7 +170,8 @@ $.fn.tagExist = function(val) { var id = $(this).attr('id'); var tagslist = $(this).val().split(delimiter[id]); - return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not + //true when tag exists, false when not + return (jQuery.inArray(val, tagslist) >= 0); }; // clear all existing tags and import new ones from a string @@ -178,7 +179,7 @@ id = $(this).attr('id'); $('#' + id + '_tagsinput .tag').remove(); $.fn.tagsInput.importTags(this, str); - } + }; $.fn.tagsInput = function(options) { var settings = jQuery.extend({ @@ -334,7 +335,8 @@ } }); } - } // if settings.interactive + } + // if settings.interactive $(data.holder).animate({scrollTop: $(data.holder).height()}); }); @@ -362,4 +364,4 @@ } }; -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/js/js.php b/js/js.php new file mode 100644 index 00000000..a021e324 --- /dev/null +++ b/js/js.php @@ -0,0 +1,70 @@ +. + * + */ + +define('APP_ROOT', '..'); +require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'init.php'; + +$jsFiles = array( + array("href" => "js/jquery.js", "min" => false), + array("href" => "js/jquery.placeholder.js", "min" => true), + array("href" => "js/jquery-ui.js", "min" => false), + array("href" => "js/fancybox/jquery.fancybox.pack.js", "min" => false), + array("href" => "js/jquery.powertip.min.js", "min" => false), + array("href" => "js/chosen.jquery.min.js", "min" => false), + array("href" => "js/alertify.js", "min" => true), + array("href" => "js/jquery.fileDownload.js", "min" => true), + array("href" => "js/jquery.filedrop.js", "min" => true), + array("href" => "js/jquery.tagsinput.js", "min" => true), + array("href" => "js/ZeroClipboard.min.js", "min" => false), + array("href" => "js/functions.js", "min" => true) +); + +$arrJsLang = array(_('Error en la consulta'), + _('Ha ocurrido un error'), + _('Sesión finalizada'), + _('Borrar la cuenta?'), + _('Borrar el usuario?'), + _('Guarde la configuración para que sea efectiva'), + _('Clave Generada'), + _('Nivel alto'), + _('Nivel medio'), + _('Nivel bajo'), + _('Nivel muy alto'), + _('Utilizar al menos 8 caracteres'), + _('Borrar elemento?'), + _('Página no encontrada'), + _('Archivo no soportado para visualizar'), + _('Eliminar archivo?'), + _('Su navegador no soporta subir archivos con HTML5'), + _('Demasiados archivos'), + _('No es posible guardar el archivo.
Tamaño máximo:'), + _('Extensión no permitida'), + _('Vaciar el registro de eventos?')); + +//$js = "// i18n language array from PHP. Detected language: " . SP_Init::$LANG . "\n"; +echo "var LANG = ['" . implode("','", $arrJsLang) . "'];"; +echo "var APP_ROOT = '" . SP_Init::$WEBROOT . "';\n"; + +SP_Util::getMinified('js', $jsFiles); \ No newline at end of file