diff --git a/admin/code/CMSBatchAction.php b/admin/code/CMSBatchAction.php index 1e190ca6d..25d04229f 100644 --- a/admin/code/CMSBatchAction.php +++ b/admin/code/CMSBatchAction.php @@ -27,7 +27,38 @@ abstract class CMSBatchAction extends Object { * Return a set of status-updated JavaScript to return to the CMS. */ abstract function run(SS_List $objs); - + + /** + * Helper method for responding to a back action request + * @param $successMessage string - The message to return as a notification. + * Can have up to two %d's in it. The first will be replaced by the number of successful + * changes, the second by the number of failures + * @param $status array - A status array like batchactions builds. Should be + * key => value pairs, the key can be any string: "error" indicates errors, anything + * else indicates a type of success. The value is an array. We don't care what's in it, + * we just use count($value) to find the number of items that succeeded or failed + */ + public function response($successMessage, $status) { + $count = 0; + $errors = 0; + + foreach($status as $k => $v) { + if ($k == 'errors') $errors = count($v); + else $count += count($v); + } + + $response = Controller::curr()->getResponse(); + + if($response) { + $response->setStatusCode( + 200, + sprintf($successMessage, $count, $errors) + ); + } + + return Convert::raw2json($status); + } + /** * Helper method for processing batch actions. * Returns a set of status-updating JavaScript to return to the CMS. @@ -67,15 +98,7 @@ abstract class CMSBatchAction extends Object { unset($obj); } - $response = Controller::curr()->getResponse(); - if($response) { - $response->setStatusCode( - 200, - sprintf($successMessage, $objs->Count(), count($status['error'])) - ); - } - - return Convert::raw2json($status); + return $this->response($successMessage, $status); } diff --git a/admin/css/screen.css b/admin/css/screen.css index 9e4992e1f..afb983def 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -545,10 +545,14 @@ body.cms-dialog { overflow: auto; background: url("../images/textures/bg_cms_mai /** -------------------------------------------- "Insert X" forms -------------------------------------------- */ .htmleditorfield-dialog.ui-dialog-content { padding: 0; position: relative; } .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb .CompositeField { overflow: hidden; *zoom: 1; } -.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb #RemoteURL { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; width: 55%; float: left; } +.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb #RemoteURL { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; width: 55%; float: left; position: relative; } +.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb #RemoteURL label { position: absolute; left: 8px; top: 0px; font-weight: normal; color: #888; } +.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb #RemoteURL .middleColumn { margin-left: 0; } +.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb #RemoteURL input.remoteurl { padding-left: 40px; } .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url { padding-top: 15px; overflow: hidden; *zoom: 1; border: none; background: none; opacity: 0.8; cursor: hand; } .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url .btn-icon-addMedia { width: 20px; height: 20px; } .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url:hover, .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url:active { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; opacity: 1; } +.htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url.ui-state-disabled, .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url.ui-state-disabled:hover, .htmleditorfield-dialog #MediaFormInsertMediaTabs_Fromtheweb button.add-url.ui-state-disabled:active { opacity: 0.35; filter: Alpha(Opacity=35); } .htmleditorfield-dialog .cms-content-header { padding: 0; width: 100%; height: 40px; } .htmleditorfield-dialog .cms-content-header h3 { padding: 0 8px; margin: 10px; } .htmleditorfield-dialog .ui-tabs { position: static; } diff --git a/admin/javascript/LeftAndMain.Tree.js b/admin/javascript/LeftAndMain.Tree.js index bf23fd084..f9ffdde84 100644 --- a/admin/javascript/LeftAndMain.Tree.js +++ b/admin/javascript/LeftAndMain.Tree.js @@ -102,7 +102,7 @@ }); }) // Make some jstree events delegatable - .bind('select_node.jstree check_node.jstree', function(e, data) { + .bind('select_node.jstree check_node.jstree uncheck_node.jstree', function(e, data) { $(document).triggerHandler(e, data); }) }, diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index 4e37fcaed..8db3ff5d9 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -1449,6 +1449,22 @@ body.cms-dialog { @include box-shadow-none; width:55%; float:left; + position: relative; + + label { + position: absolute; + left: 8px; + top: 0px; + font-weight: normal; color: #888; + } + + .middleColumn { + margin-left: 0; + } + + input.remoteurl { + padding-left: 40px; + } } button.add-url{ padding-top:15px; @@ -1466,6 +1482,12 @@ body.cms-dialog { @include box-shadow-none; opacity:1; } + &.ui-state-disabled { + &, &:hover, &:active { + opacity: 0.35; + filter: Alpha(Opacity=35); + } + } } } diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index cc7a1778f..90be1f668 100644 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -392,7 +392,7 @@ class HtmlEditorField_Toolbar extends RequestHandler { $fromWeb = new CompositeField( new LiteralField('headerURL', '

' . sprintf($numericLabelTmpl, '1', _t('HtmlEditorField.ADDURL', 'Add URL')) . '

'), - $remoteURL = new TextField('RemoteURL', ''), + $remoteURL = new TextField('RemoteURL', 'http://'), new LiteralField('addURLImage', '') ); $remoteURL->addExtraClass('remoteurl'); diff --git a/javascript/HtmlEditorField.js b/javascript/HtmlEditorField.js index 6c3b59e14..53bf85985 100644 --- a/javascript/HtmlEditorField.js +++ b/javascript/HtmlEditorField.js @@ -871,17 +871,51 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE; }); + $('form.htmleditorfield-form.htmleditorfield-mediaform input.remoteurl').entwine({ + onadd: function() { + this.validate(); + }, + + onkeyup: function() { + this.validate(); + }, + + onchange: function() { + this.validate(); + }, + + getAddButton: function() { + return this.closest('.CompositeField').find('button.add-url'); + }, + + validate: function() { + var val = this.val(), orig = val; + + val = val.replace(/^https?:\/\//i, ''); + if (orig !== val) this.val(val); + + this.getAddButton().button(!!val ? 'enable' : 'disable'); + return !!val; + } + }); + /** * Show the second step after adding a URL */ $('form.htmleditorfield-form.htmleditorfield-mediaform .add-url').entwine({ + getURLField: function() { + return this.closest('.CompositeField').find('input.remoteurl'); + }, + onclick: function(e) { - var form = this.closest('form'); + var urlField = this.getURLField(); - var urlField = this.closest('.CompositeField').find('input.remoteurl'); + if (urlField.validate()) { + var form = this.closest('form'); + form.showFileView('http://' + urlField.val()); + form.redraw(); + } - form.showFileView(urlField.val()); - form.redraw(); return false; } }); diff --git a/model/DataQuery.php b/model/DataQuery.php index 8d2a4be36..e220961a8 100644 --- a/model/DataQuery.php +++ b/model/DataQuery.php @@ -461,7 +461,7 @@ function max($field) { function whereAny($filter) { if($filter) { $clone = $this; - $clone->query->whereAny($filter); + $clone->query->addWhereAny($filter); return $clone; } else { return $this; diff --git a/model/SQLQuery.php b/model/SQLQuery.php index 3808fecbd..daf9e0ad0 100644 --- a/model/SQLQuery.php +++ b/model/SQLQuery.php @@ -738,14 +738,28 @@ class SQLQuery { return $this->setWhere($where); } + public function whereAny($where) { + Deprecation::notice('3.0', 'Please use setWhereAny() or setWhereAny() instead!'); + return $this->setWhereAny($where); + } + /** * @param String|array $filters Predicate(s) to set, as escaped SQL statements. */ - function whereAny($filters) { + function setWhereAny($filters) { if(is_string($filters)) $filters = func_get_args(); $clause = implode(" OR ", $filters); return $this->setWhere($clause); } + + /** + * @param String|array $filters Predicate(s) to set, as escaped SQL statements. + */ + function addWhereAny($filters) { + if(is_string($filters)) $filters = func_get_args(); + $clause = implode(" OR ", $filters); + return $this->addWhere($clause); + } /** * Use the disjunctive operator 'OR' to join filter expressions in the WHERE clause. diff --git a/tests/model/DataListTest.php b/tests/model/DataListTest.php index 232631061..ff2b9edb6 100755 --- a/tests/model/DataListTest.php +++ b/tests/model/DataListTest.php @@ -437,6 +437,17 @@ class DataListTest extends SapphireTest { $list->exclude(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob')); $this->assertEquals(2, $list->count()); } + + /** + * Test that if an exclude() is applied to a filter(), the filter() is still preserved. + */ + public function testExcludeOnFilter() { + $list = DataObjectTest_TeamComment::get(); + $list = $list->filter('Comment', 'Phil is a unique guy, and comments on team2'); + $list = $list->exclude('Name', 'Bob'); + + $this->assertContains('WHERE ("Comment" = \'Phil is a unique guy, and comments on team2\') AND ("Name" != \'Bob\')', $list->sql()); + } /** * $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob with Age 21 or 43 diff --git a/tests/model/SQLQueryTest.php b/tests/model/SQLQueryTest.php index e23b5022b..3819b352c 100755 --- a/tests/model/SQLQueryTest.php +++ b/tests/model/SQLQueryTest.php @@ -258,11 +258,11 @@ class SQLQueryTest extends SapphireTest { ); } - public function testWhereAny() { + public function testSetWhereAny() { $query = new SQLQuery(); $query->setFrom('MyTable'); - $query->whereAny(array("Monkey = 'Chimp'", "Color = 'Brown'")); + $query->setWhereAny(array("Monkey = 'Chimp'", "Color = 'Brown'")); $this->assertEquals("SELECT * FROM MyTable WHERE (Monkey = 'Chimp' OR Color = 'Brown')",$query->sql()); } diff --git a/view/Requirements.php b/view/Requirements.php index 00d439af7..564ebb426 100644 --- a/view/Requirements.php +++ b/view/Requirements.php @@ -1074,16 +1074,18 @@ class Requirements_Backend { * @see Requirements::themedCSS() */ public function themedCSS($name, $module = null, $media = null) { - $theme = SSViewer::current_theme(); - $path = SSViewer::get_theme_folder() . "/css/$name.css"; + $path = SSViewer::get_theme_folder(); + $abspath = BASE_PATH . DIRECTORY_SEPARATOR . $path; + $css = "/css/$name.css"; - if (file_exists(BASE_PATH . '/' . $path)) { - $this->css($path, $media); - return; + if ($module && file_exists($abspath.'_'.$module.$css)) { + $this->css($path.'_'.$module.$css, $media); } - - if ($module) { - $this->css("$module/css/$name.css"); + else if (file_exists($abspath.$css)) { + $this->css($path.$css, $media); + } + else if ($module) { + $this->css($module.$css); } }