Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1243372
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Nov 20, 5:30 PM
Size
159 KB
Mime Type
text/x-diff
Expires
Sat, Nov 22, 5:30 PM (17 h, 46 m)
Engine
blob
Format
Raw Data
Handle
809098
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/RC/themes/default2007/platform/inc/script.js
===================================================================
--- branches/RC/themes/default2007/platform/inc/script.js (revision 9020)
+++ branches/RC/themes/default2007/platform/inc/script.js (revision 9021)
@@ -1,12 +1,93 @@
+String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); };
+
function update_checkbox(cb, cb_hidden) {
cb_hidden.value = cb.checked ? 1 : 0;
}
function redirect($url) {
window.location.href = $url;
}
function open_window($url, $window_name, $width, $height) {
window.open($url, $window_name, 'width='+$width+',height='+$height+',resizable=yes');
return false;
+}
+
+// ItemCategories class
+function ItemCategories($table_id, $field_id, $primary_category) {
+ this.CategoryTable = document.getElementById($table_id);
+ this.CategorySelector = document.getElementById($field_id + '_select');
+ this.MoreCategoriesField = document.getElementById($field_id);
+ this.PrimaryCategory = $primary_category;
+
+ // get additional categories from item
+ if (this.MoreCategoriesField.value.length) {
+ this.MoreCategories = this.MoreCategoriesField.value;
+ this.MoreCategories = this.MoreCategories.substring(1, this.MoreCategories.length - 1).split('|');
+ }
+ else {
+ this.MoreCategories = new Array ();
+ }
+}
+
+ItemCategories.prototype.AddCategory = function($separator, $delete_button) {
+ var $category_id = this.CategorySelector.options[this.CategorySelector.selectedIndex].value;
+ var $category_name = this.CategorySelector.options[this.CategorySelector.selectedIndex].innerHTML.trim();
+
+ if ((this.SearchCategory($category_id) !== false) || ($category_id == this.PrimaryCategory) || ($category_id == 0)) {
+ // don't add same category twice & don't allow to add item's primary category
+ return ;
+ }
+
+ // strip trailing HTML spaces & separator
+ var $separator_pos = $category_name.indexOf($separator);
+ if ($separator_pos != -1) {
+ $category_name = $category_name.substring($separator_pos + $separator.length);
+ }
+
+
+ var $row = this.CategoryTable.insertRow(-1);
+ $row.id = 'category_' + $category_id;
+
+ var $cell = $row.insertCell(-1);
+ $cell.innerHTML = $category_name;
+
+ $cell = $row.insertCell(-1);
+ $cell.innerHTML = $delete_button.replace(/#CATEGORY_ID#/g, $category_id);
+
+ this.MoreCategories.push($category_id);
+ this.updateMoreCategoriesField();
+}
+
+ItemCategories.prototype.SearchCategory = function($category_id) {
+ var $i = 0;
+ while ($i < this.CategoryTable.rows.length) {
+ if (this.CategoryTable.rows[$i].id == 'category_' + $category_id) {
+ return $i;
+ }
+ $i++;
+ }
+
+ return false;
+}
+
+ItemCategories.prototype.DeleteCategory = function($category_id) {
+ var $row_index = this.SearchCategory($category_id);
+
+ if ($row_index !== false) {
+ this.CategoryTable.deleteRow($row_index);
+ var $i = 0;
+ while ($i < this.MoreCategories.length) {
+ if (this.MoreCategories[$i] == $category_id) {
+ this.MoreCategories.splice($i, 1);
+ break;
+ }
+ $i++;
+ }
+ this.updateMoreCategoriesField();
+ }
+}
+
+ItemCategories.prototype.updateMoreCategoriesField = function() {
+ this.MoreCategoriesField.value = this.MoreCategories.length ? '|' + this.MoreCategories.join('|') + '|' : '';
}
\ No newline at end of file
Property changes on: branches/RC/themes/default2007/platform/inc/script.js
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.4
\ No newline at end of property
+1.4.2.1
\ No newline at end of property
Index: branches/RC/themes/default2007/platform/inc/styles.css
===================================================================
--- branches/RC/themes/default2007/platform/inc/styles.css (revision 9020)
+++ branches/RC/themes/default2007/platform/inc/styles.css (revision 9021)
@@ -1,463 +1,475 @@
/* --- Golbal Usage Styles --- */
html, body {
margin: 0px;
padding: 0px;
height: 100%;
border: none;
font: 9pt Arial;
color: #000000;
}
.fullwidth {
width: 100%;
}
table {
margin: 0px;
padding: 0px;
border-collapse: collapse;
}
td {
font: 11px Arial, serif;
color: #000000;
margin: 0px;
padding: 0px;
}
.hidden-element {
display: none;
}
.horizontal-separator {
background: url(../img/horizontal_dashed_line.gif) bottom repeat-x;
}
.vertical-separator {
background: url(../img/vertical_dashed_line.gif) top center repeat-y;
}
img, img A {
border: 0px;
}
form {
display: inline;
}
.top-background {
background: url(../img/top_background.gif) right repeat-y;
}
.menu-background {
background: url(../img/menu_background.gif) top repeat-x #1865AC;
width: 100%;
}
.top-select-padding {
padding: 0px 15px;
}
.footer-table td {
background: url(../img/footer_blue.gif) top repeat-x;
height: 26px;
color: #F7EEE4;
font-size: 10px;
padding: 0px 10px;
}
/* --- Link Styles --- */
a {
color: #197ACA;
}
a:hover {
color: #FF9900;
}
a.more-link {
font-size: 10px;
}
a.item-action {
font-size: 9px;
color: #666666;
}
a.item-action:hover {
color: #000000;
}
.footer-links {
text-align: right;
padding: 5px 10px;
}
.footer-links A {
color: #333333;
font-size: 10px;
}
.footer-links A:hover {
color: #666666;
}
/* --- Side Box Styles --- */
.side-box-header {
background: url(../img/side_boxes_background.gif) bottom repeat-x #83AFD6;
height: 29px;
padding: 0px 8px 0px 20px;
}
.side-box-title {
font-size: 12px;
color: #FFFFFF;
}
.side-box-title A {
font-size: 12px;
color: #FFFFFF;
text-decoration: underline;
}
.side-box-title A:hover {
font-size: 12px;
color: #FFDC0E;
}
.side-box-content {
background: url(../img/side_boxes_content.gif) top repeat-x;
padding: 20px 20px;
}
/* --- Content Box Styles --- */
.content-box-header {
background: #F0F5FA;
height: 29px;
padding: 0px 20px;
}
.content-box-title {
font-size: 15px;
font-family: Arial;
color: #000000;
}
.content-box-content {
background: #FFFFFF;
padding: 20px 20px 0px 20px;
}
/* --- Form Control Styles --- */
.input-text, .input-textarea {
background: url(../img/input_text_background.gif) top repeat-x #FFFFFF;
border: 1px solid #7091B9;
font-family: Arial, Helvetica, sans-serif;
font-size: 11px;
}
.input-textarea {
overflow: auto;
}
.input-select {
color: #333333;
font-size: 11px;
}
.button {
background: url(../img/input_button_background.gif) bottom repeat-x #efefef;
border: 1px solid #688BAC;
padding: 0px;
font-size: 11px;
padding: 0px 5px;
}
+.delete-button {
+ background: url(../img/delete_button_background.gif) bottom repeat-x #FF6D6D;
+ color: #FFFFFF;
+ border: 1px solid #CC0000;
+ padding: 0px;
+ font-size: 11px;
+ padding: 0px 5px;
+}
+
/* --- Form Field Styles --- */
.field-name {
padding: 5px 15px;
color: #2E5679;
font-weight: bold;
font-size: 11px;
}
.field-required {
color: #FF0000;
}
.field-hint {
color: #000000;
font-size: 10px;
}
.field-error {
color: #CC0000;
font-size: 10px;
}
.field-value {
padding: 6px 5px;
}
.warning-message td {
padding: 5px;
background: #FFE5E6;
font-size: 16px;
}
+.item-categories td {
+ padding: 1px;
+}
/* --- Login Sidebox Styles --- */
.login-status, .login-status a {
font-size: 10px;
color: #FFFFFF;
}
.login-status a:hover {
font-size: 10px;
}
.remember-login {
color: #000000;
font-size: 9px;
}
/* --- Navigation Bar Styles --- */
.navigation-bar {
background: url(../img/side_boxes_background.gif) bottom repeat-x #83AFD6;
height: 29px;
padding: 0px 20px;
font-size: 12px;
color: #FFFFFF;
}
.navigation-bar A {
color: #FFFFFF;
}
.navigation-bar A:hover {
color: #FFDC0E;
}
/* --- Top Right Menu Styles --- */
.menu-top-active-icon, .menu-top-active-text {
background: url(../img/top_menu_select.gif);
}
td.top-menu-padding {
height: 37px;
white-space: nowrap;
}
.menu-top-noactive-icon, .menu-top-active-icon {
padding: 0px 5px 0px 13px;
}
.menu-top-noactive-text, .menu-top-active-text {
padding: 0px 13px 0px 3px;
}
a.top-menu-link, a.top-menu-link:hover {
font-size: 11px;
text-decoration: none;
}
a.top-menu-link {
color: #FFFFFF;
}
a.top-menu-link:hover {
color: #CCCCCC;
}
/* --- Tab Styles --- */
.inactive-tab, .active-tab {
padding:5px 10px;
border: 1px solid #94c0de;
}
.inactive-tab {
background-color: #eff4fa;
}
.active-tab {
background-color: #FFFFFF;
border-bottom-color: #FFFFFF;
}
.tab-bottom-line {
background: url(../img/pixel_blue.gif) bottom repeat-x;
}
.tab-left-padding {
padding-left: 40px;
}
/* --- Category Listing & My Account Styles --- */
.directory-icon {
width: 22px;
vertical-align: top;
padding: 5px;
}
.directory-text {
padding: 5px 20px 5px 5px;
vertical-align: top;
}
/* --- Item Listing Page & Item Details Page Styles --- */
.item-listing {
background: url(../img/gradient_background.gif) top repeat-x #FFFFFF;
}
.item-statistics {
font-size: 10px;
color: #666666;
}
.listing-field-name {
font-weight: bold;
}
.category-statistics {
font-size: 10px;
}
.sub-section-header, .sub-section-header td {
background-color: #F4F4F4;
font-weight: bold;
padding: 5px 15px;
font-size: 12px;
}
.listing-row td {
padding: 5px 8px;
}
/* --- Pagination Bar Styles --- */
.current-page {
background: #5B97CB;
color: #FFFFFF;
padding: 1px 2px;
}
a.page-link {
color: #000000;
text-decoration: none;
}
/* --- Calendar Styles --- */
.calendar {
font-family: tahoma,verdana,sans-serif;
color: #000;
font-size: 11px;
border: 1px solid #83B2C5;
width: 225px;
position: relative;
z-index: 1;
display: none;
cursor: default;
}
.calendar table {
/*font-family: tahoma,verdana,sans-serif;*/
color: #000;
font-size: 11px;
background-color: #fefefe;
width: auto;
cursor: default;
border-collapse: separate;
}
.calendar table td {
text-align: center;
padding: 2px;
text-align: center;
}
.calendar tbody .disabled {
color: #999;
}
.calendar tbody .emptyrow {
display: none;
}
.calendar tbody .today {
font-weight: bold;
background-color: #eeeeee;
border: 1px solid #aaaaaa !important;
}
.calendar tbody .emptycell {
visibility: hidden;
}
.calendar tbody .active {
background-color: red;
}
.calendar thead .title {
font-weight: bold;
}
.calendar thead .headrow {
}
.calendar thead .active {
background-color: #c4c0b8;
padding: 2px 0px 0px 2px;
}
.calendar thead .hilite {
background-color: #e4e0d8;
}
.calendar tfoot .title {
font-weight: normal;
}
.combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; background: #e4e0d8; font-size: smaller; padding: 1px;}
.combo .label { text-align: center; padding: 1px;}
.combo .active { background: #c4c0b8; padding: 0px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000;}
.combo .hilite { background: #048; color: #fea;}
.dpContainer {
display: inline;
}
.list-no-squares {
padding: 0px;
list-style-type: none;
margin: 0px;
}
/* --- Unprocessed Styles --- */
.text-title {
font-size: 12px;
font-weight: bold;
color: #1769b5;
}
a.text-title {
font-size: 12px;
font-weight: bold;
color: #1769b5;
}
a.text-title:hover {
color: #005695;
}
/* ----- Depricated Styles ----- */
.error {
color: magenta;
}
.static {
color: #00CC66;
}
\ No newline at end of file
Property changes on: branches/RC/themes/default2007/platform/inc/styles.css
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.26
\ No newline at end of property
+1.26.2.1
\ No newline at end of property
Index: branches/RC/themes/default2007/platform/designs/categories.tpl
===================================================================
--- branches/RC/themes/default2007/platform/designs/categories.tpl (revision 9020)
+++ branches/RC/themes/default2007/platform/designs/categories.tpl (revision 9021)
@@ -1,33 +1,49 @@
<inp2:m_DefineElement name="no_categories">
<inp2:m_phrase name="lu_NoCategories"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="category_element">
<td style="width: <inp2:ColumnWidth/>">
<table>
<tr>
<td class="directory-icon">
<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/directory_icon.gif" width="22" height="17" alt="" /><br />
</td>
<td class="directory-text">
<inp2:m_if check="IsCurrent">
<strong><inp2:Field name="Name"/></strong> (<inp2:m_phrase name="lu_SubCats"/>: <inp2:SubCatCount/>)
<inp2:m_else/>
<a href="<inp2:CategoryLink template="__default__"/>" class="text-title"><inp2:Field name="Name"/></a> <span class="item-statistics">(<inp2:m_phrase name="lu_SubCats"/>: <inp2:SubCatCount/>)</span>
</inp2:m_if>
<inp2:m_if check="Field" name="IsNew"><img src="<inp2:m_TemplatesBase module="In-Portal"/>img/icon_new.gif" alt="<inp2:m_phrase name="lu_New"/>"/></inp2:m_if>
<inp2:m_if check="IsEditorsPick"><img src="<inp2:m_TemplatesBase module="In-Portal"/>img/icon_pick.gif" alt="<inp2:m_phrase name="lu_Pick"/>"/></inp2:m_if>
<br />
<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="1" height="4" alt="" /><br />
<inp2:Field name="Description" first_chars="200"/>
</td>
</tr>
</table>
</td>
</inp2:m_DefineElement>
+<inp2:m_DefineElement name="selector_category_element">
+ <option value="<inp2:m_Param name="category_id"/>">
+ <inp2:m_Param name="separator"/><inp2:m_Param name="category_name"/>
+ </option>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="more_category_element">
+ <tr id="category_<inp2:m_Param name="category_id"/>">
+ <td>
+ <inp2:m_Param name="category_name"/>
+ </td>
+ <td>
+ <input type="button" class="delete-button" value="<inp2:m_Phrase name="lu_btn_Delete"/>" onclick="$ItemCategories.DeleteCategory(<inp2:m_Param name="category_id"/>);"/>
+ </td>
+ </tr>
+</inp2:m_DefineElement>
\ No newline at end of file
Property changes on: branches/RC/themes/default2007/platform/designs/categories.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.6
\ No newline at end of property
+1.6.2.1
\ No newline at end of property
Index: branches/RC/themes/default2007/platform/elements/forms.tpl
===================================================================
--- branches/RC/themes/default2007/platform/elements/forms.tpl (revision 9020)
+++ branches/RC/themes/default2007/platform/elements/forms.tpl (revision 9021)
@@ -1,291 +1,328 @@
<inp2:m_DefineElement name="error_message">
<table class="warning-message fullwidth">
<tr>
<td width="30">
<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/warning_icon.gif" width="21" height="18" alt=""/>
</td>
<td>
<inp2:m_phrase name="lu_Warning"/>
</td>
</tr>
</table>
<br />
<inp2:m_phrase name="lu_AProblemInForm"/><br />
</inp2:m_DefineElement>
<inp2:m_DefineElement name="subsection">
<div class="horizontal-separator"><img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="3" height="1" alt=""/><br /></div>
<div class="sub-section-header"><inp2:m_Phrase label="$title"/></div>
<div class="horizontal-separator"><img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="3" height="1" alt=""/><br /></div>
<br />
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_buttons" width="default">
<tr>
<td colspan="2">
<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/grey_pix.gif" width="100%" height="1" align="absmiddle" alt="" />
</td>
</tr>
<tr>
<td style="width: <inp2:m_if check="m_ParamEquals" name="width" value="default">140<inp2:m_else/><inp2:m_Param name="width"/></inp2:m_if>px">
</td>
<td>
<br />
<inp2:m_Param name="content"/>
<br /><br />
</td>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_field_separator" is_last="0">
<inp2:m_if check="m_ParamEquals" name="is_last" value="0">
<tr>
<td colspan="2">
<div class="horizontal-separator"><img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="3" height="1" alt=""/><br /></div>
</td>
</tr>
</inp2:m_if>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_field_caption">
<inp2:m_inc param="tab_index" by="1"/>
<td class="field-name">
<label for="<inp2:{$prefix}_InputName field="$field"/>">
<span <inp2:m_if check="{$prefix}_HasError" field="$field">class="field-required"</inp2:m_if>>
<inp2:m_phrase label="$title"/></span><inp2:m_if check="{$prefix}_IsRequired" field="$field"><span class="field-required"> *</span></inp2:m_if>:
</label>
</td>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_label" as_label="" currency="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td valign="top" class="field-value">
<inp2:{$prefix}_Field field="$field" as_label="$as_label" currency="$currency"/>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_label" as_label="" currency="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td valign="top" class="field-value">
<inp2:{$prefix}_Field field="$field" as_label="$as_label" currency="$currency"/>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>" />
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_box" style="" maxlength="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="text" class="input-text" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" maxlength="<inp2:m_param name="maxlength"/>" style="<inp2:m_param name="style"/>">
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><span class="small"><inp2:m_phrase label="$hint_label"/></span></inp2:m_if>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_password" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="password" class="input-text" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="" tabindex="<inp2:m_get param="tab_index"/>" style="<inp2:m_param name="style"/>" />
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><span class="small"><inp2:m_phrase label="$hint_label"/></span></inp2:m_if>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_upload" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="file" name="<inp2:{$prefix}_InputName field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" style="<inp2:m_param name="style"/>">
<inp2:m_if check="{$prefix}_FieldEquals" name="$field" value="" inverse="inverse">
(<inp2:{$prefix}_Field field="$field"/>)
</inp2:m_if>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[upload]" value="<inp2:{$prefix}_Field field="$field"/>" />
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_image_upload" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<inp2:m_if check="{$prefix}_Field" name="$field">
<a href="<inp2:{$prefix}_ImageSrc field="$field" MaxWidth="fullsize"/>" target="_blank">
<inp2:{$prefix}_Image field="$field" render_as="image_element" DefaultImage="platform/img/no_picture.gif" MaxWidth="thumbnail"/>
</a>
<br />
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<input type="hidden" id="<inp2:{$prefix}_InputName field="Delete{$field}"/>" name="<inp2:{$prefix}_InputName field="Delete{$field}"/>" value="0" />
<input type="checkbox" id="_cb_<inp2:{$prefix}_InputName field="Delete{$field}"/>" onchange="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="Delete{$field}"/>'));">
</td>
<td>
<label for="_cb_<inp2:{$prefix}_InputName field="Delete{$field}"/>"><inp2:m_phrase name="lu_btn_DeleteImage"/></label>
</td>
</tr>
</table>
</inp2:m_if>
<input type="file" name="<inp2:{$prefix}_InputName field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" style="<inp2:m_param name="style"/>">
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[upload]" value="<inp2:{$prefix}_Field field="$field"/>" />
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_hidden" db="">
- <input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="$db"/>" />
+ <input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="$db"/>" />
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_date" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="{$field}_date"/></span><br />
</inp2:m_if>
<input type="text" class="input-text" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date"/>" value="<inp2:{$prefix}_Field field="{$field}_date" format="_regional_InputDateFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_date" input_format="1" edit_size="edit_size"/>" style="<inp2:m_param name="style"/>" datepickerIcon="<inp2:m_TemplatesBase module="In-Portal"/>img/calendar_icon.gif"> <span class="small">(<inp2:{$prefix}_Format field="{$field}_date" input_format="1" human="true"/>)</span>
<script type="text/javascript">
initCalendar("<inp2:{$prefix}_InputName field="{$field}_date"/>", "<inp2:{$prefix}_Format field="{$field}_date" input_format="1"/>");
</script>
<input type="hidden" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time" input_format="1"/>" value="" />
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_time" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time"/>" value="<inp2:{$prefix}_Field field="{$field}_time" format="_regional_InputTimeFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_time" input_format="1" edit_size="edit_size"/>" style="<inp2:m_param name="style"/>">
<span class="small">(<inp2:{$prefix}_Format field="{$field}_time" input_format="1" human="true"/>)</span>
<input type="hidden" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date" input_format="1"/>" value="" />
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_date_time" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date"/>" value="<inp2:{$prefix}_Field field="{$field}_date" format="_regional_InputDateFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_date" input_format="1" edit_size="edit_size"/>" style="<inp2:m_param name="style"/>" datepickerIcon="<inp2:m_ProjectBase/>core/admin_templates/img/calendar_icon.gif">
<span class="small">(<inp2:{$prefix}_Format field="{$field}_date" input_format="1" human="true"/>)</span>
<script type="text/javascript">
initCalendar("<inp2:{$prefix}_InputName field="{$field}_date"/>", "<inp2:{$prefix}_Format field="{$field}_date" input_format="1"/>");
</script>
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time"/>" value="<inp2:{$prefix}_Field field="{$field}_time" format="_regional_InputTimeFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_time" input_format="1" edit_size="edit_size"/>" style="<inp2:m_param name="style"/>"><span class="small"> (<inp2:{$prefix}_Format field="{$field}_time" input_format="1" human="true"/>)</span>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_textarea" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<textarea class="input-textarea" tabindex="<inp2:m_get param="tab_index"/>" name="<inp2:{$prefix}_InputName field="$field"/>" cols="<inp2:m_param name="cols"/>" rows="<inp2:m_param name="rows"/>" style="<inp2:m_param name="style"/>"><inp2:{$prefix}_Field field="$field"/></textarea>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_option_item">
<option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_option_phrase">
<option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_phrase label="$option"/></option>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_options" style="" has_empty="0" empty_value="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<select class="input-select" tabindex="<inp2:m_get param="tab_index"/>" name="<inp2:{$prefix}_InputName field="$field"/>" style="<inp2:m_param name="style"/>">
<inp2:m_if check="m_ParamEquals" name="use_phrases" value="1" >
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_phrase" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
<inp2:m_else/>
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_item" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
</inp2:m_if>
</select>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_radio_item" onclick="">
<input type="radio" tabindex="<inp2:m_get param="tab_index"/>" style="<inp2:m_param name="style"/>" <inp2:m_param name="checked"/> name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_radio_phrase" onclick="">
<input type="radio" tabindex="<inp2:m_get param="tab_index"/>" style="<inp2:m_param name="style"/>" <inp2:m_param name="checked"/> name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_phrase label="$option"/></label>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_radio" style="" pass_tabindex="" onclick="" onchange="" use_phrases="1" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td class="field-value">
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<inp2:m_if check="m_ParamEquals" name="use_phrases" value="1">
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_radio_phrase" selected="checked"/>
<inp2:m_else />
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_radio_item" selected="checked"/>
</inp2:m_if>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_checkbox" style="" is_last="0">
<tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td>
<inp2:m_if check="{$prefix}_HasError" field="$field">
<span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
</inp2:m_if>
<input type="hidden" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>" />
<input tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:{$prefix}_InputName field="$field"/>" name="_cb_<inp2:{$prefix}_InputName field="$field"/>" <inp2:{$prefix}_Field field="$field" checked="checked" db="db"/> style="<inp2:m_param name="style"/>" onchange="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="$field"/>'));">
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><inp2:m_phrase label="$hint_label"/></inp2:m_if>
</td>
</tr>
<inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_categories" style="" is_last="0">
+ <inp2:m_include template="platform/designs/categories"/>
+
+ <tr class="<inp2:m_odd_even odd="table_color1" even="table_color2"/>">
+ <inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
+ <td class="field-value">
+ <inp2:m_if check="{$prefix}_HasError" field="$field">
+ <span class="field-error"><inp2:{$prefix}_Error field="$field"/></span><br />
+ </inp2:m_if>
+ <select class="input-select" tabindex="<inp2:m_get param="tab_index"/>" id="<inp2:{$prefix}_InputName field="$field"/>_select" style="<inp2:m_param name="style"/>">
+ <option value="0"><inp2:m_Phrase name="lu_opt_SelectCategory"/></option>
+ <inp2:{$prefix}_CategorySelector render_as="selector_category_element" separator="» "/>
+ </select>
+
+ <input type="button" class="button" value="<inp2:m_Phrase name="lu_btn_Add"/>" onclick="$ItemCategories.AddCategory('»&nbsp;', $delete_button);"/><br />
+ <table class="item-categories" id="item_categories">
+ <tbody>
+ <tr>
+ <td colspan="2">
+ <inp2:m_Phrase name="lu_subsection_Categories"/>:
+ </td>
+ </tr>
+ <inp2:{$prefix}_PrintMoreCategories render_as="more_category_element" field="$field"/>
+ </tbody>
+ </table>
+
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="$prefix" field="$field"/>
+
+ <script type="text/javascript">
+ var $delete_button = '<input type="button" class="delete-button" value="<inp2:m_Phrase name="lu_btn_Delete"/>" onclick="$ItemCategories.DeleteCategory(#CATEGORY_ID#);"/>';
+ var $ItemCategories = new ItemCategories('item_categories', '<inp2:{$prefix}_InputName field="$field"/>', <inp2:m_Get name="m_cat_id"/>);
+ </script>
+ </td>
+ </tr>
+ <inp2:m_RenderElement name="inp_edit_field_separator" is_last="$is_last"/>
</inp2:m_DefineElement>
\ No newline at end of file
Property changes on: branches/RC/themes/default2007/platform/elements/forms.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.12
\ No newline at end of property
+1.12.2.1
\ No newline at end of property
Index: branches/RC/themes/default2007/platform/img/delete_button_background_1.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: branches/RC/themes/default2007/platform/img/delete_button_background_1.gif
___________________________________________________________________
Deleted: cvs2svn:cvs-rev
## -1 +0,0 ##
-1.1.2.1
\ No newline at end of property
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: branches/RC/themes/default2007/platform/img/delete_button_background.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: branches/RC/themes/default2007/platform/img/delete_button_background.gif
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1.2.2
\ No newline at end of property
+1.1.2.3
\ No newline at end of property
Index: branches/RC/core/units/general/cat_dbitem.php
===================================================================
--- branches/RC/core/units/general/cat_dbitem.php (revision 9020)
+++ branches/RC/core/units/general/cat_dbitem.php (revision 9021)
@@ -1,504 +1,534 @@
<?php
class kCatDBItem extends kDBItem {
/**
* Category path, needed for import
*
* @var Array
*/
var $CategoryPath = Array();
/**
* Use automatic filename generation
*
* @var bool
*/
var $useFilenames = true;
/**
* Use pending editing abilities during item (delegated by permissions)
*
* @var bool
*/
var $usePendingEditing = false;
function Clear($new_id = null)
{
parent::Clear($new_id);
$this->CategoryPath = Array();
}
/**
* Set's prefix and special
*
* @param string $prefix
* @param string $special
* @access public
*/
function Init($prefix, $special, $event_params = null)
{
parent::Init($prefix, $special, $event_params);
$this->usePendingEditing = $this->Application->getUnitOption($this->Prefix, 'UsePendingEditing');
}
function Create($force_id=false, $system_create=false)
{
if (!$this->Validate()) return false;
$this->SetDBField('ResourceId', $this->Application->NextResourceId());
$this->SetDBField('Modified', adodb_mktime() );
$this->UpdateFormattersSubFields(array('Modified'));
if ($this->mode != 't' && !$this->Application->IsAdmin()) {
$owner_field = $this->Application->getUnitOption($this->Prefix, 'OwnerField');
if (!$owner_field) {
$owner_field = 'CreatedById';
}
$this->SetDBField($owner_field, $this->Application->RecallVar('user_id'));
}
if ($this->useFilenames) {
$this->checkFilename();
$this->generateFilename();
}
$ret = parent::Create();
if ($ret) {
- $primary_category = $this->GetDBField('CategoryId') > 0 ? $this->GetDBField('CategoryId') : $this->Application->GetVar('m_cat_id');
- $fields_hash = Array(
- 'CategoryId' => $primary_category,
- 'ItemResourceId' => $this->GetField('ResourceId'),
- 'PrimaryCat' => 1,
- 'ItemPrefix' => $this->Prefix,
- 'Filename' => $this->GetDBField('Filename'),
- );
- $this->Conn->doInsert($fields_hash, $this->CategoryItemsTable());
+ $this->assignPrimaryCategory();
}
return $ret;
}
+ function assignPrimaryCategory()
+ {
+ $primary_category = $this->GetDBField('CategoryId') > 0 ? $this->GetDBField('CategoryId') : $this->Application->GetVar('m_cat_id');
+ $this->assignToCategory($primary_category, true);
+ }
+
function Update($id=null, $system_update=false)
{
$this->VirtualFields['ResourceId'] = Array();
$this->SetDBField('Modified', adodb_mktime() );
$this->UpdateFormattersSubFields(array('Modified'));
$this->SetDBField('ModifiedById', $this->Application->RecallVar('user_id'));
if ($this->useFilenames) {
$this->checkFilename();
$this->generateFilename();
}
$ret = parent::Update($id, $system_update);
if ($ret) {
$filename = $this->useFilenames ? $this->GetDBField('Filename') : '';
$sql = 'UPDATE '.$this->CategoryItemsTable().'
SET Filename = '.$this->Conn->qstr($filename).'
WHERE ItemResourceId = '.$this->GetDBField('ResourceId');
$this->Conn->Query($sql);
}
unset($this->VirtualFields['ResourceId']);
return $ret;
}
/**
* Returns CategoryItems table based on current item mode (temp/live)
*
* @return string
*/
function CategoryItemsTable()
{
$table = TABLE_PREFIX.'CategoryItems';
if ($this->Application->IsTempTable($this->TableName)) {
$table = $this->Application->GetTempName($table, 'prefix:'.$this->Prefix);
}
return $table;
}
function checkFilename()
{
if( !$this->GetDBField('AutomaticFilename') )
{
$filename = $this->GetDBField('Filename');
$this->SetDBField('Filename', $this->stripDisallowed($filename) );
}
}
function Copy($cat_id=null)
{
if (!isset($cat_id)) $cat_id = $this->Application->GetVar('m_cat_id');
$this->NameCopy($cat_id);
return $this->Create($cat_id);
}
function NameCopy($master=null, $foreign_key=null)
{
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if (!$title_field) return;
$new_name = $this->GetDBField($title_field);
$cat_id = $this->Application->GetVar('m_cat_id');
$original_checked = false;
do {
if ( preg_match('/Copy ([0-9]*) *of (.*)/', $new_name, $regs) ) {
$new_name = 'Copy '.( (int)$regs[1] + 1 ).' of '.$regs[2];
}
elseif ($original_checked) {
$new_name = 'Copy of '.$new_name;
}
$query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ON
('.TABLE_PREFIX.'CategoryItems.ItemResourceId = '.$this->TableName.'.ResourceId)
WHERE ('.TABLE_PREFIX.'CategoryItems.CategoryId = '.$cat_id.') AND '.
$title_field.' = '.$this->Conn->qstr($new_name);
$res = $this->Conn->GetOne($query);
$original_checked = true;
} while ($res !== false);
$this->SetDBField($title_field, $new_name);
// this is needed, because Create will create items in its own CategoryId (if it's set),
// but we need to create it in target Paste category @see{kCatDBItem::Create} and its primary_category detection
$this->SetDBField('CategoryId', $cat_id);
}
function MoveToCat($cat_id=null)
{
// $this->NameCopy();
$cat_id = $this->Application->GetVar('m_cat_id');
// check if the product already exists in destination cat
$query = 'SELECT PrimaryCat FROM '.TABLE_PREFIX.'CategoryItems
WHERE CategoryId = '.$cat_id.' AND ItemResourceId = '.$this->GetDBField('ResourceId');
// if it's not found is_primary will be FALSE, if it's found but not primary it will be int 0
$is_primary = $this->Conn->GetOne($query);
$exists = $is_primary !== false;
if ($exists) { // if the Product already exists in destination category
if ($is_primary) return; // do nothing when we paste to primary
// if it's not primary - delete it from destination category,
// as we will move it from current primary below
$query = 'DELETE FROM '.TABLE_PREFIX.'CategoryItems
WHERE ItemResourceId = '.$this->GetDBField('ResourceId').' AND CategoryId = '.$cat_id;
$this->Conn->Query($query);
}
$query = 'UPDATE '.TABLE_PREFIX.'CategoryItems SET CategoryId = '.$cat_id.
' WHERE ItemResourceId = '.$this->GetDBField('ResourceId').' AND PrimaryCat = 1';
$this->Conn->Query($query);
$this->Update();
}
// We need to delete CategoryItems record when deleting product
function Delete($id = null)
{
if( isset($id) ) {
$this->setID($id);
}
$this->Load($this->GetID());
$ret = parent::Delete();
if ($ret) {
$query = ' DELETE FROM '.$this->CategoryItemsTable().'
WHERE ItemResourceId = '.$this->GetDBField('ResourceId');
$this->Conn->Query($query);
}
return $ret;
}
/**
* Deletes item from categories
*
* @param Array $delete_category_ids
* @author Alex
*/
function DeleteFromCategories($delete_category_ids)
{
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField'); // because item was loaded before by ResourceId
$ci_table = $this->Application->getUnitOption($this->Prefix.'-ci', 'TableName');
$resource_id = $this->GetDBField('ResourceId');
$item_cats_sql = 'SELECT CategoryId FROM %s WHERE ItemResourceId = %s';
$delete_category_items_sql = 'DELETE FROM %s WHERE ItemResourceId = %s AND CategoryId IN (%s)';
$category_ids = $this->Conn->GetCol( sprintf($item_cats_sql, $ci_table, $resource_id) );
$cats_left = array_diff($category_ids, $delete_category_ids);
if(!$cats_left)
{
$sql = 'SELECT %s FROM %s WHERE ResourceId = %s';
$ids = $this->Conn->GetCol( sprintf($sql, $id_field, $this->TableName, $resource_id) );
$temp =& $this->Application->recallObject($this->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$temp->DeleteItems($this->Prefix, $this->Special, $ids);
}
else
{
$this->Conn->Query( sprintf($delete_category_items_sql, $ci_table, $resource_id, implode(',', $delete_category_ids) ) );
$sql = 'SELECT CategoryId FROM %s WHERE PrimaryCat = 1 AND ItemResourceId = %s';
$primary_cat_id = $this->Conn->GetCol( sprintf($sql, $ci_table, $resource_id) );
if( count($primary_cat_id) == 0 )
{
$sql = 'UPDATE %s SET PrimaryCat = 1 WHERE (CategoryId = %s) AND (ItemResourceId = %s)';
$this->Conn->Query( sprintf($sql, $ci_table, reset($cats_left), $resource_id ) );
}
}
}
/**
* replace not allowed symbols with "_" chars + remove duplicate "_" chars in result
*
* @param string $string
* @return string
*/
function stripDisallowed($filename)
{
$filenames_helper =& $this->Application->recallObject('FilenamesHelper');
$table = $this->mode == 't' ? $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems', 'prefix:'.$this->Prefix) : TABLE_PREFIX.'CategoryItems';
return $filenames_helper->stripDisallowed($table, 'ItemResourceId', $this->GetDBField('ResourceId'), $filename);
}
/* commented out because it's called only from stripDisallowed body, which is moved to helper
function checkAutoFilename($filename)
{
$filenames_helper =& $this->Application->recallObject('FilenamesHelper');
return $filenames_helper->checkAutoFilename($this->TableName, $this->IDField, $this->GetID(), $filename);
}*/
/**
* Generate item's filename based on it's title field value
*
* @return string
*/
function generateFilename()
{
if ( !$this->GetDBField('AutomaticFilename') && $this->GetDBField('Filename') ) return false;
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if (preg_match('/l([\d]+)_(.*)/', $title_field, $regs)) {
// if title field is multilingual, then use it's name from primary language
$title_field = 'l'.$this->Application->GetDefaultLanguageId().'_'.$regs[2];
}
$name = $this->stripDisallowed( $this->GetDBField($title_field) );
if ( $name != $this->GetDBField('Filename') ) $this->SetDBField('Filename', $name);
}
/**
* Check if value is set for required field
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateRequired($field, $params)
{
$res = true;
if (getArrayValue($params, 'required')) {
$res = ( (string) $this->FieldValues[$field] != '');
}
if (!$res) {
$this->SetError($field, 'required');
}
return $res;
}
/**
* Adds item to other category
*
* @param int $category_id
* @param bool $is_primary
*/
function assignToCategory($category_id, $is_primary = false)
{
- $table = $this->mode == 't' ? $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems', 'prefix:'.$this->Prefix) : TABLE_PREFIX.'CategoryItems';
+ $table = $this->CategoryItemsTable();
$key_clause = '(ItemResourceId = '.$this->GetDBField('ResourceId').')';
// get all cateories, where item is in
$sql = 'SELECT PrimaryCat, CategoryId FROM '.$table.' WHERE '.$key_clause;
$item_categories = $this->Conn->GetCol($sql, 'CategoryId');
if (!$item_categories) {
$item_categories = Array();
$primary_found = false;
}
// find primary category
foreach ($item_categories as $item_category_id => $primary_found) {
if ($primary_found) {
break;
}
}
if ($primary_found && ($item_category_id == $category_id) && !$is_primary) {
// want to make primary category as non-primary :(
return true;
}
else if (!$primary_found) {
$is_primary = true;
}
if ($is_primary && $item_categories) {
// reset primary mark from all other categories
$sql = 'UPDATE '.$table.' SET PrimaryCat = 0 WHERE '.$key_clause;
$this->Conn->Query($sql);
}
// UPDATE & INSERT instead of REPLACE because CategoryItems table has no primary key defined in database
if (isset($item_categories[$category_id])) {
$sql = 'UPDATE '.$table.' SET PrimaryCat = '.($is_primary ? 1 : 0).' WHERE '.$key_clause.' AND (CategoryId = '.$category_id.')';
$this->Conn->Query($sql);
}
else {
- $sql = 'INSERT INTO '.$table.' (CategoryId,ItemResourceId,PrimaryCat,ItemPrefix,Filename) VALUES (%s,%s,%s,%s,%s)';
- $filename = $this->useFilenames ? $this->GetDBField('Filename') : ''; // because some prefixes does not use filenames
- $this->Conn->Query( sprintf($sql, $category_id, $this->GetDBField('ResourceId'), $is_primary ? 1 : 0, $this->Conn->qstr($this->Prefix), $this->Conn->qstr($filename)) );
+ $fields_hash = Array(
+ 'CategoryId' => $category_id,
+ 'ItemResourceId' => $this->GetField('ResourceId'),
+ 'PrimaryCat' => $is_primary ? 1 : 0,
+ 'ItemPrefix' => $this->Prefix,
+ 'Filename' => $this->useFilenames ? $this->GetDBField('Filename') : '', // because some prefixes does not use filenames,
+ );
+ $this->Conn->doInsert($fields_hash, $table);
}
// to ensure filename update after adding to another category
// this is critical since there may be an item with same filename in newly added category!
$this->Update();
}
/**
* Removes item from category specified
*
* @param int $category_id
*/
function removeFromCategory($category_id)
{
$sql = 'DELETE FROM '.TABLE_PREFIX.'CategoryItems WHERE (CategoryId = %s) AND (ItemResourceId = %s)';
$this->Conn->Query( sprintf($sql, $category_id, $this->GetDBField('ResourceId')) );
}
/**
* Returns list of columns, that could exist in imported file
*
* @return Array
*/
function getPossibleExportColumns()
{
static $columns = null;
if (!is_array($columns)) {
$columns = array_merge($this->Fields['AvailableColumns']['options'], $this->Fields['ExportColumns']['options']);
}
return $columns;
}
/**
* Returns item's primary image data
*
* @return Array
*/
function getPrimaryImageData()
{
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'Images
WHERE (ResourceId = '.$this->GetDBField('ResourceId').') AND (DefaultImg = 1)';
$image_data = $this->Conn->GetRow($sql);
if (!$image_data) {
// 2. no primary image, then get image with name "main"
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'Images
WHERE (ResourceId = '.$this->GetDBField('ResourceId').') AND (Name = "main")';
$image_data = $this->Conn->GetRow($sql);
}
return $image_data;
}
function ChangeStatus($new_status)
{
$status_field = array_shift( $this->Application->getUnitOption($this->Prefix,'StatusField') );
$this->SetDBField($status_field, $new_status);
return $this->Update();
}
/**
* Approves changes made to category item
*
* @return bool
*/
function ApproveChanges()
{
$original_id = $this->GetDBField('OrgId');
if (!($this->usePendingEditing && $original_id)) {
// non-pending copy of original link
return $this->ChangeStatus(STATUS_ACTIVE);
}
if ($this->raiseEvent('OnBeforeDeleteOriginal', null, Array('original_id' => $original_id))) {
// delete original item, because changes made in pending copy (this item) got to be approved in this method
$temp_handler =& $this->Application->recallObject($this->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$temp_handler->DeleteItems($this->Prefix, $this->Special, Array($original_id));
$this->SetDBField('OrgId', 0);
return $this->ChangeStatus(STATUS_ACTIVE);
}
return false;
}
/**
* Decline changes made to category item
*
* @return bool
*/
function DeclineChanges()
{
$original_id = $this->GetDBField('OrgId');
if (!($this->usePendingEditing && $original_id)) {
// non-pending copy of original link
return $this->ChangeStatus(STATUS_DISABLED);
}
// delete this item, because changes made in pending copy (this item) will be declined in this method
$temp_handler =& $this->Application->recallObject($this->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$temp_handler->DeleteItems($this->Prefix, $this->Special, Array($this->GetID()));
// original item is not changed here, because it is already enabled (thrus pending copy is visible to item's owner or admin with permission)
return true;
}
function RegisterHit()
{
$already_viewed = $this->Application->RecallVar($this->getPrefixSpecial().'_already_viewed');
$already_viewed = $already_viewed ? unserialize($already_viewed) : Array ();
$id = $this->GetID();
if (!in_array($id, $already_viewed)) {
$property_map = $this->Application->getUnitOption($this->Prefix, 'ItemPropertyMappings');
if (!$property_map) {
return ;
}
$hits_field = $property_map['ClickField'];
$new_hits = $this->GetDBField($hits_field) + 1;
$sql = 'SELECT MAX('.$hits_field.')
FROM '.$this->TableName.'
WHERE FLOOR('.$hits_field.') = '.$new_hits;
$max_hits = $this->Conn->GetOne($sql);
if ($max_hits) {
$new_hits = $max_hits + 0.000001;
}
$fields_hash = Array (
$hits_field => $new_hits,
);
$this->Conn->doUpdate($fields_hash, $this->TableName, $this->IDField.' = '.$id);
array_push($already_viewed, $id);
$this->Application->StoreVar($this->getPrefixSpecial().'_already_viewed', serialize($already_viewed));
}
}
+ /**
+ * Returns part of SQL WHERE clause identifing the record, ex. id = 25
+ *
+ * @access public
+ * @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
+ * @param Array $keys_hash alternative, then item id, keys hash to load item by
+ * @return void
+ * @see kDBItem::Load()
+ * @see kDBItem::Update()
+ * @see kDBItem::Delete()
+ */
+ function GetKeyClause($method = null, $keys_hash = null)
+ {
+ if ($method == 'load') {
+ // for item with many categories makes primary to load
+ $ci_table = TABLE_PREFIX.'CategoryItems';
+ if ($this->IsTempTable()) {
+ $ci_table = $this->Application->GetTempName($ci_table, 'prefix:'.$this->Prefix);
+ }
+ $keys_hash = Array(
+ $this->IDField => $this->ID,
+ '`'.$ci_table.'`.`PrimaryCat`' => 1,
+ );
+ }
+ return parent::GetKeyClause($method, $keys_hash);
+ }
+
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/cat_dbitem.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.40
\ No newline at end of property
+1.40.2.1
\ No newline at end of property
Index: branches/RC/core/units/general/cat_tag_processor.php
===================================================================
--- branches/RC/core/units/general/cat_tag_processor.php (revision 9020)
+++ branches/RC/core/units/general/cat_tag_processor.php (revision 9021)
@@ -1,532 +1,611 @@
<?php
class kCatDBTagProcessor extends kDBTagProcessor {
/**
* Permission Helper
*
* @var kPermissionsHelper
*/
var $PermHelper = null;
function kCatDBTagProcessor()
{
parent::kDBTagProcessor();
$this->PermHelper = $this->Application->recallObject('PermissionsHelper');
}
function ItemIcon($params)
{
$object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
$icons =& $grids[ $params['grid'] ]['Icons'];
$status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
if (!$status_fields) return $icons['default'];
$value = $object->GetDBField($status_fields[0]); // sets base status icon
/* @var $object kDBItem */
if ($value == STATUS_ACTIVE) {
if( $object->HasField('IsPop') && $object->GetDBField('IsPop') ) $value = 'POP';
if( $object->HasField('IsHot') && $object->GetDBField('IsHot') ) $value = 'HOT';
if( $object->HasField('IsNew') && $object->GetDBField('IsNew') ) $value = 'NEW';
if( $object->HasField('EditorsPick') && $object->GetDBField('EditorsPick') ) $value = 'PICK';
}
return isset($icons[$value]) ? $icons[$value] : $icons['default'];
}
/**
* Allows to create valid mod-rewrite compatible link to module item
*
* @param Array $params
* @param string $id_prefix
* @return string
*/
function ItemLink($params, $id_prefix = null)
{
$params = array_merge($params, Array('pass' => 'm,'.$this->Prefix) );
$item_id = isset($params[$id_prefix.'_id']) && $params[$id_prefix.'_id'];
if (!$item_id) {
$item_id = $this->Application->GetVar($this->getPrefixSpecial().'_id');
if (!$item_id) {
$item_id = $this->Application->GetVar($this->Prefix.'_id');
}
}
$params[$this->Prefix.'_id'] = $item_id;
$object =& $this->getObject($params);
$params['m_cat_id'] = $object->GetDBField('CategoryId');
$params['pass_category'] = 1;
return $this->Application->ProcessParsedTag('m', 't', $params);
}
function CategoryPath($params)
{
if ($this->Application->IsAdmin()) {
// path for module root category in admin
if (!isset($params['cat_id'])) {
$params['cat_id'] = $this->Application->RecallVar($params['session_var'], 0);
}
}
else {
// path for category item category in front-end
$object =& $this->getObject($params);
$params['cat_id'] = $object->GetDBField('CategoryId');
}
return $this->Application->ProcessParsedTag('c', 'CategoryPath', $params);
}
function BuildListSpecial($params)
{
if ($this->Special != '') return $this->Special;
if ( isset($params['parent_cat_id']) ) {
$parent_cat_id = $params['parent_cat_id'];
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
}
$recursive = isset($params['recursive']);
$types = $this->SelectParam($params, 'types');
$except = $this->SelectParam($params, 'except');
if ($types.$except.$recursive == '') {
return parent::BuildListSpecial($params);
}
$special = crc32($parent_cat_id.$types.$except.$recursive);
return $special;
}
function CatalogItemCount($params)
{
$object =& $this->GetList($params);
if (!$object->Counted) {
$object->CountRecs();
}
return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' / '.$object->NoFilterCount : $object->RecordsCount;
}
function ListReviews($params)
{
$prefix = $this->Prefix.'-rev';
$review_tag_processor =& $this->Application->recallObject($prefix.'.item_TagProcessor');
return $review_tag_processor->PrintList($params);
}
function ReviewCount($params)
{
$review_tag_processor =& $this->Application->recallObject('rev.item_TagProcessor');
return $review_tag_processor->TotalRecords($params);
}
function InitCatalogTab($params)
{
$tab_params['mode'] = $this->Application->GetVar('tm'); // single/multi selection possible
$tab_params['special'] = $this->Application->GetVar('ts'); // use special for this tab
$tab_params['dependant'] = $this->Application->GetVar('td'); // is grid dependant on categories grid
// set default params (same as in catalog)
if ($tab_params['mode'] === false) $tab_params['mode'] = 'multi';
if ($tab_params['special'] === false) $tab_params['special'] = '';
if ($tab_params['dependant'] === false) $tab_params['dependant'] = 'yes';
// pass params to block with tab content
$params['name'] = $params['render_as'];
$params['prefix'] = trim($this->Prefix.'.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
$params['cat_prefix'] = trim('c.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
$params['tab_mode'] = $tab_params['mode'];
$params['tab_dependant'] = $tab_params['dependant'];
$params['show_category'] = $tab_params['special'] == 'showall' ? 1 : 0; // this is advanced view -> show category name
return $this->Application->ParseBlock($params, 1);
}
/**
* Show CachedNavbar of current item primary category
*
* @param Array $params
* @return string
*/
function CategoryName($params)
{
// show category cachednavbar of
$object =& $this->getObject($params);
$category_id = isset($params['cat_id']) ? $params['cat_id'] : $object->GetDBField('CategoryId');
$category_path = $this->Application->getCache('category_paths', $category_id);
if ($category_path === false) {
// not chached
if ($category_id > 0) {
$category_path = trim($this->CategoryName( Array('cat_id' => 0) ).' > '.str_replace('&|&', ' > ', $object->GetDBField('CachedNavbar')), ' > ');
}
else {
$category_path = $this->Application->Phrase( $this->Application->ConfigValue('Root_Name') );
}
$this->Application->setCache('category_paths', $category_id, $category_path);
}
return $category_path;
}
/**
* Allows to determine if original value should be shown
*
* @param Array $params
* @return bool
*/
function DisplayOriginal($params)
{
// original id found & greather then zero + show original
$display_original = isset($params['display_original']) && $params['display_original'];
$owner_field = $this->Application->getUnitOption($this->Prefix, 'OwnerField');
if (!$owner_field) {
$owner_field = 'CreatedById';
}
$object =& $this->getObject($params);
$perm_value = $this->PermHelper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $this->Prefix);
return $display_original && ($perm_value == 1) && $this->Application->GetVar($this->Prefix.'.original_id');
}
/**
* Checks if user have one of required permissions
*
* @param Array $params
* @return bool
*/
function HasPermission($params)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$params['raise_warnings'] = 0;
$object =& $this->getObject($params);
/* @var $object kCatDBItem */
// 1. category restriction
$params['cat_id'] = $object->isLoaded() ? $object->GetDBField('ParentPath') : $this->Application->GetVar('m_cat_id');
// 2. owner restriction
$owner_field = $this->Application->getUnitOption($this->Prefix, 'OwnerField');
if (!$owner_field) {
$owner_field = 'CreatedById';
}
$is_owner = $object->GetDBField($owner_field) == $this->Application->RecallVar('user_id');
return $perm_helper->TagPermissionCheck($params, $is_owner);
}
/**
* Creates link to current category or to module root category, when current category is home
*
* @param Array $params
* @return string
*/
function SuggestItemLink($params)
{
if (!isset($params['cat_id'])) {
$params['cat_id'] = $this->Application->GetVar('m_cat_id');
}
if ($params['cat_id'] == 0) {
$params['cat_id'] = $this->Application->findModule('Var', $this->Prefix, 'RootCat');
}
return $this->Application->ProcessParsedTag('c', 'CategoryLink', $params);
}
/**
* Allows to detect if item has any additional images available
*
* @param Array $params
* @return string
*/
function HasAdditionalImages($params)
{
$object =& $this->getObject($params);
$sql = 'SELECT ImageId
FROM '.$this->Application->getUnitOption('img', 'TableName').'
WHERE ResourceId = '.$object->GetDBField('ResourceId').' AND DefaultImg != 1 AND Enabled = 1';
return $this->Conn->GetOne($sql) ? 1 : 0;
}
/**
* Checks that item is pending
*
* @param Array $params
* @return bool
*/
function IsPending($params)
{
$object =& $this->getObject($params);
$pending_status = Array (STATUS_PENDING, STATUS_PENDING_EDITING);
return in_array($object->GetDBField('Status'), $pending_status);
}
function IsFavorite($params)
{
static $favorite_status = Array ();
$object =& $this->getObject($params);
/* @var $object kDBList */
if (!isset($favorite_status[$this->Special])) {
$resource_ids = $object->GetCol('ResourceId');
$user_id = $this->Application->RecallVar('user_id');
$sql = 'SELECT FavoriteId, ResourceId
FROM '.$this->Application->getUnitOption('fav', 'TableName').'
WHERE (PortalUserId = '.$user_id.') AND (ResourceId IN ('.implode(',', $resource_ids).'))';
$favorite_status[$this->Special] = $this->Conn->GetCol($sql, 'ResourceId');
}
return isset($favorite_status[$this->Special][$object->GetDBField('ResourceId')]);
}
/**
* Returns item's editors pick status (using not formatted value)
*
* @param Array $params
* @return bool
*/
function IsEditorsPick($params)
{
$object =& $this->getObject($params);
return $object->GetDBField('EditorsPick') == 1;
}
function FavoriteToggleLink($params)
{
$fav_prefix = $this->Prefix.'-fav';
$params['pass'] = implode(',', Array('m', $this->Prefix, $fav_prefix));
$params[$fav_prefix.'_event'] = 'OnFavoriteToggle';
return $this->Application->ProcessParsedTag('m', 'Link', $params);
}
/**
* Checks if item is passed in url
*
* @param Array $params
* @return bool
*/
function ItemAvailable($params)
{
return $this->Application->GetVar($this->getPrefixSpecial().'_id') > 0;
}
function SortingSelected($params)
{
$list =& $this->GetList($params);
$user_sorting_start = $this->getUserSortIndex();
$sorting = strtolower($list->GetOrderField($user_sorting_start).'|'.$list->GetOrderDirection($user_sorting_start));
if ($sorting == strtolower($params['sorting'])) return $params['selected'];
}
function CombinedSortingDropDownName($params)
{
return $this->Prefix.'_CombinedSorting';
}
/**
* Prepares name for field with event in it (used only on front-end)
*
* @param Array $params
* @return string
*/
function SubmitName($params)
{
return 'events['.$this->Prefix.']['.$params['event'].']';
}
/**
* Returns prefix + any word (used for shared between categories per page settings)
*
* @param Array $params
* @return string
*/
function VarName($params)
{
return $this->Prefix.'_'.$params['type'];
}
/**
* Checks if we are viewing module root category
*
* @param Array $params
* @return bool
*/
function IsModuleHome($params)
{
$root_category = $this->Application->findModule('Var', $this->Prefix, 'RootCat');
return $root_category == $this->Application->GetVar('m_cat_id');
}
/**
* Dynamic votes indicator
*
* @param Array $params
*
* @return string
*/
function VotesIndicator($params)
{
$blocks_params = $this->prepareTagParams($params);
$blocks_params['name'] = $params['render_as'];
$object =& $this->getObject($params);
/* @var $object kDBItem */
if ($this->Application->ConfigValue('UseFloatRating')) {
$rating = $object->GetDBField('CachedRating');
$float_rating = floor(($rating - floor($rating)) / 0.25) * 0.25;
}
else {
$rating = round( $object->GetDBField('CachedRating') );
$float_rating = 0;
}
$i = 1;
$ret = '';
while ($i <= 5) {
$blocks_params['number'] = $i;
$blocks_params['active'] = $rating >= $i ? 1 : 0;
if ($rating > $i - 1 && $rating < $i && $float_rating > 0) {
$blocks_params['active'] = 1;
$blocks_params['float_rating'] = $float_rating;
}
else {
$blocks_params['float_rating'] = '';
}
$ret .= trim($this->Application->ParseBlock($blocks_params));
$i++;
}
return $ret;
}
function RelevanceIndicator($params)
{
$object =& $this->getObject($params);
$search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$sql = 'SELECT Relevance
FROM '.$search_results_table.'
WHERE ResourceId = '.$object->GetDBField('ResourceId');
$percents_off = (int)(100 - (100 * $this->Conn->GetOne($sql)));
$percents_off = ($percents_off < 0) ? 0 : $percents_off;
if ($percents_off) {
$params['percent_off'] = $percents_off;
$params['percent_on'] = 100 - $percents_off;
$params['name'] = $this->SelectParam($params, 'relevance_normal_render_as,block_relevance_normal');
}
else {
$params['name'] = $this->SelectParam($params, 'relevance_full_render_as,block_relevance_full');
}
return $this->Application->ParseBlock($params);
}
function SearchResultField($params)
{
$ret = $this->Field($params);
$keywords = unserialize( $this->Application->RecallVar('highlight_keywords') );
$opening = $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'highlight_opening_render_as,block_highlight_opening')) );
$closing = $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'highlight_closing_render_as,block_highlight_closing')) );
foreach ($keywords as $index => $keyword) {
$keywords[$index] = preg_quote($keyword, '/');
}
return preg_replace('/('.implode('|', $keywords).')/i', $opening.'\\1'.$closing, $ret);
}
/**
* Returns last modification date of items in category / system
*
* @param Array $params
* @return string
*/
function LastUpdated($params)
{
$category_id = $this->Application->GetVar('m_cat_id');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
if (isset($params['local']) && $params['local'] && $category_id > 0) {
// scan only current category & it's children
$sql = 'SELECT TreeLeft, TreeRight
FROM '.TABLE_PREFIX.'Category
WHERE CategoryId = '.$category_id;
$tree_info = $this->Conn->GetRow($sql);
$sql = 'SELECT MAX(item_table.Modified) AS ModDate, MAX(item_table.CreatedOn) AS NewDate
FROM '.$table_name.' item_table
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON (item_table.ResourceId = ci.ItemResourceId)
LEFT JOIN '.TABLE_PREFIX.'Category c ON c.CategoryId = ci.CategoryId
WHERE c.TreeLeft BETWEEN '.$tree_info['TreeLeft'].' AND '.$tree_info['TreeRight'];
}
else {
// scan all categories in system
$sql = 'SELECT MAX(Modified) AS ModDate, MAX(CreatedOn) AS NewDate
FROM '.$table_name;
}
$row_data = $this->Conn->GetRow($sql);
if (!$row_data) {
return '';
}
$date = $row_data[ $row_data['NewDate'] > $row_data['ModDate'] ? 'NewDate' : 'ModDate' ];
// format date
$format = isset($params['format']) ? $params['format'] : '_regional_DateTimeFormat';
if (preg_match("/_regional_(.*)/", $format, $regs)) {
$lang =& $this->Application->recallObject('lang.current');
if ($regs[1] == 'DateTimeFormat') {
// combined format
$format = $lang->GetDBField('DateFormat').' '.$lang->GetDBField('TimeFormat');
}
else {
// simple format
$format = $lang->GetDBField($regs[1]);
}
}
return adodb_date($format, $date);
}
/**
* Counts category item count in system (not category-dependent)
*
* @param Array $params
* @return int
*/
function ItemCount($params)
{
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
$today_only = isset($params['today']) && $params['today'];
return $count_helper->ItemCount($this->Prefix, $today_only);
}
+
+ function CategorySelector($params)
+ {
+ $category_id = isset($params['category_id']) && is_numeric($params['category_id']) ? $params['category_id'] : false;
+ if ($category_id === false) {
+ // if category id not given use module root category
+ $category_id = $this->Application->findModule('Var', $this->Prefix, 'RootCat');
+ }
+
+ $id_field = $this->Application->getUnitOption('c', 'IDField');
+ $title_field = $this->Application->getUnitOption('c', 'TitleField');
+ $table_name = $this->Application->getUnitOption('c', 'TableName');
+
+ $count_helper =& $this->Application->recallObject('CountHelper');
+ /* @var $count_helper kCountHelper */
+
+ list ($view_perm, $view_filter) = $count_helper->GetPermissionClause('c', 'perm_cache');
+
+ // get category list (permission based)
+ $sql = 'SELECT c.'.$title_field.', c.'.$id_field.'
+ FROM '.$table_name.' c
+ INNER JOIN '.TABLE_PREFIX.'PermCache perm_cache ON c.CategoryId = perm_cache.CategoryId
+ WHERE (ParentId = '.$category_id.') AND ('.$view_filter.') AND (perm_cache.PermId = '.$view_perm.') AND (c.Status = '.STATUS_ACTIVE.')
+ ORDER BY c.'.$title_field.' ASC';
+ $categories = $this->Conn->GetCol($sql, $id_field);
+
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['render_as'];
+ $block_params['strip_nl'] = 2;
+
+ $ret = '';
+ foreach ($categories as $category_id => $category_name) {
+ // print category
+ $block_params['separator'] = isset($params['category_id']) ? $params['separator'] : ''; // return original separator, remove separator for top level categories
+ $block_params['category_id'] = $category_id;
+ $block_params['category_name'] = $category_name;
+ $ret .= $this->Application->ParseBlock($block_params);
+
+ // print it's children
+ $block_params['separator'] = ' '.$params['separator'];
+ $ret .= $this->CategorySelector($block_params);
+ }
+
+ return $ret;
+ }
+
+ function PrintMoreCategories($params)
+ {
+ $object =& $this->getObject();
+ /* @var $object kDBItem */
+
+ $category_ids = $this->Field($params);
+ if (!$category_ids) {
+ return '';
+ }
+
+ $category_ids = explode('|', substr($category_ids, 1, -1));
+
+ $id_field = $this->Application->getUnitOption('c', 'IDField');
+ $title_field = $this->Application->getUnitOption('c', 'TitleField');
+ $table_name = $this->Application->getUnitOption('c', 'TableName');
+
+ $sql = 'SELECT '.$title_field.', '.$id_field.'
+ FROM '.$table_name.'
+ WHERE '.$id_field.' IN ('.implode(',', $category_ids).')';
+ $categories = $this->Conn->GetCol($sql, $id_field);
+
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['render_as'];
+
+ $ret = '';
+ foreach ($categories as $category_id => $category_name) {
+ $block_params['category_id'] = $category_id;
+ $block_params['category_name'] = $category_name;
+ $ret .= $this->Application->ParseBlock($block_params);
+ }
+
+ return $ret;
+ }
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/cat_tag_processor.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.38.2.2
\ No newline at end of property
+1.38.2.3
\ No newline at end of property
Index: branches/RC/core/units/general/cat_event_handler.php
===================================================================
--- branches/RC/core/units/general/cat_event_handler.php (revision 9020)
+++ branches/RC/core/units/general/cat_event_handler.php (revision 9021)
@@ -1,2159 +1,2225 @@
<?php
$application =& kApplication::Instance();
$application->Factory->includeClassFile('kDBEventHandler');
class kCatDBEventHandler extends kDBEventHandler {
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnExport' => Array('self' => 'view|advanced:export'),
'OnExportBegin' => Array('self' => 'view|advanced:export'),
'OnSaveSettings' => Array('self' => 'add|edit|advanced:import'),
'OnBeforeDeleteOriginal' => Array('self' => 'edit|advanced:approve'),
'OnCancelAction' => Array('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Load item if id is available
*
* @param kEvent $event
*/
function LoadItem(&$event)
{
$object =& $event->getObject();
$id = $this->getPassedID($event);
if ($object->Load($id)) {
$actions =& $this->Application->recallObject('kActions');
$actions->Set($event->Prefix_Special.'_id', $object->GetID() );
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ($use_pending_editing && $event->Special != 'original') {
$this->Application->SetVar($event->Prefix.'.original_id', $object->GetDBField('OrgId'));
}
}
else {
$object->setID($id);
}
}
/**
* Checks permissions of user
*
* @param kEvent $event
*/
function CheckPermission(&$event)
{
if (!$this->Application->IsAdmin()) {
if ($event->Name == 'OnSetSortingDirect') {
// allow sorting on front event without view permission
return true;
}
}
if ($event->Name == 'OnExport') {
// save category_id before doing export
$this->Application->LinkVar('m_cat_id');
}
if ($event->Name == 'OnNew' && preg_match('/(.*)\/import$/', $this->Application->GetVar('t'), $rets)) {
// redirect to item import template, where permission (import) category will be chosen)
$root_category = $this->Application->findModule('Path', $rets[1].'/', 'RootCat');
$this->Application->StoreVar('m_cat_id', $root_category);
}
$check_events = Array ('OnEdit', 'OnSave', 'OnMassDelete');
if (in_array($event->Name, $check_events)) {
// check each id from selected individually and only if all are allowed proceed next
if ($event->Name == 'OnSave') {
$selected_ids = implode(',', $this->getSelectedIDs($event, true));
if (!$selected_ids) {
$selected_ids = 0; // when saving newly created item (OnPreCreate -> OnPreSave -> OnSave)
}
}
else {
$selected_ids = implode(',', $this->StoreSelectedIDs($event));
}
$perm_value = true;
if (strlen($selected_ids)) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$items = $perm_helper->GetCategoryItemData($event->Prefix, $selected_ids);
$check_method = ($event->Name == 'OnMassDelete') ? 'DeleteCheckPermission' : 'ModifyCheckPermission';
foreach ($items as $item_id => $item_data) {
if ($perm_helper->$check_method($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) == 0) {
// one of items selected has no permission
$perm_value = false;
break;
}
}
if (!$perm_value) {
$event->status = erPERM_FAIL;
}
}
else {
trigger_error('IDs not passed to '.$event->getPrefixSpecial().':CheckPermission', E_USER_WARNING);
}
return $perm_value;
}
return parent::CheckPermission($event);
}
/**
* Add selected items to clipboard with mode = COPY (CLONE)
*
* @param kEvent $event
*/
function OnCopy(&$event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
$clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event));
}
/**
* Add selected items to clipboard with mode = CUT
*
* @param kEvent $event
*/
function OnCut(&$event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
$clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event));
}
/**
* Performs category item paste
*
* @param kEvent $event
*/
function OnPaste(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$clipboard_data = $event->getEventParam('clipboard_data');
if (!$clipboard_data['cut'] && !$clipboard_data['copy']) {
return false;
}
if ($clipboard_data['copy']) {
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$this->Application->SetVar('ResetCatBeforeClone', 1);
$temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']);
}
if ($clipboard_data['cut']) {
$object =& $this->Application->recallObject($event->getPrefixSpecial().'.item', $event->Prefix, Array('skip_autoload' => true));
foreach ($clipboard_data['cut'] as $id) {
$object->Load($id);
$object->MoveToCat();
}
}
}
/**
* Return type clauses for list bulding on front
*
* @param kEvent $event
* @return Array
*/
function getTypeClauses(&$event)
{
$types = $event->getEventParam('types');
$types = $types ? explode(',', $types) : Array ();
$except_types = $event->getEventParam('except');
$except_types = $except_types ? explode(',', $except_types) : Array ();
$type_clauses = Array();
$user_id = $this->Application->RecallVar('user_id');
$owner_field = $this->getOwnerField($event->Prefix);
$type_clauses['my_items']['include'] = '%1$s.'.$owner_field.' = '.$user_id;
$type_clauses['my_items']['except'] = '%1$s.'.$owner_field.' <> '.$user_id;
$type_clauses['my_items']['having_filter'] = false;
$type_clauses['pick']['include'] = '%1$s.EditorsPick = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
$type_clauses['pick']['except'] = '%1$s.EditorsPick! = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
$type_clauses['pick']['having_filter'] = false;
$type_clauses['hot']['include'] = '`IsHot` = 1 AND PrimaryCat = 1';
$type_clauses['hot']['except'] = '`IsHot`! = 1 AND PrimaryCat = 1';
$type_clauses['hot']['having_filter'] = true;
$type_clauses['pop']['include'] = '`IsPop` = 1 AND PrimaryCat = 1';
$type_clauses['pop']['except'] = '`IsPop`! = 1 AND PrimaryCat = 1';
$type_clauses['pop']['having_filter'] = true;
$type_clauses['new']['include'] = '`IsNew` = 1 AND PrimaryCat = 1';
$type_clauses['new']['except'] = '`IsNew`! = 1 AND PrimaryCat = 1';
$type_clauses['new']['having_filter'] = true;
$type_clauses['displayed']['include'] = '';
$displayed = $this->Application->GetVar($event->Prefix.'_displayed_ids');
if ($displayed) {
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$type_clauses['displayed']['except'] = '%1$s.'.$id_field.' NOT IN ('.$displayed.')';
}
else {
$type_clauses['displayed']['except'] = '';
}
$type_clauses['displayed']['having_filter'] = false;
if (in_array('search', $types) || in_array('search', $except_types)) {
$event_mapping = Array(
'simple' => 'OnSimpleSearch',
'subsearch' => 'OnSubSearch',
'advanced' => 'OnAdvancedSearch');
if($this->Application->GetVar('INPORTAL_ON') && $this->Application->GetVar('Action') == 'm_simple_subsearch')
{
$type = 'subsearch';
}
else
{
$type = $this->Application->GetVar('search_type') ? $this->Application->GetVar('search_type') : 'simple';
}
if($keywords = $event->getEventParam('keyword_string')) // processing keyword_string param of ListProducts tag
{
$this->Application->SetVar('keywords', $keywords);
$type = 'simple';
}
$search_event = $event_mapping[$type];
$this->$search_event($event);
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$sql = 'SHOW TABLES LIKE "'.$search_table.'"';
if ($this->Conn->Query($sql)) {
$search_res_ids = $this->Conn->GetCol('SELECT ResourceId FROM '.$search_table);
}
if (isset($search_res_ids) && $search_res_ids) {
$type_clauses['search']['include'] = '%1$s.ResourceId IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
$type_clauses['search']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $search_res_ids).') AND PrimaryCat = 1';
}
else {
$type_clauses['search']['include'] = '0';
$type_clauses['search']['except'] = '1';
}
$type_clauses['search']['having_filter'] = false;
}
if (in_array('related', $types) || in_array('related', $except_types)) {
$related_to = $event->getEventParam('related_to');
if (!$related_to) {
$related_prefix = $event->Prefix;
}
else {
$sql = 'SELECT Prefix
FROM '.TABLE_PREFIX.'ItemTypes
WHERE ItemName = '.$this->Conn->qstr($related_to);
$related_prefix = $this->Conn->GetOne($sql);
}
$rel_table = $this->Application->getUnitOption('rel', 'TableName');
$item_type = $this->Application->getUnitOption($event->Prefix, 'ItemType');
$p_item =& $this->Application->recallObject($related_prefix.'.current', null, Array('skip_autoload' => true));
$p_item->Load( $this->Application->GetVar($related_prefix.'_id') );
$p_resource_id = $p_item->GetDBField('ResourceId');
$sql = 'SELECT SourceId, TargetId FROM '.$rel_table.'
WHERE
(Enabled = 1)
AND (
(Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(Type = 1
AND (
(SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.')
)
)
)';
$related_ids_array = $this->Conn->Query($sql);
$related_ids = Array();
foreach ($related_ids_array as $key => $record) {
$related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ];
}
if (count($related_ids) > 0) {
$type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
$type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
}
else {
$type_clauses['related']['include'] = '0';
$type_clauses['related']['except'] = '1';
}
$type_clauses['related']['having_filter'] = false;
}
if (in_array('favorites', $types) || in_array('favorites', $except_types)) {
$sql = 'SELECT ResourceId
FROM '.$this->Application->getUnitOption('fav', 'TableName').'
WHERE PortalUserId = '.$this->Application->RecallVar('user_id');
$favorite_ids = $this->Conn->GetCol($sql);
if ($favorite_ids) {
$type_clauses['favorites']['include'] = '%1$s.ResourceId IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1';
$type_clauses['favorites']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1';
}
else {
$type_clauses['favorites']['include'] = 0;
$type_clauses['favorites']['except'] = 1;
}
$type_clauses['favorites']['having_filter'] = false;
}
return $type_clauses;
}
/**
* Apply filters to list
*
* @param kEvent $event
*/
function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
// add category filter if needed
if ($event->Special != 'showall') {
if ($event->getEventParam('parent_cat_id') !== false) {
$parent_cat_id = $event->getEventParam('parent_cat_id');
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
if ((string) $parent_cat_id != 'any') {
if ($event->getEventParam('recursive')) {
if ($parent_cat_id > 0) {
// not "Home" category
$sql = 'SELECT TreeLeft, TreeRight
FROM '.TABLE_PREFIX.'Category
WHERE CategoryId = '.$parent_cat_id;
$tree_indexes = $this->Conn->GetRow($sql);
$object->addFilter('category_filter', TABLE_PREFIX.'Category.TreeLeft BETWEEN '.$tree_indexes['TreeLeft'].' AND '.$tree_indexes['TreeRight']);
}
$object->addFilter('primary_filter', 'PrimaryCat = 1');
}
else {
$object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId = '.$parent_cat_id );
}
}
}
else {
$object->addFilter('primary_filter', 'PrimaryCat = 1');
}
// add permission filter
if ($this->Application->RecallVar('user_id') == -1) {
// for "root" CATEGORY.VIEW permission is checked for items lists too
$view_perm = 1;
}
else {
// for any real user itemlist view permission is checked instead of CATEGORY.VIEW
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
list ($view_perm, $view_filter) = $count_helper->GetPermissionClause($event->Prefix, 'perm');
$object->addFilter('perm_filter2', $view_filter);
}
$object->addFilter('perm_filter', 'perm.PermId = '.$view_perm);
$types = $event->getEventParam('types');
$this->applyItemStatusFilter($object, $types);
$except_types = $event->getEventParam('except');
$type_clauses = $this->getTypeClauses($event);
// convert prepared type clauses into list filters
$includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter->setType(FLT_TYPE_OR);
$excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter->setType(FLT_TYPE_AND);
$includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter_h->setType(FLT_TYPE_OR);
$excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter_h->setType(FLT_TYPE_AND);
if ($types) {
$types_array = explode(',', $types);
for ($i = 0; $i < sizeof($types_array); $i++) {
$type = trim($types_array[$i]);
if (isset($type_clauses[$type])) {
if ($type_clauses[$type]['having_filter']) {
$includes_or_filter_h->removeFilter('filter_'.$type);
$includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}else {
$includes_or_filter->removeFilter('filter_'.$type);
$includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}
}
}
}
if ($except_types) {
$except_types_array = explode(',', $except_types);
for ($i = 0; $i < sizeof($except_types_array); $i++) {
$type = trim($except_types_array[$i]);
if (isset($type_clauses[$type])) {
if ($type_clauses[$type]['having_filter']) {
$excepts_and_filter_h->removeFilter('filter_'.$type);
$excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}else {
$excepts_and_filter->removeFilter('filter_'.$type);
$excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}
}
}
}
/*if ( !$this->Application->IsAdmin() ) {
$object->addFilter('expire_filter', '%1$s.Expire IS NULL OR %1$s.Expire > UNIX_TIMESTAMP()');
}*/
/*$list_type = $event->getEventParam('ListType');
switch($list_type)
{
case 'favorites':
$fav_table = $this->Application->getUnitOption('fav','TableName');
$user_id =& $this->Application->RecallVar('user_id');
$sql = 'SELECT DISTINCT f.ResourceId
FROM '.$fav_table.' f
LEFT JOIN '.$object->TableName.' p ON p.ResourceId = f.ResourceId
WHERE f.PortalUserId = '.$user_id;
$ids = $this->Conn->GetCol($sql);
if(!$ids) $ids = Array(-1);
$object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.PrimaryCat = 1');
$object->addFilter('favorites_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
break;
case 'search':
$search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$sql = ' SELECT DISTINCT ResourceId
FROM '.$search_results_table.'
WHERE ItemType=11';
$ids = $this->Conn->GetCol($sql);
if(!$ids) $ids = Array(-1);
$object->addFilter('search_filter', '%1$s.`ResourceId` IN ('.implode(',',$ids).')');
break;
} */
$object->addFilter('includes_filter', $includes_or_filter);
$object->addFilter('excepts_filter', $excepts_and_filter);
$object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
$object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
}
/**
* Adds filter that filters out items with non-required statuses
*
* @param kDBList $object
* @param string $types
*/
function applyItemStatusFilter(&$object, $types)
{
// Link1 (before modifications) [Status = 1, OrgId = NULL], Link2 (after modifications) [Status = -2, OrgId = Link1_ID]
$pending_editing = $this->Application->getUnitOption($object->Prefix, 'UsePendingEditing');
if ( !$this->Application->IsAdmin() ) {
$types = explode(',', $types);
if (in_array('my_items', $types)) {
$allow_statuses = Array (STATUS_ACTIVE, STATUS_PENDING, STATUS_PENDING_EDITING);
$object->addFilter('status_filter', '%1$s.Status IN ('.implode(',', $allow_statuses).')');
if ($pending_editing) {
$user_id = $this->Application->RecallVar('user_id');
$this->applyPendingEditingFilter($object, $user_id);
}
}
else {
$object->addFilter('status_filter', '%1$s.Status = 1');
if ($pending_editing) {
// if category item uses pending editing abilities, then in no cases show pending copies on front
$object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL');
}
}
}
else {
if ($pending_editing) {
$this->applyPendingEditingFilter($object);
}
}
}
/**
* Adds filter, that removes live items if they have pending editing copies
*
* @param kDBList $object
* @param int $user_id
*/
function applyPendingEditingFilter(&$object, $user_id = null)
{
$sql = 'SELECT OrgId
FROM '.$object->TableName.'
WHERE Status = '.STATUS_PENDING_EDITING.' AND OrgId IS NOT NULL';
if (isset($user_id)) {
$owner_field = $this->getOwnerField($object->Prefix);
$sql .= ' AND '.$owner_field.' = '.$user_id;
}
$pending_ids = $this->Conn->GetCol($sql);
if ($pending_ids) {
$object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')');
}
}
/**
* Adds calculates fields for item statuses
*
* @param kCatDBItem $object
* @param kEvent $event
*/
function prepareObject(&$object, &$event)
{
$this->prepareItemStatuses($event);
$object->addCalculatedField('CachedNavbar', 'l'.$this->Application->GetVar('m_lang').'_CachedNavbar');
if ($event->Special == 'export' || $event->Special == 'import')
{
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
$export_helper->prepareExportColumns($event);
}
}
/**
* Creates calculated fields for all item statuses based on config settings
*
* @param kEvent $event
*/
function prepareItemStatuses(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if (!$property_map) {
return ;
}
// new items
$object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue($property_map['NewDays']).
'*3600*24), 1, 0),
%1$s.NewItem
)');
// hot items (cache updated every hour)
$sql = 'SELECT Data
FROM '.TABLE_PREFIX.'Cache
WHERE (VarName = "'.$property_map['HotLimit'].'") AND (Cached >'.(adodb_mktime() - 3600).')';
$hot_limit = $this->Conn->GetOne($sql);
if ($hot_limit === false) {
$hot_limit = $this->CalculateHotLimit($event);
}
$object->addCalculatedField('IsHot', ' IF(%1$s.HotItem = 2,
IF(%1$s.'.$property_map['ClickField'].' >= '.$hot_limit.', 1, 0),
%1$s.HotItem
)');
// popular items
$object->addCalculatedField('IsPop', ' IF(%1$s.PopItem = 2,
IF(%1$s.CachedVotesQty >= '.
$this->Application->ConfigValue($property_map['MinPopVotes']).
' AND %1$s.CachedRating >= '.
$this->Application->ConfigValue($property_map['MinPopRating']).
', 1, 0),
%1$s.PopItem)');
}
function CalculateHotLimit(&$event)
{
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if (!$property_map) {
return;
}
$click_field = $property_map['ClickField'];
$last_hot = $this->Application->ConfigValue($property_map['MaxHotNumber']) - 1;
$sql = 'SELECT '.$click_field.' FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
ORDER BY '.$click_field.' DESC
LIMIT '.$last_hot.', 1';
$res = $this->Conn->GetCol($sql);
$hot_limit = (double)array_shift($res);
$this->Conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("'.$property_map['HotLimit'].'", "'.$hot_limit.'", '.adodb_mktime().')');
return $hot_limit;
return 0;
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnBeforeItemUpdate(&$event)
{
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if (!$property_map) {
return;
}
$click_field = $property_map['ClickField'];
$object =& $event->getObject();
if( $this->Application->IsAdmin() && ($this->Application->GetVar($click_field.'_original') !== false) &&
floor($this->Application->GetVar($click_field.'_original')) != $object->GetDBField($click_field) )
{
$sql = 'SELECT MAX('.$click_field.') FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE FLOOR('.$click_field.') = '.$object->GetDBField($click_field);
$hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $object->GetDBField($click_field);
$object->SetDBField($click_field, $hits);
}
}
/**
* Load price from temp table if product mode is temp table
*
* @param kEvent $event
*/
function OnAfterItemLoad(&$event)
{
$special = substr($event->Special, -6);
$object =& $event->getObject();
/* @var $object kCatDBItem */
if ($special == 'import' || $special == 'export') {
$image_data = $object->getPrimaryImageData();
if ($image_data) {
$thumbnail_image = $image_data[$image_data['LocalThumb'] ? 'ThumbPath' : 'ThumbUrl'];
if ($image_data['SameImages']) {
$full_image = '';
}
else {
$full_image = $image_data[$image_data['LocalImage'] ? 'LocalPath' : 'Url'];
}
$object->SetDBField('ThumbnailImage', $thumbnail_image);
$object->SetDBField('FullImage', $full_image);
$object->SetDBField('ImageAlt', $image_data['AltName']);
}
}
// substituiting pending status value for pending editing
if ($object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2) {
$options = $object->Fields['Status']['options'];
foreach ($options as $key => $val) {
if ($key == 2) $key = -2;
$new_options[$key] = $val;
}
$object->Fields['Status']['options'] = $new_options;
}
// linking existing images for item with virtual fields
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$image_helper->LoadItemImages($object);
+
+ // set item's additional categories to virtual field (used in editing)
+ $item_categories = $this->getItemCategories($object->GetDBField('ResourceId'));
+ $object->SetDBField('MoreCategories', $item_categories ? '|'.implode('|', $item_categories).'|' : '');
}
function OnAfterItemUpdate(&$event)
{
$this->CalculateHotLimit($event);
if ( substr($event->Special, -6) == 'import') {
$this->setCustomExportColumns($event);
}
if (!$this->Application->IsAdmin()) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
+
+ if ($event->Special != '-item') {
+ // don't touch categories during cloning
+ $this->processAdditionalCategories($object, 'update');
+ }
}
}
/**
* sets values for import process
*
* @param kEvent $event
*/
function OnAfterItemCreate(&$event)
{
if ( substr($event->Special, -6) == 'import') {
$this->setCustomExportColumns($event);
}
if (!$this->Application->IsAdmin()) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
+
+ if ($event->Special != '-item') {
+ // don't touch categories during cloning
+ $this->processAdditionalCategories($object, 'create');
+ }
}
}
/**
* Make record to search log
*
* @param string $keywords
* @param int $search_type 0 - simple search, 1 - advanced search
*/
function saveToSearchLog($keywords, $search_type = 0)
{
$sql = 'UPDATE '.TABLE_PREFIX.'SearchLog
SET Indices = Indices + 1
WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows() == 0) {
$fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLog');
}
}
/**
* Makes simple search for products
* based on keywords string
*
* @param kEvent $event
* @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
*/
function OnSimpleSearch(&$event)
{
if($this->Application->GetVar('INPORTAL_ON') && !($this->Application->GetVar('Action') == 'm_simple_search'))
{
return;
}
$event->redirect = false;
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$keywords = unhtmlentities( trim($this->Application->GetVar('keywords')) );
$query_object =& $this->Application->recallObject('HTTPQuery');
$sql = 'SHOW TABLES LIKE "'.$search_table.'"';
if(!isset($query_object->Get['keywords']) &&
!isset($query_object->Post['keywords']) &&
$this->Conn->Query($sql))
{
return; // used when navigating by pages or changing sorting in search results
}
if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length'))
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
$this->Application->SetVar('keywords_too_short', 1);
return; // if no or too short keyword entered, doing nothing
}
$this->Application->StoreVar('keywords', $keywords);
if (!$this->Application->GetVar('INPORTAL_ON')) {
// don't save search log, because in-portal already saved it
$this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search
}
$keywords = strtr($keywords, Array('%' => '\\%', '_' => '\\_'));
$event->setPseudoClass('_List');
$object =& $event->getObject();
$this->Application->SetVar($event->getPrefixSpecial().'_Page', 1);
$lang = $this->Application->GetVar('m_lang');
$items_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$module_name = $this->Application->findModule('Var', $event->Prefix, 'Name');
$sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
WHERE ModuleName="'.$module_name.'"
AND SimpleSearch=1';
$search_config = $this->Conn->Query($sql, 'FieldName');
$field_list = array_keys($search_config);
$join_clauses = Array();
// field processing
$weight_sum = 0;
$alias_counter = 0;
$custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if ($custom_fields) {
$custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId';
}
// what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table))
$search_config_map = Array();
foreach ($field_list as $key => $field) {
$options = $object->getFieldOptions($field);
$local_table = TABLE_PREFIX.$search_config[$field]['TableName'];
$weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause
// processing multilingual fields
if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$field_list[$key] = 'l'.$lang.'_'.$field;
if(!isset($search_config[$field]['ForeignField']))
{
$field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary'];
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
}
// processing fields from other tables
if($foreign_field = $search_config[$field]['ForeignField'])
{
$exploded = explode(':', $foreign_field, 2);
if($exploded[0] == 'CALC')
{
unset($field_list[$key]);
continue; // ignoring having type clauses in simple search
/*$user_groups = $this->Application->RecallVar('UserGroups');
$having_list[$key] = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
$join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $search_config[$field]['JoinClause']);
$join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
$join_clause = ' LEFT JOIN '.$join_clause;
$join_clauses[] = $join_clause;*/
}
else
{
$multi_lingual = false;
if ($exploded[0] == 'MULTI')
{
$multi_lingual = true;
$foreign_field = $exploded[1];
}
$exploded = explode('.', $foreign_field); // format: table.field_name
$foreign_table = TABLE_PREFIX.$exploded[0];
$alias_counter++;
$alias = 't'.$alias_counter;
if ($multi_lingual) {
$field_list[$key] = $alias.'.'.'l'.$lang.'_'.$exploded[1];
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$search_config_map[ $field_list[$key] ] = $field;
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
else {
$field_list[$key] = $alias.'.'.$exploded[1];
$search_config_map[ $field_list[$key] ] = $field;
}
$join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']);
$join_clause = str_replace('{LocalTable}', $items_table, $join_clause);
$join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.'
ON '.$join_clause;
}
}
else {
// processing fields from local table
if ($search_config[$field]['CustomFieldId']) {
$local_table = 'custom_data';
$field_list[$key] = 'l'.$lang.'_cust_'.array_search($field_list[$key], $custom_fields);
}
$field_list[$key] = $local_table.'.'.$field_list[$key];
$search_config_map[ $field_list[$key] ] = $field;
}
}
// keyword string processing
$search_helper =& $this->Application->recallObject('SearchHelper');
$where_clause = $search_helper->buildWhereClause($keywords, $field_list);
$where_clause = $where_clause.' AND '.$items_table.'.Status=1';
if($this->Application->GetVar('Action') == 'm_simple_subsearch') // subsearch, In-portal
{
if( $event->getEventParam('ResultIds') )
{
$where_clause .= ' AND '.$items_table.'.ResourceId IN ('.implode(',', $event->specificParams['ResultIds']).')';
}
}
if( $event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild' ) // subsearch, k4
{
if( $event->MasterEvent->getEventParam('ResultIds') )
{
$where_clause .= ' AND '.$items_table.'.ResourceId IN ('.implode(',', $event->MasterEvent->getEventParam('ResultIds')).')';
}
}
// making relevance clause
$positive_words = $search_helper->getPositiveKeywords($keywords);
$this->Application->StoreVar('highlight_keywords', serialize($positive_words));
$revelance_parts = Array();
reset($search_config);
foreach ($field_list as $field) {
$config_elem = $search_config[ $search_config_map[$field] ];
$weight = $config_elem['Priority'];
$revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)';
foreach ($positive_words as $keyword) {
$revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)';
}
}
$conf_postfix = $this->Application->getUnitOption($event->Prefix, 'SearchConfigPostfix');
$rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100;
$rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100;
$rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100;
$relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords;
if ($rel_pop && isset($object->Fields['Hits'])) {
$relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
}
if ($rel_rating && isset($object->Fields['CachedRating'])) {
$relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
}
// building final search query
if (!$this->Application->GetVar('do_not_drop_search_table') && !$this->Application->GetVar('INPORTAL_ON')) {
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event
$this->Application->SetVar('do_not_drop_search_table', true);
}
$search_table_exists = $this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"');
if ($search_table_exists) {
$select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) ';
}
else {
$select_intro = 'CREATE TABLE '.$search_table.' AS ';
}
$edpick_clause = $this->Application->getUnitOption($event->Prefix.'.EditorsPick', 'Fields') ? $items_table.'.EditorsPick' : '0';
$sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance,
'.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField').' AS ItemId,
'.$items_table.'.ResourceId,
'.$this->Application->getUnitOption($event->Prefix, 'ItemType').' AS ItemType,
'.$edpick_clause.' AS EdPick
FROM '.$object->TableName.'
'.implode(' ', $join_clauses).'
WHERE '.$where_clause.'
GROUP BY '.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField');
$res = $this->Conn->Query($sql);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSubSearch(&$event)
{
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$sql = 'SHOW TABLES LIKE "'.$search_table.'"';
if($this->Conn->Query($sql))
{
$sql = 'SELECT DISTINCT ResourceId FROM '.$search_table;
$ids = $this->Conn->GetCol($sql);
}
$event->setEventParam('ResultIds', $ids);
$event->CallSubEvent('OnSimpleSearch');
}
/**
* Enter description here...
*
* @param kEvent $event
* @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
*/
function OnAdvancedSearch(&$event)
{
$query_object =& $this->Application->recallObject('HTTPQuery');
if(!isset($query_object->Post['andor']))
{
return; // used when navigating by pages or changing sorting in search results
}
$this->Application->RemoveVar('keywords');
$this->Application->RemoveVar('Search_Keywords');
$sql = ' SELECT * FROM '.$this->Application->getUnitOption('confs', 'TableName').'
WHERE ModuleName="In-Commerce"
AND AdvancedSearch=1';
$search_config = $this->Conn->Query($sql);
$lang = $this->Application->GetVar('m_lang');
$object =& $event->getObject();
$object->SetPage(1);
$product_table = $this->Application->getUnitOption('p', 'TableName');
$search_keywords = $this->Application->GetVar('value'); // will not be changed
$keywords = $this->Application->GetVar('value'); // will be changed down there
$verbs = $this->Application->GetVar('verb');
$glues = $this->Application->GetVar('andor');
$and_conditions = Array();
$or_conditions = Array();
$and_having_conditions = Array();
$or_having_conditions = Array();
$join_clauses = Array();
$highlight_keywords = Array();
$relevance_parts = Array();
$condition_patterns = Array( 'any' => '%s LIKE %s',
'contains' => '%s LIKE %s',
'notcontains' => '(NOT (%1$s LIKE %2$s) OR %1$s IS NULL)',
'is' => '%s = %s',
'isnot' => '(%1$s != %2$s OR %1$s IS NULL)');
$alias_counter = 0;
$custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if ($custom_fields) {
$custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$product_table.'.ResourceId = custom_data.ResourceId';
}
$search_log = '';
$weight_sum = 0;
// processing fields and preparing conditions
foreach($search_config as $record)
{
$field = $record['FieldName'];
$join_clause = '';
$condition_mode = 'WHERE';
// field processing
$options = $object->getFieldOptions($field);
$local_table = TABLE_PREFIX.$record['TableName'];
$weight_sum += $record['Priority']; // counting weight sum; used when making relevance clause
// processing multilingual fields
if (getArrayValue($options, 'formatter') == 'kMultiLanguage') {
$field_name = 'l'.$lang.'_'.$field;
}
else {
$field_name = $field;
}
// processing fields from other tables
if ($foreign_field = $record['ForeignField']) {
$exploded = explode(':', $foreign_field, 2);
if($exploded[0] == 'CALC')
{
$user_groups = $this->Application->RecallVar('UserGroups');
$field_name = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
$join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $record['JoinClause']);
$join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
$join_clause = ' LEFT JOIN '.$join_clause;
$condition_mode = 'HAVING';
}
else {
$exploded = explode('.', $foreign_field);
$foreign_table = TABLE_PREFIX.$exploded[0];
if($record['CustomFieldId']) {
$exploded[1] = 'l'.$lang.'_'.$exploded[1];
}
$alias_counter++;
$alias = 't'.$alias_counter;
$field_name = $alias.'.'.$exploded[1];
$join_clause = str_replace('{ForeignTable}', $alias, $record['JoinClause']);
$join_clause = str_replace('{LocalTable}', $product_table, $join_clause);
if($record['CustomFieldId'])
{
$join_clause .= ' AND '.$alias.'.CustomFieldId='.$record['CustomFieldId'];
}
$join_clause = ' LEFT JOIN '.$foreign_table.' '.$alias.'
ON '.$join_clause;
}
}
else
{
// processing fields from local table
if ($record['CustomFieldId']) {
$local_table = 'custom_data';
$field_name = 'l'.$lang.'_cust_'.array_search($field_name, $custom_fields);
}
$field_name = $local_table.'.'.$field_name;
}
$condition = '';
switch($record['FieldType'])
{
case 'text':
$keywords[$field] = unhtmlentities( $keywords[$field] );
if(strlen($keywords[$field]) >= $this->Application->ConfigValue('Search_MinKeyword_Length'))
{
$highlight_keywords[] = $keywords[$field];
if( in_array($verbs[$field], Array('any', 'contains', 'notcontains')) )
{
$keywords[$field] = '%'.strtr($keywords[$field], Array('%' => '\\%', '_' => '\\_')).'%';
}
$condition = sprintf( $condition_patterns[$verbs[$field]],
$field_name,
$this->Conn->qstr( $keywords[$field] ));
}
break;
case 'boolean':
if($keywords[$field] != -1)
{
$property_mappings = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
switch($field)
{
case 'HotItem':
$hot_limit_var = getArrayValue($property_mappings, 'HotLimit');
if($hot_limit_var)
{
$sql = 'SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName="'.$hot_limit_var.'"';
$hot_limit = (int)$this->Conn->GetOne($sql);
$condition = 'IF('.$product_table.'.HotItem = 2,
IF('.$product_table.'.Hits >= '.
$hot_limit.
', 1, 0), '.$product_table.'.HotItem) = '.$keywords[$field];
}
break;
case 'PopItem':
$votes2pop_var = getArrayValue($property_mappings, 'VotesToPop');
$rating2pop_var = getArrayValue($property_mappings, 'RatingToPop');
if($votes2pop_var && $rating2pop_var)
{
$condition = 'IF('.$product_table.'.PopItem = 2, IF('.$product_table.'.CachedVotesQty >= '.
$this->Application->ConfigValue($votes2pop_var).
' AND '.$product_table.'.CachedRating >= '.
$this->Application->ConfigValue($rating2pop_var).
', 1, 0), '.$product_table.'.PopItem) = '.$keywords[$field];
}
break;
case 'NewItem':
$new_days_var = getArrayValue($property_mappings, 'NewDays');
if($new_days_var)
{
$condition = 'IF('.$product_table.'.NewItem = 2,
IF('.$product_table.'.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue($new_days_var).
'*3600*24), 1, 0), '.$product_table.'.NewItem) = '.$keywords[$field];
}
break;
case 'EditorsPick':
$condition = $product_table.'.EditorsPick = '.$keywords[$field];
break;
}
}
break;
case 'range':
$range_conditions = Array();
if($keywords[$field.'_from'] && !preg_match("/[^0-9]/i", $keywords[$field.'_from']))
{
$range_conditions[] = $field_name.' >= '.$keywords[$field.'_from'];
}
if($keywords[$field.'_to'] && !preg_match("/[^0-9]/i", $keywords[$field.'_to']))
{
$range_conditions[] = $field_name.' <= '.$keywords[$field.'_to'];
}
if($range_conditions)
{
$condition = implode(' AND ', $range_conditions);
}
break;
case 'date':
if($keywords[$field])
{
if( in_array($keywords[$field], Array('today', 'yesterday')) )
{
$current_time = getdate();
$day_begin = adodb_mktime(0, 0, 0, $current_time['mon'], $current_time['mday'], $current_time['year']);
$time_mapping = Array('today' => $day_begin, 'yesterday' => ($day_begin - 86400));
$min_time = $time_mapping[$keywords[$field]];
}
else
{
$time_mapping = Array( 'last_week' => 604800, 'last_month' => 2628000,
'last_3_months' => 7884000, 'last_6_months' => 15768000,
'last_year' => 31536000
);
$min_time = adodb_mktime() - $time_mapping[$keywords[$field]];
}
$condition = $field_name.' > '.$min_time;
}
break;
}
if($condition)
{
if($join_clause)
{
$join_clauses[] = $join_clause;
}
$relevance_parts[] = 'IF('.$condition.', '.$record['Priority'].', 0)';
if($glues[$field] == 1) // and
{
if($condition_mode == 'WHERE')
{
$and_conditions[] = $condition;
}
else
{
$and_having_conditions[] = $condition;
}
}
else // or
{
if($condition_mode == 'WHERE')
{
$or_conditions[] = $condition;
}
else
{
$or_having_conditions[] = $condition;
}
}
// create search log record
$search_log_data = Array('search_config' => $record, 'verb' => getArrayValue($verbs, $field), 'value' => ($record['FieldType'] == 'range') ? $search_keywords[$field.'_from'].'|'.$search_keywords[$field.'_to'] : $search_keywords[$field]);
$search_log[] = $this->Application->Phrase('la_Field').' "'.$this->getHuman('Field', $search_log_data).'" '.$this->getHuman('Verb', $search_log_data).' '.$this->Application->Phrase('la_Value').' '.$this->getHuman('Value', $search_log_data).' '.$this->Application->Phrase($glues[$field] == 1 ? 'lu_And' : 'lu_Or');
}
}
$search_log = implode('<br />', $search_log);
$search_log = preg_replace('/(.*) '.preg_quote($this->Application->Phrase('lu_and'), '/').'|'.preg_quote($this->Application->Phrase('lu_or'), '/').'$/is', '\\1', $search_log);
$this->saveToSearchLog($search_log, 1); // advanced search
$this->Application->StoreVar('highlight_keywords', serialize($highlight_keywords));
// making relevance clause
if($relevance_parts)
{
$rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100;
$rel_pop = $this->Application->ConfigValue('SearchRel_Pop_products') / 100;
$rel_rating = $this->Application->ConfigValue('SearchRel_Rating_products') / 100;
$relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords;
$relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
$relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
}
else
{
$relevance_clause = '0';
}
// building having clause
if($or_having_conditions)
{
$and_having_conditions[] = '('.implode(' OR ', $or_having_conditions).')';
}
$having_clause = implode(' AND ', $and_having_conditions);
$having_clause = $having_clause ? ' HAVING '.$having_clause : '';
// building where clause
if($or_conditions)
{
$and_conditions[] = '('.implode(' OR ', $or_conditions).')';
}
// $and_conditions[] = $product_table.'.Status = 1';
$where_clause = implode(' AND ', $and_conditions);
if(!$where_clause)
{
if($having_clause)
{
$where_clause = '1';
}
else
{
$where_clause = '0';
$this->Application->SetVar('adv_search_error', 1);
}
}
$where_clause .= ' AND '.$product_table.'.Status = 1';
// building final search query
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
$sql = ' CREATE TABLE '.$search_table.'
SELECT '.$relevance_clause.' AS Relevance,
'.$product_table.'.ProductId AS ItemId,
'.$product_table.'.ResourceId AS ResourceId,
11 AS ItemType,
'.$product_table.'.EditorsPick AS EdPick
FROM '.$product_table.'
'.implode(' ', $join_clauses).'
WHERE '.$where_clause.'
GROUP BY '.$product_table.'.ProductId'.
$having_clause;
$res = $this->Conn->Query($sql);
}
function getHuman($type, $search_data)
{
$type = ucfirst(strtolower($type));
extract($search_data);
switch ($type) {
case 'Field':
return $this->Application->Phrase($search_config['DisplayName']);
break;
case 'Verb':
return $verb ? $this->Application->Phrase('lu_advsearch_'.$verb) : '';
break;
case 'Value':
switch ($search_config['FieldType']) {
case 'date':
$values = Array(0 => 'lu_comm_Any', 'today' => 'lu_comm_Today',
'yesterday' => 'lu_comm_Yesterday', 'last_week' => 'lu_comm_LastWeek',
'last_month' => 'lu_comm_LastMonth', 'last_3_months' => 'lu_comm_Last3Months',
'last_6_months' => 'lu_comm_Last6Months', 'last_year' => 'lu_comm_LastYear');
$ret = $this->Application->Phrase($values[$value]);
break;
case 'range':
$value = explode('|', $value);
return $this->Application->Phrase('lu_comm_From').' "'.$value[0].'" '.$this->Application->Phrase('lu_comm_To').' "'.$value[1].'"';
break;
case 'boolean':
$values = Array(1 => 'lu_comm_Yes', 0 => 'lu_comm_No', -1 => 'lu_comm_Both');
$ret = $this->Application->Phrase($values[$value]);
break;
case 'text':
$ret = $value;
break;
}
return '"'.$ret.'"';
break;
}
}
/**
* Set's correct page for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetPagination(&$event)
{
// get PerPage (forced -> session -> config -> 10)
$per_page = $this->getPerPage($event);
$object =& $event->getObject();
$object->SetPerPage($per_page);
$this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
$page = $this->Application->GetVar($event->getPrefixSpecial().'_Page');
if (!$page)
{
$page = $this->Application->GetVar($event->getPrefixSpecial(true).'_Page');
}
if (!$page)
{
if( $this->Application->RewriteURLs() )
{
$page = $this->Application->GetVar($event->Prefix.'_Page');
if (!$page)
{
$page = $this->Application->RecallVar($event->Prefix.'_Page');
}
if($page) $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
}
else
{
$page = $this->Application->RecallVar($event->getPrefixSpecial().'_Page');
}
}
else {
$this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
}
if( !$event->getEventParam('skip_counting') )
{
$pages = $object->GetTotalPages();
if($page > $pages)
{
$this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
$page = 1;
}
}
/*$cur_per_page = $per_page;
$per_page = $event->getEventParam('per_page');
if ($per_page == 'list_next') {
$cur_page = $page;
$object =& $this->Application->recallObject($event->Prefix);
$object->SetPerPage(1);
$cur_item_index = $object->CurrentIndex;
$page = ($cur_page-1) * $cur_per_page + $cur_item_index + 1;
$object->SetPerPage(1);
}*/
$object->SetPage($page);
}
/* === RELATED TO IMPORT/EXPORT: BEGIN === */
/**
* Shows export dialog
*
* @param kEvent $event
*/
function OnExport(&$event)
{
// use old fasion (in-portal) grid
$selector_name = $this->Application->getUnitOption($event->Prefix, 'CatalogSelectorName');
if ($selector_name) {
$selected_ids = $this->Application->GetVar($selector_name);
}
else {
$selected_ids = $this->StoreSelectedIDs($event);
if (implode(',', $selected_ids) == '') {
// K4 fix when no ids found bad selected ids array is formed
$selected_ids = false;
}
}
$selected_cats_ids = $this->Application->GetVar('export_categories');
$this->Application->StoreVar($event->Prefix.'_export_ids', $selected_ids ? implode(',', $selected_ids) : '' );
$this->Application->StoreVar($event->Prefix.'_export_cats_ids', $selected_cats_ids);
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
$event->redirect = $export_helper->getModuleFolder($event).'/export';
$redirect_params = Array( 'm_opener' => 'd',
$this->Prefix.'.export_event' => 'OnNew',
'pass' => 'all,'.$this->Prefix.'.export');
$event->setRedirectParams($redirect_params);
}
/**
* Performs each export step & displays progress percent
*
* @param kEvent $event
*/
function OnExportProgress(&$event)
{
$export_object =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_object kCatDBItemExportHelper */
$event = new kEvent($event->getPrefixSpecial().':OnDummy');
$action_method = 'perform'.ucfirst($event->Special);
$field_values = $export_object->$action_method($event);
// finish code is done from JS now
if ($field_values['start_from'] == $field_values['total_records']) {
if ($event->Special == 'import') {
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
$this->Application->Redirect('in-portal/categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1, 'no_amp' => 1));
}
elseif ($event->Special == 'export') {
$template = $this->Application->getUnitOption($event->Prefix, 'ModuleFolder').'/'.$event->Special.'_finish';
$this->Application->Redirect($template, Array('pass' => 'all'));
}
}
$export_options = $export_object->loadOptions($event);
echo $export_options['start_from'] * 100 / $export_options['total_records'];
$event->status = erSTOP;
}
/**
* Returns specific to each item type columns only
*
* @param kEvent $event
* @return Array
*/
function getCustomExportColumns(&$event)
{
return Array( '__VIRTUAL__ThumbnailImage' => 'ThumbnailImage',
'__VIRTUAL__FullImage' => 'FullImage',
'__VIRTUAL__ImageAlt' => 'ImageAlt');
}
/**
* Sets non standart virtual fields (e.g. to other tables)
*
* @param kEvent $event
*/
function setCustomExportColumns(&$event)
{
$this->restorePrimaryImage($event);
}
/**
* Create/Update primary image record in info found in imported data
*
* @param kEvent $event
*/
function restorePrimaryImage(&$event)
{
$object =& $event->getObject();
$has_image_info = $object->GetDBField('ImageAlt') && ($object->GetDBField('ThumbnailImage') || $object->GetDBField('FullImage'));
if (!$has_image_info) {
return false;
}
$image_data = $object->getPrimaryImageData();
$image =& $this->Application->recallObject('img', null, Array('skip_autoload' => true));
if ($image_data) {
$image->Load($image_data['ImageId']);
}
else {
$image->Clear();
$image->SetDBField('Name', 'main');
$image->SetDBField('DefaultImg', 1);
$image->SetDBField('ResourceId', $object->GetDBField('ResourceId'));
}
$image->SetDBField('AltName', $object->GetDBField('ImageAlt'));
if ($object->GetDBField('ThumbnailImage')) {
$thumbnail_field = $this->isURL( $object->GetDBField('ThumbnailImage') ) ? 'ThumbUrl' : 'ThumbPath';
$image->SetDBField($thumbnail_field, $object->GetDBField('ThumbnailImage') );
$image->SetDBField('LocalThumb', $thumbnail_field == 'ThumbPath' ? 1 : 0);
}
if (!$object->GetDBField('FullImage')) {
$image->SetDBField('SameImages', 1);
}
else {
$image->SetDBField('SameImages', 0);
$full_field = $this->isURL( $object->GetDBField('FullImage') ) ? 'Url' : 'LocalPath';
$image->SetDBField($full_field, $object->GetDBField('FullImage') );
$image->SetDBField('LocalImage', $full_field == 'LocalPath' ? 1 : 0);
}
if ($image->isLoaded()) {
$image->Update();
}
else {
$image->Create();
}
}
function isURL($path)
{
return preg_match('#(http|https)://(.*)#', $path);
}
/**
* Prepares item for import/export operations
*
* @param kEvent $event
*/
function OnNew(&$event)
{
parent::OnNew($event);
if ($event->Special == 'import' || $event->Special == 'export') {
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
$export_helper->setRequiredFields($event);
$this->Application->StoreVar('ImportCategory', 0);
}
}
/**
* Process items selected in item_selector
*
* @param kEvent $event
*/
function OnProcessSelected(&$event)
{
$selected_ids = $this->Application->GetVar('selected_ids');
$dst_field = $this->Application->RecallVar('dst_field');
if ($dst_field == 'ItemCategory') {
// Item Edit -> Categories Tab -> New Categories
$object =& $event->getObject();
$category_ids = explode(',', $selected_ids['c']);
foreach ($category_ids as $category_id) {
$object->assignToCategory($category_id);
}
}
if ($dst_field == 'ImportCategory') {
// Tools -> Import -> Item Import -> Select Import Category
$this->Application->StoreVar('ImportCategory', $selected_ids['c']);
// $this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 1); // not to loose import/export values on form refresh
$this->Application->SetVar($event->getPrefixSpecial().'_id', 0);
$this->Application->SetVar($event->getPrefixSpecial().'_event', 'OnExportBegin');
$passed = $this->Application->GetVar('passed');
$this->Application->SetVar('passed', $passed.','.$event->getPrefixSpecial());
$event->setEventParam('pass_events', true);
}
$this->finalizePopup($event);
}
/**
* Saves Import/Export settings to session
*
* @param kEvent $event
*/
function OnSaveSettings(&$event)
{
$event->redirect = false;
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
list($id, $field_values) = each($items_info);
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->SetFieldsFromHash($field_values);
$field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
$field_values['ImportSource'] = 2;
$field_values['ImportLocalFilename'] = $object->GetDBField('ImportFilename');
$items_info[$id] = $field_values;
$this->Application->StoreVar($event->getPrefixSpecial().'_ItemsInfo', serialize($items_info));
}
}
function OnCancelAction(&$event)
{
$event->redirect_params = Array('pass' => 'all,'.$event->GetPrefixSpecial());
$event->redirect = $this->Application->GetVar('cancel_template');
}
/* === RELATED TO IMPORT/EXPORT: END === */
/**
* Stores item's owner login into separate field together with id
*
* @param kEvent $event
* @param string $id_field
* @param string $cached_field
*/
function cacheItemOwner(&$event, $id_field, $cached_field)
{
$object =& $event->getObject();
$user_id = $object->GetDBField($id_field);
$options = $object->GetFieldOptions($id_field);
if (isset($options['options'][$user_id])) {
$object->SetDBField($cached_field, $options['options'][$user_id]);
}
else {
$id_field = $this->Application->getUnitOption('u', 'IDField');
$table_name = $this->Application->getUnitOption('u', 'TableName');
$sql = 'SELECT Login
FROM '.$table_name.'
WHERE '.$id_field.' = '.$user_id;
$object->SetDBField($cached_field, $this->Conn->GetOne($sql));
}
}
/**
* Saves item beeing edited into temp table
*
* @param kEvent $event
*/
function OnPreSave(&$event)
{
parent::OnPreSave($event);
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ($event->status == erSUCCESS && $use_pending_editing) {
// decision: clone or not clone
$object =& $event->getObject();
if ($object->GetID() == 0 || $object->GetDBField('OrgId') > 0) {
// new items or cloned items shouldn't be cloned again
return true;
}
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
$owner_field = $this->getOwnerField($event->Prefix);
if ($perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix) == 2) {
// 1. clone original item
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($object->GetID()), null, null, null, true);
$ci_table = $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems');
// 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
$sql = 'SELECT ResourceId
FROM '.$object->TableName.'
WHERE '.$object->IDField.' = '.$cloned_ids[0];
$clone_resource_id = $this->Conn->GetOne($sql);
$sql = 'DELETE FROM '.$ci_table.'
WHERE ItemResourceId = '.$clone_resource_id.' AND PrimaryCat = 1';
$this->Conn->Query($sql);
// 3. copy main item categoryitems to cloned item
$sql = ' INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
SELECT CategoryId, '.$clone_resource_id.' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
FROM '.$ci_table.'
WHERE ItemResourceId = '.$object->GetDBField('ResourceId');
$this->Conn->Query($sql);
// 4. put cloned id to OrgId field of item being cloned
$sql = 'UPDATE '.$object->TableName.'
SET OrgId = '.$object->GetID().'
WHERE '.$object->IDField.' = '.$cloned_ids[0];
$this->Conn->Query($sql);
// 5. substitute id of item being cloned with clone id
$this->Application->SetVar($event->getPrefixSpecial().'_id', $cloned_ids[0]);
$selected_ids = $this->getSelectedIDs($event, true);
$selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0];
$this->StoreSelectedIDs($event, $selected_ids);
// 6. delete original item from temp table
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array($object->GetID()));
}
}
}
/**
* Sets default expiration based on module setting
*
* @param kEvent $event
*/
function OnPreCreate(&$event)
{
parent::OnPreCreate($event);
if ($event->status == erSUCCESS) {
$object =& $event->getObject();
$owner_field = $this->getOwnerField($event->Prefix);
$object->SetDBField($owner_field, $this->Application->RecallVar('user_id'));
}
}
/**
* Occures before original item of item in pending editing got deleted (for hooking only)
*
* @param kEvent $event
*/
function OnBeforeDeleteOriginal(&$event)
{
}
/**
* Occures before an item is cloneded
* Id of ORIGINAL item is passed as event' 'id' param
* Do not call object' Update method in this event, just set needed fields!
*
* @param kEvent $event
*/
function OnBeforeClone(&$event)
{
if ($this->Application->GetVar('ResetCatBeforeClone')) {
$object =& $event->getObject();
$object->SetDBField('CategoryId', null);
}
}
/**
* Set status for new category item based on user permission in category
*
* @param kEvent $event
*/
function OnBeforeItemCreate(&$event)
{
if ($this->Application->IsAdmin()) {
return true;
}
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ($use_pending_editing) {
$object =& $event->getObject();
/* @var $object kDBItem */
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$primary_category = $object->GetDBField('CategoryId') > 0 ? $object->GetDBField('CategoryId') : $this->Application->GetVar('m_cat_id');
$item_status = $perm_helper->AddCheckPermission($primary_category, $event->Prefix);
if ($item_status == STATUS_DISABLED) {
$event->status = erFAIL;
return false;
}
else {
$object->SetDBField('Status', $item_status);
}
}
}
/**
* Creates category item & redirects to confirmation template (front-end only)
*
* @param kEvent $event
*/
function OnCreate(&$event)
{
parent::OnCreate($event);
$this->SetFrontRedirectTemplate($event, 'suggest');
}
- /**
+ /**
+ * Returns item's categories (allows to exclude primary category)
+ *
+ * @param int $resource_id
+ * @param bool $with_primary
+ * @return Array
+ */
+ function getItemCategories($resource_id, $with_primary = false)
+ {
+ $sql = 'SELECT CategoryId
+ FROM '.TABLE_PREFIX.'CategoryItems
+ WHERE (ItemResourceId = '.$resource_id.')';
+
+ if (!$with_primary) {
+ $sql .= ' AND (PrimaryCat = 0)';
+ }
+
+ return $this->Conn->GetCol($sql);
+ }
+
+ /**
+ * Adds new and removes old additional categories from category item
+ *
+ * @param kCatDBItem $object
+ */
+ function processAdditionalCategories(&$object, $mode)
+ {
+ $process_categories = $object->GetDBField('MoreCategories');
+ if ($process_categories === '') {
+ // field was not in submit & have default value (when no categories submitted, then value is null)
+ return ;
+ }
+
+ if ($mode == 'create') {
+ // prevents first additional category to become primary
+ $object->assignPrimaryCategory();
+ }
+
+ $process_categories = $process_categories ? explode('|', substr($process_categories, 1, -1)) : Array ();
+ $existing_categories = $this->getItemCategories($object->GetDBField('ResourceId'));
+
+ $add_categories = array_diff($process_categories, $existing_categories);
+ foreach ($add_categories as $category_id) {
+ $object->assignToCategory($category_id);
+ }
+
+ $remove_categories = array_diff($existing_categories, $process_categories);
+ foreach ($remove_categories as $category_id) {
+ $object->removeFromCategory($category_id);
+ }
+ }
+
+ /**
* Creates category item & redirects to confirmation template (front-end only)
*
* @param kEvent $event
*/
function OnUpdate(&$event)
{
$use_pending = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ($this->Application->IsAdmin() || !$use_pending) {
parent::OnUpdate($event);
$this->SetFrontRedirectTemplate($event, 'modify');
return ;
}
$object =& $event->getObject(Array('skip_autoload' => true));
/* @var $object kCatDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$owner_field = $this->getOwnerField($event->Prefix);
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
foreach ($items_info as $id => $field_values) {
$object->Load($id);
$edit_perm = $perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix);
- if ($use_pending && !$object->GetDBField('OrgId') && ($edit_perm == STATUS_PENDING)) {
+ if ($use_pending && !$object->GetDBField('OrgId') && ($edit_perm == STATUS_PENDING)) {
// pending editing enabled + not pending copy -> get/create pending copy & save changes to it
$original_id = $object->GetID();
$original_resource_id = $object->GetDBField('ResourceId');
$image_helper->PreserveItemImages($field_values);
$object->Load($original_id, 'OrgId');
if (!$object->isLoaded()) {
// 1. user has no pending copy of live item -> clone live item
$cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($original_id), null, null, null, true);
$object->Load($cloned_ids[0]);
$object->SetFieldsFromHash($field_values);
// 1a. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
$sql = 'DELETE FROM '.$ci_table.'
WHERE ItemResourceId = '.$object->GetDBField('ResourceId').' AND PrimaryCat = 1';
$this->Conn->Query($sql);
// 1b. copy main item categoryitems to cloned item
$sql = 'INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
SELECT CategoryId, '.$object->GetDBField('ResourceId').' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
FROM '.$ci_table.'
WHERE ItemResourceId = '.$original_resource_id;
$this->Conn->Query($sql);
// 1c. put cloned id to OrgId field of item being cloned
$object->SetDBField('Status', STATUS_PENDING_EDITING);
$object->SetDBField('OrgId', $original_id);
}
else {
// 2. user has pending copy of live item -> just update field values
$object->SetFieldsFromHash($field_values);
}
// update id in request (used for redirect in mod-rewrite mode)
$this->Application->SetVar($event->getPrefixSpecial().'_id', $object->GetID());
- }
- else {
- // 3. already editing pending copy -> just update field values
- $object->SetFieldsFromHash($field_values);
- }
+ }
+ else {
+ // 3. already editing pending copy -> just update field values
+ $object->SetFieldsFromHash($field_values);
+ }
if ($object->Update()) {
$event->status = erSUCCESS;
}
else {
$event->status = erFAIL;
$event->redirect = false;
break;
}
}
}
$this->SetFrontRedirectTemplate($event, 'modify');
}
/**
* Sets next template to one required for front-end after adding/modifying item
*
* @param kEvent $event
* @param string $template_key - {suggest,modify}
*/
function SetFrontRedirectTemplate(&$event, $template_key)
{
if ($this->Application->IsAdmin() || $event->status != erSUCCESS) {
return ;
}
// prepare redirect template
$object =& $event->getObject();
$is_active = ($object->GetDBField('Status') == STATUS_ACTIVE);
$next_template = $is_active ? 'confirm_template' : 'pending_confirm_template';
$event->redirect = $this->Application->GetVar($template_key.'_'.$next_template);
$event->SetRedirectParam('opener', 's');
// send email events
$perm_prefix = $this->Application->getUnitOption($event->Prefix, 'PermItemPrefix');
switch ($event->Name) {
case 'OnCreate':
$event_suffix = $is_active ? 'ADD' : 'ADD.PENDING';
$owner_field = $this->getOwnerField($event->Prefix);
$this->Application->EmailEventAdmin($perm_prefix.'.'.$event_suffix); // there are no ADD.PENDING event for admin :(
$this->Application->EmailEventUser($perm_prefix.'.'.$event_suffix, $object->GetDBField($owner_field));
break;
case 'OnUpdate':
$event_suffix = $is_active ? 'MODIFY' : 'MODIFY.PENDING';
$this->Application->EmailEventAdmin($perm_prefix.'.'.$event_suffix); // there are no ADD.PENDING event for admin :(
$this->Application->EmailEventUser($perm_prefix.'.'.$event_suffix, $object->GetDBField('ModifiedById'));
break;
}
}
/**
* Apply same processing to each item beeing selected in grid
*
* @param kEvent $event
* @access private
*/
function iterateItems(&$event)
{
if ($event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline') {
return parent::iterateItems($event);
}
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
foreach ($ids as $id) {
$object->Load($id);
switch ($event->Name) {
case 'OnMassApprove':
$ret = $object->ApproveChanges();
break;
case 'OnMassDecline':
$ret = $object->DeclineChanges();
break;
}
if (!$ret) {
$event->status = erFAIL;
$event->redirect = false;
break;
}
}
}
$this->clearSelectedIDs($event);
}
/**
* Deletes items & preserves clean env
*
* @param kEvent $event
*/
function OnDelete(&$event)
{
parent::OnDelete($event);
if ($event->status == erSUCCESS && !$this->Application->IsAdmin()) {
$event->SetRedirectParam('pass', 'm');
$event->SetRedirectParam('m_cat_id', 0);
}
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
*/
function checkItemStatus(&$event)
{
$object =& $event->getObject();
if (!$object->isLoaded()) {
return true;
}
$status = $object->GetDBField('Status');
$user_id = $this->Application->RecallVar('user_id');
$owner_field = $this->getOwnerField($event->Prefix);
if (($status == -2 || $status == STATUS_PENDING) && ($object->GetDBField($owner_field) == $user_id)) {
return true;
}
return $status == STATUS_ACTIVE;
}
/**
* Set sorting directly to session
*
* @param kEvent $event
*/
function OnSetSortingDirect(&$event)
{
$combined = $this->Application->GetVar($event->Prefix.'_CombinedSorting');
if ($combined) {
list($field, $dir) = explode('|', $combined);
$this->Application->StoreVar($event->Prefix.'_Sort1', $field);
$this->Application->StoreVar($event->Prefix.'_Sort1_Dir', $dir);
return ;
}
$field_pos = $this->Application->GetVar($event->Prefix.'_SortPos');
$this->Application->LinkVar($event->Prefix.'_Sort'.$field_pos, $event->Prefix.'_Sort'.$field_pos);
$this->Application->LinkVar($event->Prefix.'_Sort'.$field_pos.'_Dir', $event->Prefix.'_Sort'.$field_pos.'_Dir');
}
/**
* Set's correct sorting for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetSorting(&$event)
{
if (!$this->Application->IsAdmin()) {
$event->setEventParam('same_special', true);
}
parent::SetSorting($event);
}
/**
* Returns current per-page setting for list
*
* @param kEvent $event
* @return int
*/
function getPerPage(&$event)
{
if (!$this->Application->IsAdmin()) {
$event->setEventParam('same_special', true);
}
return parent::getPerPage($event);
}
function getOwnerField($prefix)
{
$owner_field = $this->Application->getUnitOption($prefix, 'OwnerField');
if (!$owner_field) {
$owner_field = 'CreatedById';
}
return $owner_field;
}
/**
* Creates virtual image fields for item
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$image_helper->createItemImages($event->Prefix);
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/cat_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.97.2.1
\ No newline at end of property
+1.97.2.2
\ No newline at end of property
Index: branches/RC/core/admin_templates/js/ajax.js
===================================================================
--- branches/RC/core/admin_templates/js/ajax.js (revision 9020)
+++ branches/RC/core/admin_templates/js/ajax.js (revision 9021)
@@ -1,325 +1,325 @@
function preg_print_pre(obj, reg)
{
if (!reg) reg = /.*/;
var p = ''
for (var prop in obj) {
if (prop.match(reg) ) {
p += prop + ': '+obj[prop] + '\n'
}
}
alert(p)
}
// Main AJAX classs
function Request() {}
Request.timeout = 60000; //60 seconds
Request.method = 'GET';
Request.headers = new Array();
Request.params = null;
Request.makeRequest = function(p_url, p_busyReq, p_progId, p_successCallBack, p_errorCallBack, p_pass, p_object) {
//p_url: the web service url
//p_busyReq: is a request for this object currently in progress?
//p_progId: element id where progress HTML should be shown
//p_successCallBack: callback function for successful response
//p_errorCallBack: callback function for erroneous response
//p_pass: string of params to pass to callback functions
//p_object: object of params to pass to callback functions
if (p_busyReq) return;
var req = Request.getRequest();
if (req != null) {
p_busyReq = true;
Request.showProgress(p_progId);
req.onreadystatechange = function() {
if (req.readyState == 4) {
p_busyReq = false;
window.clearTimeout(toId);
try {
if (req.status == 200) {
// preg_print_pre(req)
p_successCallBack(req, p_pass, p_object);
} else {
p_errorCallBack(req, p_pass, p_object);
}
Request.hideProgress(p_progId);
}
catch (e) {
// alert('AJAX error')
}
}
}
var $ajax_mark = (p_url.indexOf('?') ? '&' : '?') + 'ajax=yes';
req.open(Request.method, p_url + $ajax_mark, true);
if (Request.method == 'POST') {
Request.headers['Content-type'] = 'application/x-www-form-urlencoded';
Request.headers['referer'] = p_url;
}
else {
Request.headers['If-Modified-Since'] = 'Sat, 1 Jan 2000 00:00:00 GMT';
}
Request.sendHeaders(req);
if (Request.method == 'POST') {
req.send(Request.params);
Request.method = 'GET'; // restore method back to GET
}
else {
req.send(null);
}
var toId = window.setTimeout( function() {if (p_busyReq) req.abort();}, Request.timeout );
}
}
Request.sendHeaders = function($request) {
for (var $header_name in Request.headers) {
$request.setRequestHeader($header_name, Request.headers[$header_name]);
}
Request.headers = new Array(); // reset header afterwards
}
Request.getRequest = function() {
var xmlHttp;
try { xmlHttp = new ActiveXObject('MSXML2.XMLHTTP'); return xmlHttp; } catch (e) {}
try { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); return xmlHttp; } catch (e) {}
try { xmlHttp = new XMLHttpRequest(); return xmlHttp; } catch(e) {}
return null;
}
Request.showProgress = function(p_id) {
if (p_id != '') {
Request.setOpacity(20, p_id);
if (!document.getElementById(p_id + '_progress')) {
document.body.appendChild(Request.getProgressObject(p_id));
}
else {
var $progress_div = document.getElementById(p_id + '_progress');
$progress_div.style.top = getRealTop(p_id) + 'px';
$progress_div.style.height = document.getElementById(p_id).clientHeight;
$progress_div.style.display = 'block';
}
// document.getElementById(p_id).innerHTML = Request.getProgressHtml();
}
}
Request.hideProgress = function(p_id) {
if (p_id != '') {
document.getElementById(p_id + '_progress').style.display = 'none';
Request.setOpacity(100, p_id);
}
}
Request.setOpacity = function (opacity, id) {
var elem = typeof(id)=='string' ? document.getElementById(id) : id;
var object = elem.style;
object.opacity = (opacity / 100);
object.MozOpacity = (opacity / 100);
object.KhtmlOpacity = (opacity / 100);
object.filter = "alpha(opacity=" + opacity + ")";
}
Request.getProgressHtml = function() {
return "<p class='progress'>" + Request.progressText + "<br /><img src='img/ajax_progress.gif' align='absmiddle' width='100' height='7' alt='" + Request.progressText + "'/></p>";
}
Request.getProgressObject = function($id) {
var $div = document.createElement('DIV');
var $parent_div = document.getElementById($id);
$div.id = $id + '_progress';
$div.style.width = $parent_div.clientWidth + 'px';
$div.style.height = '150px'; // default height if div is empty (first ajax request for div)
$div.style.left = getRealLeft($parent_div) + 'px';
$div.style.top = getRealTop($parent_div) + 'px';
$div.style.position = 'absolute';
/*$div.style.border = '1px solid green';
$div.style.backgroundColor = '#FF0000';*/
$div.innerHTML = '<table style="width: 100%; height: 100%;"><tr><td style="text-align: center;">'+Request.progressText+'<br /><img src="img/ajax_progress.gif" align="absmiddle" width="100" height="7" alt="'+escape(Request.progressText)+'" /></td></tr></table>';
return $div;
}
Request.getErrorHtml = function(p_req) {
//TODO: implement accepted way to handle request error
return '[status: ' + p_req.status + '; status_text: ' + p_req.statusText + '; responce_text: ' + p_req.responseText + ']';
}
Request.serializeForm = function(theform) {
if (typeof(theform) == 'string') {
theform = document.getElementById(theform);
}
var els = theform.elements;
var len = els.length;
var queryString = '';
Request.addField = function(name, value) {
if (queryString.length > 0) queryString += '&';
queryString += encodeURIComponent(name) + '=' + encodeURIComponent(value);
};
for (var i = 0; i<len; i++) {
var el = els[i];
if (el.disabled) continue;
switch(el.type) {
case 'text':
case 'password':
case 'hidden':
case 'textarea':
Request.addField(el.name, el.value);
break;
case 'select-one':
if (el.selectedIndex >= 0) {
Request.addField(el.name, el.options[el.selectedIndex].value);
}
break;
case 'select-multiple':
for (var j = 0; j < el.options.length; j++) {
if (!el.options[j].selected) continue;
Request.addField(el.name, el.options[j].value);
}
break;
case 'checkbox':
case 'radio':
if (!el.checked) continue;
Request.addField(el.name,el.value);
break;
}
}
return queryString;
};
-// AJAX ProgressBar classs
+// AJAX ProgressBar class
function AjaxProgressBar($url) {
this.WindowTitle = this.GetWindow().document.title;
this.URL = $url;
this.BusyRequest = false;
this.LastResponceTime = this.GetMicroTime();
this.ProgressPercent = 0; // progress percent
this.ProgressTime = new Array();
this.Query();
}
AjaxProgressBar.prototype.GetWindow = function() {
return window.parent ? window.parent : window;
}
AjaxProgressBar.prototype.GetMicroTime = function() {
var $now = new Date();
return Math.round($now.getTime() / 1000); // because miliseconds are returned too
}
AjaxProgressBar.prototype.Query = function() {
// prompt('requestinng', this.URL);
Request.makeRequest(this.URL, this.BusyRequest, '', this.successCallback, this.errorCallback, '', this);
}
// return time needed for progress to finish
AjaxProgressBar.prototype.GetEstimatedTime = function() {
return Math.ceil((100 - this.ProgressPercent) * Math.sum(this.ProgressTime) / this.ProgressPercent);
}
AjaxProgressBar.prototype.successCallback = function($request, $params, $object) {
var $responce = $request.responseText;
var $match_redirect = new RegExp('^#redirect#(.*)').exec($responce);
if ($match_redirect != null) {
$object.showProgress(100);
// redirect to external template requested
window.location.href = $match_redirect[1];
return false;
}
if ($object.showProgress($responce)) {
$object.Query();
}
}
AjaxProgressBar.prototype.errorCallback = function($request, $params, $object) {
alert('AJAX Error; class: AjaxProgressBar; ' + Request.getErrorHtml($request));
}
AjaxProgressBar.prototype.FormatTime = function ($seconds) {
$seconds = parseInt($seconds);
var $minutes = Math.floor($seconds / 60);
if ($minutes < 10) $minutes = '0' + $minutes;
$seconds = $seconds % 60;
if ($seconds < 10) $seconds = '0' + $seconds;
return $minutes + ':' + $seconds;
}
AjaxProgressBar.prototype.showProgress = function ($percent) {
this.ProgressPercent = $percent;
var $now = this.GetMicroTime();
this.ProgressTime[this.ProgressTime.length] = $now - this.LastResponceTime;
this.LastResponceTime = $now;
var $display_progress = parseInt(this.ProgressPercent);
this.GetWindow().document.title = $display_progress + '% - ' + this.WindowTitle;
document.getElementById('progress_display[percents_completed]').innerHTML = $display_progress + '%';
document.getElementById('progress_display[elapsed_time]').innerHTML = this.FormatTime( Math.sum(this.ProgressTime) );
document.getElementById('progress_display[Estimated_time]').innerHTML = this.FormatTime( this.GetEstimatedTime() );
document.getElementById('progress_bar[done]').style.width = $display_progress + '%';
document.getElementById('progress_bar[left]').style.width = (100 - $display_progress) + '%';
return $percent < 100 ? true : false;
}
// AJAX PopupManager class
function AjaxPopupManager($url) {
this.URL = $url;
this.ResponceFunction = null;
this.PopupSizes = new Array();
}
AjaxPopupManager.prototype.GetSize = function ($template) {
if (this.ResponceFunction == null) {
alert ('Please define responce function first (type: '+typeof(this.ResponceFunction)+')');
}
if (!isset(this.PopupSizes[$template])) {
var $url = this.URL + '&type=GetPopupSize&template_name=' + $template;
// alert('from ajax: '+$url);
Request.makeRequest($url, this.BusyRequest, '', this.successCallback, this.errorCallback, ['GetSize', $template], this);
}
else {
// alert('from cache');
this.ResponceFunction(this.PopupSizes[$template]);
}
}
AjaxPopupManager.prototype.successCallback = function($request, $params, $object) {
var $responce = $request.responseText;
var $match_redirect = new RegExp('^#redirect#(.*)').exec($responce);
if ($match_redirect != null) {
// redirect to external template requested
window.location.href = $match_redirect[1];
return false;
}
switch ($params[0]) {
case 'GetSize':
// store responce to cache for future use
$object.PopupSizes[ $params[1] ] = $responce;
break;
}
$object.ResponceFunction($responce);
$object.ResponceFunction = null; // reset responce function
}
AjaxPopupManager.prototype.errorCallback = function($request, $params, $object) {
alert('AJAX Error; class: AjaxPopupManager; ' + Request.getErrorHtml($request));
}
\ No newline at end of file
Property changes on: branches/RC/core/admin_templates/js/ajax.js
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.6
\ No newline at end of property
+1.6.2.1
\ No newline at end of property
Event Timeline
Log In to Comment